# Когда webhook так и не приходит

Source: https://help.didit.me/ru/integration/webhook-troubleshooting
Updated: 2026-10-12

Начните с вкладки Deliveries: она показывает, отправлял ли Didit событие. Если да, код ответа укажет на недоступный маршрут или неверную подпись.

Начните со вкладки **Deliveries** у нужного назначения. Если Didit вообще не
пытался доставить событие - проблема в подписке или в самом назначении. Если
попытка была и она провалилась, код ответа подскажет, в чём дело: **404**
означает, что ваш маршрут был недоступен по этому URL, а несовпадение подписи
означает, что вы захэшировали не те байты.

## Шаг 1: пытался ли Didit отправить событие?

Откройте Разработчики и Вебхуки, выберите точку и список доставок, чтобы увидеть запрос и ответ каждой попытки. Повторите после исправления. Проверьте приложение, среду, подписки на события и включена ли точка.

![Страница webhooks в консоли Didit со статусом доставки по каждому назначению](https://help.didit.me/screenshots/webhooks-light.webp)

*На этой странице есть всё, чтобы отличить отсутствующее событие от неработающего эндпоинта.*

Эта единственная проверка делит проблему пополам:

- **Попытка не залогирована** → событие для этого назначения вообще не сгенерировалось. Переходите к шагу 2.
- **Попытка залогирована, неудачно** → Didit отправил событие, а ваша сторона его отклонила или не получила. Переходите к шагу 3.
- **Попытка залогирована, 2xx** → доставка прошла успешно. Проблема внутри вашего обработчика, а не в доставке.

## Шаг 2: попытка не залогирована

По убыванию вероятности:

1. **Событие не подписано.** Подстановочного знака нет - каждое семейство событий нужно перечислять явно. А название, которого не существует (`session.status.updated`, `kyc.completed`), молча ничего не получает. Сверьтесь со [списком событий](https://help.didit.me/ru/integration/webhooks-basics).
2. **Не то приложение.** Назначения принадлежат приложению. Если ваши сессии выполняются в другом приложении, чем назначение, событие туда никогда не дойдёт. Это самая частая причина, когда всё выглядит настроенным правильно.
3. **На самом деле ничего не изменилось.** Webhook срабатывает при изменении. Сессия, которая не сдвинулась с места, или повторный AML-скрининг, не нашедший ничего выше порога, закономерно не порождают событие.
4. **Статус, которого вы ждёте, ещё не наступил.** Сессия в статусе In Progress ещё не завершена. См. [когда сессия так и не завершается](https://help.didit.me/ru/verification-sessions/session-not-finished).

## Шаг 3: доставка была предпринята и провалилась

**404** означает, что запрос дошёл до чего-то, у чего нет вашего маршрута. Проверьте:

- Точный путь, включая завершающий слэш. Фреймворк, который редиректит `/hook` на `/hook/`, может превратить рабочий эндпоинт в 404 или потерянное тело запроса.
- Доступен ли URL публично. Локальный или staging-хост, недоступный из интернета, падает именно так.
- Не отправляет ли этот путь куда-то ещё прокси, балансировщик нагрузки или роутер на основе пути перед вашим приложением.

**5xx** означает, что ваш обработчик выбросил исключение. Логируйте сырое тело запроса до парсинга, чтобы видеть, что он на самом деле получил.

**Таймаут** означает, что вы не ответили достаточно быстро. Сначала верните 2xx, а обработку выполняйте после.

**Вообще ничего / соединение отклонено** означает, что ваш периметр заблокировал запрос. Didit доставляет события со статического IP **18.203.201.92** с user agent `DiditWebhook/2.0`. Если вы за Cloudflare или WAF с политикой запрета по умолчанию, разрешите этот IP для принимающего хоста.

## Классика: автоматическая доставка падает с 404, а Resend работает

Этот случай встречается достаточно часто, чтобы дать ему имя. Автоматическая доставка падает с 404, а затем нажатие **Resend** на том же событии проходит успешно.

Такое сочетание означает, что и содержимое, и ваш эндпоинт в порядке - значит, разница в тайминге или пути, а не в содержимом. Проверьте:

- **Деплой или рестарт** в момент исходной доставки. Resend срабатывает позже, когда приложение уже снова поднято.
- **Холодный старт**, превысивший таймаут вашей платформы - типично для serverless с медленным первым вызовом.
- **Маршрутизацию по пути, которая изменилась** между двумя попытками, или правило, которое совпадает не для всех запросов.
- **Ограничение частоты запросов или защиту от ботов на вашем периметре**, которая пропустила ручной повтор, потому что он пришёл один, а не пачкой.

Во вкладке Deliveries есть обе попытки с временными метками - сравните их со своими логами деплоев и ошибок за эту минуту.

## Проверка подписи не проходит

Почти всегда одна из трёх причин:

1. **Вы захэшировали пересериализованный JSON.** Считайте HMAC от **сырых** байтов тела запроса ровно в том виде, в котором оно получено. Разбор и повторная сериализация меняют пробелы и порядок ключей, и подпись перестаёт совпадать. Большинству фреймворков нужна явная настройка, чтобы отдать сырое тело.
2. **Неверный секрет.** Секрет подписи задаётся **на каждое назначение отдельно**, и это не ваш API-ключ. У двух назначений - два разных секрета.
3. **Неверное предположение о кодировке.** Если вы не уверены, используется ли секрет как обычная строка или его нужно предварительно декодировать, не гадайте - следуйте [справке по проверке подписи](https://docs.didit.me/integration/webhooks#signature-verification) буквально и логируйте сырое тело во время отладки, чтобы можно было сравнить.

> **Warning:** Никогда не "чините" несовпадение подписи, просто отключив проверку.
> Непроверяемый эндпоинт webhook примет поддельное подтверждение от кого угодно,
> кто найдёт этот URL, - и отладочный обходной путь превращается в способ
> захвата аккаунта.

## Два повтора - это не очередь

При ответах 5xx или 404 Didit повторяет доставку дважды: примерно через минуту, затем через четыре. Тайм-аут после 5 секунд и ошибка соединения не повторяются автоматически. После исправления используйте Повторить в списке доставок. Окончательный сбой вызывает уведомление.

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

## Тестирование без реальных верификаций

[Video: Настройка API-ключей и проверка вебхуков - Didit Academy](https://www.youtube.com/watch?v=thOMIGbNLP0&t=140)

**Отправьте тестовое событие** на странице назначения отправляет полностью сформированное событие любого нужного вам вида - approved, declined, in review, KYB, entity, transaction. С его помощью можно убедиться, что ваш эндпоинт, проверка подписи и обработчик работают, прежде чем от них будет зависеть настоящая сессия.

Sandbox дополняет это с другой стороны: sandbox-сессия отправляет настоящие webhook с `"environment": "sandbox"`, поэтому вы можете бесплатно прогнать весь путь целиком. См. [тестирование в sandbox](https://help.didit.me/ru/getting-started/sandbox-and-testing).
