Сквозной пример интеграции KYC: пользователь проходит проверку в виджете (Web SDK) на сайте интегратора, а решение по нему принимает сервер интегратора. Страница показывает, кто что делает на каждом шаге и как трактовать результат.
Главный принцип:
- колбэки виджета в браузере — только для интерфейса: показать экран, закрыть окно;
- решение по пользователю принимает сервер интегратора по вебхуку;
- запрос статуса через API — страховка на случай, если вебхук не дошёл.
Минимальное подключение описано на странице Быстрый старт. Здесь — полный поток с вебхуком.
Участники и последовательность
| Участник | Что делает |
|---|---|
| Сервер интегратора | Формирует и шифрует clientKey, принимает вебхуки, принимает решение, при необходимости запрашивает статус и изображения через API |
| Фронт интегратора | Запускает виджет со scenarioId и зашифрованным clientKey, показывает пользователю состояние проверки |
| Виджет (Web SDK) | Проводит пользователя по шагам сценария, вызывает successCb и closeCb |
| Neurovision | Обрабатывает сессию, выполняет проверки по базам данных, отправляет вебхуки, отвечает на запросы API |
| Бэкофис интегратора | Получает итоговое решение от сервера интегратора |
Последовательность:
- Сервер интегратора формирует
clientKeyдля новой попытки, сохраняет связь «ключ → пользователь» и отдаёт фронту зашифрованный ключ. - Фронт запускает виджет.
- Пользователь проходит шаги сценария.
- Виджет вызывает
successCbпри успехе илиcloseCbпри закрытии. Фронт только меняет экран. - Neurovision отправляет на сервер интегратора вебхук
SESSION_COMPLETE, а если в сценарии есть проверки по базам данных — ещё иDATABASE_CHECKS_COMPLETE. - Сервер интегратора трактует статус, сохраняет решение и передаёт его в бэкофис.
- Если итогового вебхука нет дольше ожидаемого, сервер интегратора запрашивает статус сессии через 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. Для решения нужны поля:
| Поле | Что содержит |
|---|---|
event | SESSION_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: такую пару, которая уже обработана, пропускайте.
Проверяйте условия по порядку:
| Порядок | Условие | Что означает | Итог |
|---|---|---|---|
| 1 | status = failed и в errors есть [legal] database check failed | Не пройдена блокирующая проверка по базе данных | Окончательный отказ |
| 2 | status = success | Шаги пройдены, блокирующие проверки пройдены | Пройдено |
| 3 | status = failed и secondsToLive больше 0 | Промежуточный результат: пользователь ещё может повторить шаг | Ждать следующего вебхука |
| 4 | status = failed и secondsToLive = 0 | Попытки или время закончились | Окончательный отказ |
| 5 | status = suspicious | Сессия помечена как подозрительная | Окончательный отказ |
| 6 | idle или 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».
- Интеграция проверена на тестовом сценарии — Тестирование интеграции.