Сквозной пример интеграции: от виджета до решения на сервере

Сквозной пример интеграции KYC: пользователь проходит проверку в виджете (Web SDK) на сайте интегратора, а решение по нему принимает сервер интегратора. Страница показывает, кто что делает на каждом шаге и как трактовать результат.

Главный принцип:

  • колбэки виджета в браузере — только для интерфейса: показать экран, закрыть окно;
  • решение по пользователю принимает сервер интегратора по вебхуку;
  • запрос статуса через API — страховка на случай, если вебхук не дошёл.

Минимальное подключение описано на странице Быстрый старт. Здесь — полный поток с вебхуком.


Участники и последовательность

УчастникЧто делает
Сервер интегратораФормирует и шифрует clientKey, принимает вебхуки, принимает решение, при необходимости запрашивает статус и изображения через API
Фронт интегратораЗапускает виджет со scenarioId и зашифрованным clientKey, показывает пользователю состояние проверки
Виджет (Web SDK)Проводит пользователя по шагам сценария, вызывает successCb и closeCb
NeurovisionОбрабатывает сессию, выполняет проверки по базам данных, отправляет вебхуки, отвечает на запросы API
Бэкофис интегратораПолучает итоговое решение от сервера интегратора

Последовательность:

  1. Сервер интегратора формирует clientKey для новой попытки, сохраняет связь «ключ → пользователь» и отдаёт фронту зашифрованный ключ.
  2. Фронт запускает виджет.
  3. Пользователь проходит шаги сценария.
  4. Виджет вызывает successCb при успехе или closeCb при закрытии. Фронт только меняет экран.
  5. Neurovision отправляет на сервер интегратора вебхук SESSION_COMPLETE, а если в сценарии есть проверки по базам данных — ещё и DATABASE_CHECKS_COMPLETE.
  6. Сервер интегратора трактует статус, сохраняет решение и передаёт его в бэкофис.
  7. Если итогового вебхука нет дольше ожидаемого, сервер интегратора запрашивает статус сессии через API.

Настройка сценария в личном кабинете

Делается один раз для каждого сценария. Где находятся настройки — на странице KYC/AML в личном кабинете.

  • «Бэкэнд колбэк URL» на вкладке «Настройки коллбека» — адрес обработчика вебхуков на сервере интегратора. У каждого сценария свой адрес. Если поле пустое, вебхуки по сценарию не отправляются.
  • «Зашифровать тело POST-запроса с помощью секретного ключа» — включите. Тело вебхука будет зашифровано секретным ключом сценария, и расшифровать его сможет только владелец ключа.
  • Режим уведомлений — оставьте по умолчанию: вебхук приходит при каждом изменении результата сессии. Нужные статусы сервер интегратора отбирает сам, по правилам из раздела «Как трактовать статус».
  • Проверки по базам данных — проверки, без которых пользователя нельзя пропустить, отметьте в сценарии как блокирующие. Неблокирующая проверка на статус сессии не влияет: её итог есть только в результатах проверок по базам данных.
  • «Время жизни сессии после ее начала» — сколько времени у пользователя есть на прохождение: 15 минут, 30 минут, 1 час, 6 часов, 12 часов, 24 часа, 7 дней, 14 дней, 1 месяц или 1 год. От него зависят повторные попытки и момент, когда результат становится окончательным.
  • Тексты экранов и отказов — в редакторе Web SDK, вкладка «Текст». Подробно — на странице Параметры.

Шаг 1. Сервер интегратора формирует clientKey

clientKey — строка до 36 символов, которую задаёт интегратор. Она возвращается без изменений в вебхуках и ответах API и связывает сессию с пользователем.

  • Формируйте новый ключ на каждую попытку проверки. Повторный запуск виджета с тем же ключом открывает прежнюю сессию, а не создаёт новую.
  • Удобный формат — <userId>:<orderId>:<attempt>, например u1024:o77:1. Следующая попытка того же пользователя получит u1024:o77:2.
  • Сохраните у себя связь «ключ → пользователь» до запуска виджета: по ней сервер найдёт пользователя, когда придёт вебхук.
  • Зашифруйте ключ секретным ключом сценария на сервере и отдайте фронту только зашифрованное значение. Секретный ключ сценария в браузер не передаётся.

Как шифровать, с примером кода — Работа с clientKey.


Шаг 2. Фронт интегратора запускает виджет

