Overview
To provide a more seamless claim experience for your customers, Cermati Protect allows partners to deep-link directly into our Claim Center. Customers will visit our Claim Center via a URL with encrypted Coverage ID appended in it.
By appending the customer's Coverage ID to the URL parameters, the Claim Center will automatically prefill the Coverage ID field. This would reduce manual typing errors for the customer.
Endpoint Structure
Partners should redirect users to our Claim Center using the following URL format:
GET https://[claim-center-base-url]/cermatiprotect/claim?plcy=<base64url_payload>&ts=<base64url_timestamp>&id=<id>
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| plcy | String | Required | The Base64URL-encoded string containing the encrypted Coverage ID payload and its initialization vector (IV). |
| ts | String | Required | The Base64URL-encoded string containing the encrypted timestamp payload with format 2026-12-31T23:59:59.999Z (ISO 8601) and its IV. The timestamp is useful to make the payload temporary. The payload will be invalid when 1 hour has passed since the given timestamp |
| id | String | Required | the id provided securely to the partner from us, in plain text |
Cryptographic Specifications
To successfully generate the parameters, your system must implement the following encryption scheme:
Key Derivation (PBKDF2)
Before encrypting payloads, derive a 256-bit key from the password provided to you during onboarding.
| Parameter | Value / Configuration | Notes |
|---|---|---|
| Password | [Provided Securely] | The shared secret provided during onboarding |
| Salt | The first 6 characters of the Password | Derived dynamically from the password string. |
| Iterations | 600,000 | Recommended iterations for PBKDF2-HMAC-SHA256 |
| HMAC Algorithm | SHA256 | Hashing algorithm used for key derivation. |
| Derived Key Length | 32 bytes (256 bits) | The resulting key. Use directly as the key for AES-256-CBC encryption |
Encryption (AES-256-CBC)
For every encryption operation (both Coverage ID and timestamp):
a. Apply PKCS7 padding to the plaintext payload to match block size requirements.
b. Generate a cryptographically secure, random 16-byte Initialization Vector (IV). Never reuse an IV across different operations.
c. Derive the key using the password and salt. Use 600,000 iterations, SHA256, and length of 32 bytes.
d. Encrypt the padded plaintext with the derived key and generated IV using the AES-256-CBC.
e. Convert the resulting ciphertext and the IV into lowercase Hex strings, then concatenate them with a dot delimiter:
ciphertextHex.ivHex
f. Encode the entire concatenated string using Base64URL. Do not use standard Base64; ensure + is replaced by -, / by _, and trailing padding = is stripped.
Code Example (Node.js)
const crypto = require('crypto');
const Bluebird = require('bluebird');
const cryptoRandomBytesAsync = Bluebird.promisify(crypto.randomBytes, { context: crypto });
// Configuration (Ensure these match your credentials safely stored in environment variables)
const SHARED_SECRET = 'your_16_char_secret';
const ALGORITHM = 'aes-256-cbc';
const ITERATIONS = 600000;
const KEY_LENGTH = 32;
const DIGEST = 'sha256';
const ID = 'your_given_id';
/**
* Encrypts a plaintext string into a Base64URL-encoded payload
*/
const encryptPayload = async (plaintext) => {
const passwordBuf = Buffer.from(SHARED_SECRET, 'utf8');
const saltBuf = Buffer.from(SHARED_SECRET.slice(0, 6), 'utf8');
// 1. Derive Key
const keyBuf = crypto.pbkdf2Sync(passwordBuf, saltBuf, ITERATIONS, KEY_LENGTH, DIGEST);
// 2. Generate random IV
const ivBuf = await cryptoRandomBytesAsync(16);
const ivHex = ivBuf.toString('hex');
// 3. Encrypt data
const cipher = crypto.createCipheriv(ALGORITHM, keyBuf, ivBuf);
let ciphertextHex = cipher.update(plaintext, 'utf8', 'hex');
ciphertextHex += cipher.final('hex');
// 4. Serialize and Base64URL encode
const serializedPayload = `${ciphertextHex}.${ivHex}`;
const base64UrlPayload = Buffer.from(serializedPayload, 'utf8').toString('base64url');
return base64UrlPayload;
};
(async () => {
try {
const coverageId = 'CP-12345-67890';
const currentTimestamp = new Date().toISOString();
const plcyParam = await encryptPayload(coverageId);
const tsParam = await encryptPayload(currentTimestamp);
const redirectUrl = `https://claim.cermatiprotect.com/cermatiprotect/claim?plcy=${plcyParam}&ts=${tsParam}&id=${ID}`;
console.log('Constructed Redirection URL:\n', redirectUrl);
} catch (error) {
console.error('Encryption failed:', error);
}
})();