Working with clientKey

clientKey is a user ID that you define and use to link KYC sessions to your users, applications, or contracts.

Using clientKey you can:

  • find all KYC sessions of a specific user;
  • match the verification results with your objects (userId, orderId, loanId, etc.);
  • filter sessions via the REST API;
  • easier to process webhooks.

Important: you create the clientKey value yourself, the platform does not generate it automatically.


Format and restrictions

  • 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 for use:

  • clientKey = userId — if one KYC check per user;
  • clientKey = "${userId}:${applicationId}" — if KYC is linked to an application, order, or contract;
  • clientKey = UUID — if it’s 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 «scenario secret key» in the personal account.

Workflow:

  1. On the backend:
  • you form clientKeyRaw (up to 36 characters);
  • encrypt it with the script’s secret key;
  • you send the encrypted clientKey to the frontend.
  1. On the frontend:
  • you pass the encrypted clientKey to KYCWidget.setupKYC(...).
  1. On the side of the KYC service:
  • the value is decrypted;
  • the original clientKeyRaw is stored in the session;
  • you can filter sessions by it and get results via API and webhooks.


Where clientKey is used

In WebSDK

Widget call:

window.KYCWidget.setupKYC({
  scenarioId:  "SCENARIO_ID",            // Test scenario 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 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.


Generating and encrypting clientKey on the backend

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

General idea:

  1. Take clientKeyRaw (up to 36 characters).
  2. You take the scenario secret key from your personal account (scenarioSecretKey).
  3. On the backend, encrypt clientKeyRaw using an algorithm (example — AES-256-CBC).
  4. You pass the resulting Base64 string to WebSDK as clientKey.

Node.js example (AES-256-CBC)

const crypto = require("crypto");

// 1. Original ID (what you want to see in the API and webhooks)
const clientKeyRaw = "user_123"; // up to 36 characters

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

// 3. Get 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 concatenate 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 you substitute into:

window.KYCWidget.setupKYC({
  scenarioId:  "SCENARIO_ID",
  clientKey: encryptedBase64,
  // ...
});


How to test clientKey

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

Frequent questions and errors

«Where do I get the values for clientKey and clientUser?»

  • clientKeyany string up to 36 characters that you define yourself: userId, application number, order, any convenient value. The parameter is required.
  • clientUser — an optional string up to 36 characters, not required to be unique: you can use it later to find all sessions (attempts) of a single user.


Console error: «Asymmetric decryption failed!»

Most often it means that:

  • the widget received an unencrypted clientKeyRaw;
  • 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 pass to the widget exactly the Base64 string obtained after encryption (see example above).
  2. That the script in the personal account and the secret key you use for encryption match.
  3. That the extra parameter clientUser is not used (it can be removed).

«How do I find the clientKey to decrypt the webhook?»

To decrypt the webhook body, clientKey is not needed:

  • the webhook is encrypted with the session key/webhook secret, not clientKey;
  • to decrypt, you only need the password/key you specified in the webhook settings and the encrypted encrypted field 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 specified in clientKeyRaw.


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

It’s normal:

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

Overall KYC session status:

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

Checks against external databases (sanctions, debtor registries, etc.) also affect the overall success: if a «red flag» is considered critical, it will result in a failed status at the session level.


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

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