<script src="https://kyc.neuro-vision.ru/lib/widget-lib.js"></script>
<script>
  async function startKyc() {
    // Зашифрованный clientKey выдаёт сервер интегратора
    const { clientKey } = await fetch("/kyc/attempt", { method: "POST" }).then((r) => r.json());

    window.KYCWidget.setupKYC({
      scenarioId: "<scenarioId>",
      clientKey: clientKey,
      successCb: (sessionJson) => {
        const { sessionId } = JSON.parse(sessionJson);
        showScreen("checking"); // «Проверяем данные»
        fetch("/kyc/client-success", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ sessionId }),
        });
      },
      closeCb: () => {
        showScreen("waiting"); // ждём решения сервера
      },
    });
  }
</script>
  • /kyc/attempt и /kyc/client-success — адреса на сервере интегратора, имена условные.
  • showScreen — функция интерфейса интегратора.

Все параметры виджета и варианты подключения — на странице Подключение.


Шаг 3. Пользователь проходит шаги

Пользователь проходит шаги сценария: документ, селфи, liveness — в зависимости от настроек. На каждый шаг есть несколько попыток. Если шаг не пройден, виджет показывает пользователю текст отказа и предлагает повторить, пока остаются попытки и время жизни сессии.

Тексты отказов меняются в редакторе Web SDK, вкладка «Текст». Значения кодов ошибок — на странице Ошибки.


Шаг 4. Колбэки виджета — только для интерфейса

  • successCb вызывается один раз и только при успешном прохождении шагов. Он приходит до завершения проверок по базам данных, поэтому пользователь ещё может получить отказ. Покажите экран «Проверяем данные» и передайте sessionId на свой сервер для сверки (шаг 8).
  • closeCb вызывается при закрытии виджета: пользователь закрыл окно, получил отказ или произошёл сбой. Колбэк вызывается без аргументов и не сообщает итог.

Решение по колбэкам не принимайте: их вызывает браузер пользователя. Итог приходит на сервер интегратора вебхуком.


Шаг 5. Сервер интегратора принимает вебхук SESSION_COMPLETE

Neurovision отправляет POST-запрос на «Бэкэнд колбэк URL» сценария. Тело вебхука SESSION_COMPLETE совпадает с ответом метода kyc/session/status и дополнено полем event. Для решения нужны поля:

ПолеЧто содержит
eventSESSION_COMPLETE
sessionIdИдентификатор сессии
clientKeyИсходный ключ, который сформировал сервер интегратора, без шифрования
statusСтатус сессии
resultsРезультаты шагов, в том числе ссылки на изображения
errorsОбщие ошибки сессии
secondsToLiveСколько секунд сессии осталось жить; 0 — время истекло или сессия закрыта

Если шифрование включено, тело приходит в виде { "encrypted": "...", "scenarioId": "..." }. По scenarioId выберите секретный ключ сценария и расшифруйте encrypted, как описано на странице Вебхуки.

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

Правила доставки:

  • Ответьте 200 сразу, а обработку выполняйте асинхронно.
  • Ожидание ответа — 30 секунд. Код и тело ответа не анализируются.
  • Попытка доставки одна, повторов нет. Поэтому нужна сверка через API (шаг 8).
app.post("/kyc/webhook", express.json(), (req, res) => {
  res.sendStatus(200);      // ответить сразу
  queue.push(req.body);     // обработать асинхронно
});

function handle(raw) {
  const body = raw.encrypted ? decrypt(raw.encrypted, secretKeyFor(raw.scenarioId)) : raw;

  if (body.event === "SESSION_COMPLETE") {
    const userId = findUserByClientKey(body.clientKey);
    applyDecision(userId, body.sessionId, body.status, decide(body));
  } else if (body.event === "DATABASE_CHECKS_COMPLETE") {
    saveDatabaseChecks(body.sessionId, body.results);
  }
}

Функции decrypt, secretKeyFor, findUserByClientKey, applyDecision и saveDatabaseChecks — на стороне интегратора.


Шаг 6. Как трактовать статус

Событие по одной сессии может прийти несколько раз: пользователь повторил шаг, оператор сменил статус в личном кабинете, повторная проверка по базе изменила результат. Обрабатывайте вебхуки идемпотентно по паре sessionId + status: такую пару, которая уже обработана, пропускайте.

Проверяйте условия по порядку:

ПорядокУсловиеЧто означаетИтог
1status = failed и в errors есть [legal] database check failedНе пройдена блокирующая проверка по базе данныхОкончательный отказ
2status = successШаги пройдены, блокирующие проверки пройденыПройдено
3status = failed и secondsToLive больше 0Промежуточный результат: пользователь ещё может повторить шагЖдать следующего вебхука
4status = failed и secondsToLive = 0Попытки или время закончилисьОкончательный отказ
5status = suspiciousСессия помечена как подозрительнаяОкончательный отказ
6idle или processingСессия ещё не завершенаЖдать

