Working with clientKey

clientKey is a custom identifier that you set yourself and use to associate KYC sessions with your users, applications, or contracts.

Through clientKey you can:

  • find all KYC sessions for a specific user;
  • match verification results with your objects (userId, orderId, loanId, etc.);
  • filter sessions via REST API;
  • it’s more convenient to process webhooks.

Important: the value of clientKey is chosen by you; the platform does not generate it automatically.


Format and limitations

  • Type: string
  • Maximum length: 36 characters
  • Format: any string, it is convenient to limit yourself to Latin letters, numbers, and separators ([a-zA-Z0-9_-])

Recommended to use:

  • clientKey = userId — if one KYC check per user;
  • clientKey = "${userId}:${applicationId}" — if KYC is linked to an application, order, contract;
  • clientKey = UUID — if it is more convenient to work only with the KYC identifier.

Two forms of clientKey: “raw” and encrypted

To integrate with WebSDK, you need to understand that there are:

  1. Original value (clientKeyRaw) What you came up with: for example, "user_123" or "loan-42".
  2. Encrypted value (clientKey) This is what you actually pass to the widget. It is the result of encrypting clientKeyRaw with the “script secret key” in the Personal Account.

How it works:

  1. On the backend:
  • form clientKeyRaw (up to 36 characters);
  • encrypt it with the script’s secret key;
  • send the encrypted clientKey to the front.
  1. On the frontend:
  • pass the encrypted clientKey to KYCWidget.setupKYC(...).
  1. On the **KYC service** side:
  • value is deciphered;
  • the original clientKeyRaw is saved in the session;
  • it can be used to filter sessions and retrieve results via API and webhooks.

In the API (/kyc/session/status, /kyc/sessions/filter, and webhooks), you work with the original value that you set yourself. Encryption is only needed for the secure transmission of clientKey to the browser.


Where clientKey is Used

In WebSDK

Widget call:

window.KYCWidget.setupKYC({
  schemaId:  "SCHEMA_ID",            // Schema validation ID
  clientKey: "ENCRYPTED_CLIENT_KEY", // encrypted clientKeyRaw
  theme: "light",
  closeCb:   () => console.log("CLOSE"),
  successCb: (payload) => {
    console.log("SUCCESS", payload);
    // here you already know the original clientKeyRaw, as you set it yourself on the backend
  },
});

In the REST API

  • /kyc/session/status — you can pass clientKey to clarify the status for a specific key;
  • /kyc/sessions/filter — there is a clientKey filter to get all sessions by key.

Here you pass the original value (clientKeyRaw), without encryption.


Generation and Encryption of clientKey on the Backend

The Scenario Secret Key is stored only on your server-side. It must not be transmitted to the browser.

General idea:

  1. Take clientKeyRaw (up to 36 characters).
  2. Take the script secret key from the personal account (scenarioSecretKey).
  3. On the backend, encrypt clientKeyRaw using an algorithm (e.g., AES-256-CBC).
  4. Pass the resulting Base64 string to WebSDK as clientKey.

Example in Node.js (AES-256-CBC)

const crypto = require("crypto");

// 1. Source identifier (what you want to see in APIs and webhooks)
const clientKeyRaw = "user_123"; // up to 36 characters

// 2. Script secret key from the Personal Account (DO NOT pass to the browser!)
const password = "SCENARIO_SECRET_KEY";

// 3. Obtain a 32-byte key from the password
const key = crypto.createHash("sha256").update(password).digest('hex').substr(0, 32);

// 4. Generate a random IV (16 bytes)
const iv = crypto.randomBytes(16);

// 5. Encrypt clientKeyRaw
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
const encrypted = Buffer.concat([cipher.update(clientKeyRaw, "utf8"), cipher.final()]);

// 6. We glue together IV + ciphertext and encode it in Base64 — this is the clientKey for the widget
const encryptedBase64 = Buffer.concat([iv, encrypted]).toString("base64");

console.log("clientKeyRaw:", clientKeyRaw);
console.log("clientKey (encrypted):", encryptedBase64);

This is the encrypted clientKey that you substitute into:

window.KYCWidget.setupKYC({
  schemaId:  "SCHEMA_ID",
  clientKey: encryptedBase64,
  // ...
});

The “Check” button next to the script secret key in the Personal Account uses the same encryption algorithm and helps to quickly verify that clientKey is encrypted/decrypted correctly. For production, always encrypt on your backend.


How to test clientKey

  1. In the personal account, find the secret script key.
  2. Click the “Check” button and enter the test clientKeyRaw (e.g., test_user_1).
  3. The LC will return an encrypted value — it can be temporarily substituted into the integration examples (instead of "ENCRYPTED_CLIENT_KEY").
  4. Make sure that:
  • widget opens without errors;
  • your KYC session logs show the original clientKeyRaw (e.g., in filtering by clientKey via /kyc/sessions/filter).

Frequently Asked Questions and Errors

“Where do I get the values for clientKey and clientUser?”

  • clientKeyany string up to 36 characters, which you define yourself: userId, application number, order, any convenient value. The parameter is required.
  • clientUser — also any string up to 36 characters, but it is better not to use it in new integrations.

Best practice: set clientKeyRaw = your userId or orderId, encrypt it, and only pass clientKey.


Console Error: “Failed to perform asymmetric decryption!”

Most often it means that:

  • an unencrypted clientKeyRaw was passed to the widget;
  • or a different secret key was used, other than the script key;
  • or the clientKey value was corrupted/truncated (e.g., during copying).

Check:

  1. That you are passing a Base64 string obtained after encryption to the widget (see the example above).
  2. That the script in the LC and the secret key you use for encryption match.
  3. The extra parameter clientUser is not used (it can be removed).

“And how do I find the clientKey to decrypt the webhook?”

The webhook body does not require clientKey for decryption:

  • the webhook is encrypted with the session key/webhook secret, not the clientKey;
  • to decrypt, you only need the password/key that you specified in the webhook settings, and the encrypted field encrypted from the POST request.
clientKey in the webhook is simply one of the JSON fields within the already decrypted body, and its value will be exactly what you set in clientKeyRaw.

“Why does each test webhook come with a different encrypted string, even though the JSON is the same?”

This is normal:

  • a **random IV (initialization vector)** is used for encryption;
  • even with the same JSON and encryption key, the ciphertext is different each time;
  • after decryption the body will be the same JSON.

“How is the general status success/failed related to checks and databases?”

Overall KYC session status:

  • successonly if all checks passed successfully;
  • if somewhere there is a failed (OCR, fraud, databases, etc.) — the overall status will be failed.

Checks against external databases (sanctions, bailiffs, etc.) also affect the overall success: if a “red flag” is considered critical, it will result in failed at the session level as well.


Recommended workflow with clientKey

  1. On the backend at the start of the KYC process:
  • generate or select a clientKeyRaw (e.g., user_123);
  • encrypt it with the secret script key → encryptedClientKey;
  • you save clientKeyRaw with yourself along with userId/orderId.
  1. On the frontend:
  • pass encryptedClientKey to KYCWidget.setupKYC(...).
  1. To get the result:
  • either accept the webhook and look for the clientKey field within the body;
  • or call /kyc/sessions/filter with clientKey = clientKeyRaw to find all sessions for this key.

This way, you can always unambiguously determine which user or application any KYC session belongs to.