Вебхуки

Вебхук — POST-запрос, который система отправляет на ваш сервер, когда с сессией или анкетой что-то произошло. Так вы узнаёте о результате без постоянного опроса API.


Настройка

Адрес вебхука задаётся в настройках сценария KYC в личном кабинете, поле «Бэкэнд колбэк URL». У каждого сценария свой адрес. Если поле пустое, вебхуки по сценарию не отправляются.

Там же настраиваются:

НастройкаЧто делает
Зашифровать тело POST-запроса с помощью секретного ключаТело приходит зашифрованным секретным ключом сценария, см. «Шифрование»
Не отправлять персональные данныеИз тела убираются распознанные и введённые данные, см. «Режим без персональных данных»
Уведомлять только если сессия финализированаSESSION_COMPLETE приходит один раз, когда сессия завершена окончательно
Отправить тестовый запросОтправляет пробный запрос на указанный адрес

Доставка

  • Метод POST, заголовок Content-Type: application/json; charset=utf-8.
  • Подписи запроса нет. Чтобы убедиться, что запрос пришёл от системы, включите шифрование: расшифровать тело можно только секретным ключом сценария.
  • Ожидание ответа — 30 секунд. Код и тело вашего ответа не учитываются.
  • Повторной отправки нет. Если вебхук не дошёл, получите актуальное состояние методом API (см. таблицу событий).
  • Порядок событий DATABASE_CHECKS_COMPLETE и SESSION_COMPLETE не гарантирован.
  • Обрабатывайте события идемпотентно: одно и то же событие по одной сессии может прийти больше одного раза.

События

Тип события — в поле event тела запроса.

eventКогда приходитКак получить то же через API
SESSION_COMPLETEИзменился результат KYC-сессииkyc/session/status
DATABASE_CHECKS_COMPLETEЗавершились все проверки сессии по базам данныхkyc/session/databases
QUESTIONNAIRE_COMPLETEПользователь заполнил анкету первого этапаkyc/questionnaire/sessions
PD_ERASURE_COMPLETEЗавершено уничтожение персональных данных сессииkyc/session/erase

SESSION_COMPLETE

Тело — данные сессии в том же виде, что в ответе kyc/session/status, плюс поле event.

  • По умолчанию событие приходит при каждом изменении результата сессии, пока пользователь её проходит. Повторные попытки пользователя дают новые события.
  • С настройкой «Уведомлять только если сессия финализирована» событие приходит один раз: когда время жизни сессии истекло (secondsToLive = 0) или исчерпаны попытки.
  • Если в сценарии есть проверки по базам данных, итоговое событие приходит после их завершения.
  • Поле faceReference (сравнение с эталонной сессией) приходит во всех режимах.
{
  "event": "SESSION_COMPLETE",
  "sessionId": "00000000-0000-0000-0000-000000000000",
  "schemaId": "00000000-0000-0000-0000-000000000000",
  "clientKey": "client-0001",
  "status": "success",
  "secondsToLive": 0,
  "results": []
}

Полный список полей — на странице Статус сессии. Значения статусов — на странице Статусы сессии.

DATABASE_CHECKS_COMPLETE

Приходит, когда все проверки сессии по базам данных завершились. По сессии, персональные данные которой уничтожены, не отправляется.

{
  "event": "DATABASE_CHECKS_COMPLETE",
  "sessionId": "00000000-0000-0000-0000-000000000000",
  "schemaId": "00000000-0000-0000-0000-000000000000",
  "clientId": "00000000-0000-0000-0000-000000000000",
  "results": [
    {
      "checker": "insolvencyStatus",
      "spent": 1230,
      "outcome": "performed",
      "notPerformedReason": null,
      "missingInputs": [],
      "passed": true
    }
  ],
  "responseTime": "2026-01-01T10:00:00.000Z"
}

Поля результата проверки описаны на странице kyc/session/databases. Сначала смотрите outcome, потом passed: пропущенная проверка — не «чисто».

QUESTIONNAIRE_COMPLETE

Приходит, когда пользователь отправил анкету первого этапа (см. Двухэтапная проверка: анкета → KYC). Если в сценарии анкеты есть проверки по базам данных, событие приходит после их завершения и содержит массив checks.

{
  "event": "QUESTIONNAIRE_COMPLETE",
  "type": "questionnaire",
  "questionnaireSessionId": "00000000-0000-0000-0000-000000000000",
  "schemaId": "00000000-0000-0000-0000-000000000000",
  "clientKey": "client-0001",
  "clientUser": "user-0001",
  "status": "success",
  "createdAt": "2026-01-01T10:00:00.000Z",
  "fullName": "Иванов Иван Иванович",
  "dob": "1990-01-01",
  "email": "user@example.com",
  "phone": "+70000000000",
  "fields": [
    { "key": "city", "title": "Город", "value": "Москва" }
  ],
  "checks": [
    {
      "checker": "insolvencyStatus",
      "status": "success",
      "outcome": "performed",
      "notPerformedReason": null,
      "missingInputs": [],
      "result": { "passed": true }
    }
  ]
}

status: "success" означает, что ответы анкеты записаны. Это не решение по пользователю.

PD_ERASURE_COMPLETE

Приходит один раз, когда завершено уничтожение персональных данных сессии: по запросу kyc/session/erase или при удалении сессии в личном кабинете.

{
  "event": "PD_ERASURE_COMPLETE",
  "sessionId": "00000000-0000-0000-0000-000000000000",
  "schemaId": "00000000-0000-0000-0000-000000000000",
  "clientKey": "client-0001",
  "pdErasedAt": "2026-03-02T10:15:30Z",
  "parts": {
    "text": { "state": "erased" },
    "media": { "state": "erased" },
    "person": { "state": "kept", "reason": "linked_session" },
    "questionnaire": { "state": "absent" }
  },
  "responseTime": "2026-03-02T10:15:30Z"
}

Если событие потерялось, вызовите kyc/session/erase ещё раз: он ответит erased с тем же pdErasedAt.


Связанные сценарии

Если сессия создана по связанным сценариям, вебхуки приходят на адрес сценария, с которого сессия началась, и шифруются его секретным ключом. В теле есть selectedSchemaId — сценарий, выбранный по документу, или null.


Режим без персональных данных

С настройкой «Не отправлять персональные данные»:

  • в SESSION_COMPLETE нет распознанных данных документов (ocr в results и history) и данных анкеты: ФИО, даты рождения, email, телефона и значений полей (key и title остаются);
  • в QUESTIONNAIRE_COMPLETE нет введённых значений, результаты проверок checks приходят полностью.

Полные данные можно получить методами API.


Шифрование

Шифрование работает, если включена настройка «Зашифровать тело POST-запроса с помощью секретного ключа» и в сценарии задан «Секретный ключ» — тот же, которым шифруется clientKey.

Тело зашифрованного запроса:

{
  "encrypted": "<base64>"
}

Как расшифровать:

  1. Ключ — первые 32 символа шестнадцатеричной строки SHA-256 от секретного ключа сценария.
  2. Декодируйте encrypted из base64.
  3. Первые 16 байт — вектор инициализации (IV), остальное — шифротекст.
  4. Расшифруйте AES-256-CBC и разберите результат как JSON.
Пример на Node.js
const crypto = require('crypto');

function decryptWebhook(body, secretKey) {
  const key = crypto.createHash('sha256').update(secretKey).digest('hex').substring(0, 32);
  const buf = Buffer.from(body.encrypted, 'base64');
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, buf.subarray(0, 16));
  const text = Buffer.concat([decipher.update(buf.subarray(16)), decipher.final()]).toString('utf8');
  return JSON.parse(text);
}