Первое условие проверяйте раньше третьего: при отказе по блокирующей проверке secondsToLive может оставаться больше 0, но повторить проверку пользователь не может.

При success сессия закрывается сразу: secondsToLive = 0.

Статус expired вебхуком не приходит. Если итогового вебхука нет дольше времени жизни сессии, запросите статус через API (шаг 8).

function decide({ status, errors = [], secondsToLive }) {
  if (status === "failed" && errors.includes("[legal] database check failed")) return "rejected";
  if (status === "success") return "approved";
  if (status === "failed" && secondsToLive > 0) return "pending";
  if (["failed", "suspicious", "expired"].includes(status)) return "rejected";
  return "pending"; // idle, processing
}

Все значения статусов — на странице Статусы сессии.


Шаг 7. Проверки по базам данных

Если в сценарии есть проверки по базам данных, приходит вебхук DATABASE_CHECKS_COMPLETE — один раз на серию проверок, когда все они завершились.

  • В теле есть sessionId и results, но нет clientKey и status. Связывайте событие с пользователем по sessionId из SESSION_COMPLETE.
  • Порядок событий DATABASE_CHECKS_COMPLETE и SESSION_COMPLETE не гарантирован.

Подробные результаты проверок возвращает метод kyc/session/databases. Когда пришёл итоговый вебхук SESSION_COMPLETE, этот метод уже отвечает checksStatus = complete. Если в ответе pending, повторяйте запрос раз в 5–10 секунд до своего таймаута: одна проверка может ждать ответа источника до 24 часов.

В результатах сначала смотрите outcome, потом passed: пропущенная проверка означает «не проверялось», а не «чисто».


Шаг 8. Сверка через API — страховка

Вебхук доставляется один раз, поэтому серверу интегратора нужна сверка:

  • если после successCb итогового вебхука нет дольше N минут (N выбирает интегратор);
  • если после closeCb или выдачи clientKey итогового вебхука нет дольше времени жизни сессии.

В этих случаях вызовите метод kyc/session/status по sessionId или по исходному clientKey и трактуйте ответ по тем же правилам, что и вебхук.

curl -X POST "https://api.neuro-vision.ru/v1/kyc/session/status" -H "Content-Type: application/json" -H "token: <jwt-token>" -d '{"sessionId": "00000000-0000-0000-0000-000000000000"}'

Если переданы оба параметра, поиск идёт по clientKey. Если сессии нет, метод отвечает HTTP 200 с "status": "error" и "message": "session not found" — проверяйте тело ответа, а не только код.


Шаг 9. Изображения сессии

Ссылки на изображения приходят в results. Тип шага — в поле type:

typeЧто на изображениях
documentДокумент; в docName — тип документа, в countryCode — страна, в isBackSide — обратная ли это сторона
selfieСелфи и вырезы лица
livenessКадры проверки liveness
facesПары сравниваемых лиц

Чтобы скачать изображение:

  • получите временный JWT-токен методом user/login и передайте его в заголовке token. Постоянный API-токен для скачивания изображений не подходит;
  • у пользователя, от имени которого выполнен вход, должно быть право «Просмотр изображений документов KYC». Без права ссылка отвечает 404.

Ссылки действуют, пока данные сессии не удалены. Пример скрипта — Скачивание изображений KYC-сессии через API.


Перед запуском в прод

  • В каждом рабочем сценарии заполнен «Бэкэнд колбэк URL» и включено шифрование тела вебхука.
  • Обязательные проверки по базам данных отмечены как блокирующие.
  • Время жизни сессии выбрано под ваш процесс.
  • clientKey уникален для каждой попытки и шифруется только на сервере; секретный ключ сценария не попадает в браузер.
  • Обработчик вебхуков отвечает 200 сразу, обрабатывает асинхронно и идемпотентно по sessionId + status.
  • Отказ по блокирующей проверке проверяется раньше промежуточного failed.
  • Решение принимается только на сервере; successCb и closeCb меняют только интерфейс.
  • Работает сверка через kyc/session/status для сессий без итогового вебхука.
  • Для скачивания изображений используется JWT-токен пользователя с правом «Просмотр изображений документов KYC».
  • Интеграция проверена на тестовом сценарии — Тестирование интеграции.