> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Мониторинг транзакций (KYT): типичные проблемы и решения

> Частые проблемы KYT в Didit: коллизии txn_id, правила не срабатывают, таймауты AML, подпись webhook, валюты. Причины и исправления.

Справочник распространённых проблем мониторинга транзакций с описанием симптомов, причин и решений.

## Ошибка дубликата `txn_id`

**Симптом.** При отправке транзакции возвращается `400` с сообщением `A transaction with this transaction_id already exists.` в поле `transaction_id`, либо `409`, когда два одинаковых запроса выполняются одновременно.

**Причина.** `txn_id` (это `transaction_id`, который вы отправляете) уникален в рамках приложения.
Didit отклоняет вторую транзакцию с тем же `transaction_id` и не возвращает существующую запись.

**Решение.**

* Генерируйте `txn_id` детерминированно на своей стороне (например, используйте ID транзакции из вашей базы данных).
* При ответе `400` или `409` с ошибкой дубликата `transaction_id` во время повторной попытки не отправляйте запрос заново, а найдите существующую транзакцию: прочитайте её через [`GET /v3/transactions/{uuid}/`](https://docs.didit.me/ru/management-api/transactions/get), используя `uuid` из первого ответа, или используйте `transaction_id` (uuid Didit), который webhook `transaction.created` передаёт рядом с вашим `txn_id`.
* Если запрос не был повторной попыткой, присвойте новой транзакции собственный `transaction_id`.

## Правило не срабатывает

**Симптом.** Вы создали правило, которое должно совпадать, но ни в одной транзакции в `rule_runs[]` нет записи с `matched: true`.

**Причины и решения.**

* **Приложение работает в режиме песочницы** - приложение в режиме песочницы не выполняет оценку правил, AML-скрининг и биллинг и не отправляет webhook `transaction.created` и `transaction.status.updated`. Обмен по Travel Rule выполняется, если он включён, с [Didit Test VASP](https://docs.didit.me/ru/transaction-monitoring/travel-rule-sandbox.md), и доставляет webhook `travel_rule.status.updated` с пометкой `environment: sandbox`. `rule_runs` возвращается пустым, оценка остаётся `0` независимо от режима ваших правил, а транзакция остаётся `APPROVED`, если только для перевода Travel Rule с истекающим сроком не применяется ваш `timeout_outcome`. Проверьте `environment` в ответе по транзакции: значение `"sandbox"` означает, что она не оценивалась. См. [Мониторинг транзакций в песочнице](https://docs.didit.me/ru/integration/sandbox-testing.md#мониторинг-транзакций-в-песочнице), чтобы узнать, как проверить правило перед запуском в эксплуатацию.
* **Режим правила `DISABLED` или `TEST`** - проверьте *Rules → \[rule] → Mode*. Только правила `ACTIVE` влияют на скоринг; правила `TEST` выполняются, но не влияют на статус.
* **Фильтр области действия исключает транзакцию** - например, область `transaction_type = finance` не совпадёт с транзакциями `travelRule`.
* **Окно агрегации короче, чем нужно** - правило "20 транзакций за 30 дней" не сработает после всего 15 транзакций.
* **Поле условия равно null** - например, правило проверяет `counterparty.country_code`, но контрагент не был отправлен.
* **Конвертация валюты** - правило сравнивает порог с `amount_in_default_currency`; если валюта по умолчанию вашего приложения отличается от валюты транзакции, сконвертированная сумма может оказаться ниже порога.

Чтобы воспроизвести прошлую транзакцию и понять, почему правило сработало или не сработало, используйте функцию *Rules → \[rule] → Backtest*.

## Правило срабатывает на все транзакции

**Симптом.** Правило срабатывает для более чем 90% транзакций, и очередь на проверку переполнена.

**Причина.** Условия слишком широкие или пороги слишком низкие.

**Решение.**

* Добавьте фильтры `scope`, чтобы сузить область действия (например, только исходящие или только определённые типы транзакций).
* Повысьте пороги (суммы, количество транзакций за период).
* Переведите правило в режим `TEST` на неделю - проанализируйте `rule_runs`, чтобы увидеть долю совпадений, и ужесточите условия перед повторным включением.

## Истекло время криптоскрининга

**Симптом.** Транзакция завершена со статусом `status: APPROVED`, но в массиве `provider_results[]` для кошелька, хеша транзакции или провайдера криптоскрининга указан `status: FAILED`.

**Причины.**

* API провайдера ненадолго стал недоступен.
* Запрос превысил время ожидания (обычно около 10 с).

**Решение.**

* Транзакции никогда не завершаются с ошибкой из-за проблем провайдеров: обогащение выполняется по принципу максимальных усилий.
* Если конкретный провайдер регулярно выдаёт ошибки, проверьте его страницу статуса или откройте обращение в поддержку.
* Можно настроить предпочтения провайдеров в *Settings → Transaction Monitoring → Providers*, чтобы направлять запросы к другим провайдерам.

## Отсутствует IP-обогащение

**Симптом.** Поле `applicant.ip_enrichment` в транзакции отсутствует или заполнено частично.

**Причины.**

* В запросе нет `applicant.device.ip`.
* IP-адрес приватный или зарезервированный (не маршрутизируется).
* Все провайдеры обогащения временно недоступны.

**Решение.**

* Получайте IP-адрес отправителя на стороне клиента или сервера и передавайте его в каждой транзакции.
* Используйте только маршрутизируемые IP-адреса: Didit без предупреждения пропускает приватные диапазоны.
* Проверьте состояние провайдеров в консоли: *Settings → Status*.

## Несовпадение подписи webhook

**Симптом.** Ваш endpoint отклоняет события, потому что подпись не совпадает.

**Причины.**

* Исходное тело запроса было изменено (JSON пересериализован с другими пробелами).
* Указан неверный секрет.
* Несколько адресов назначения с одним и тем же URL - подписи различаются для каждого адреса назначения.

**Решение.**

* **Подписывайте исходное тело запроса**, а не разобранный JSON. Во многих фреймворках есть промежуточное ПО для получения исходного тела.
* При компрометации секрета перевыпустите его: *Webhook destinations → \[destination] → Rotate secret*.
* Используйте один адрес назначения на каждый URL, чтобы избежать путаницы с секретами.

## Webhook не приходит

**Симптом.** Транзакции создаются, но webhook не приходят.

**Причины.**

* Параметр `enabled` адреса назначения имеет значение `false`.
* URL недоступен из интернета.
* Адрес назначения автоматически отключён после повторных ошибок.
* Событие отсутствует в `subscribed_events`.

**Решение.**

* Отправьте тестовое событие: *Webhook destinations → \[destination] → Send test*.
* Проверьте последние доставки: *Webhooks → \[destination] → Deliveries*. Там видны ответы 4xx/5xx с телом и заголовками.
* Снова включите отключённые адреса назначения.

## Неверная конвертация валюты

**Симптом.** `amount_in_default_currency` не совпадает с ожидаемым курсом.

**Причины.**

* Курс валюты - это средний рыночный курс на дату `txn_date`.
* Транзакции с задним числом используют исторический курс на эту дату.
* Для некоторых валют (экзотических) курсы обновляются реже.

**Решение.**

* Для отображения используйте `amount` и `currency` (исходные).
* Используйте `amount_in_default_currency` только для внутренней проверки порогов правил.
* Для аудита запись о транзакции фиксирует курс конвертации, использованный при оценке.

## Контрагент не совпадает с моим списком блокировки

**Симптом.** Вы добавили компанию в список блокировки по `vendor_data`, но транзакция с этим контрагентом всё равно прошла.

**Причины.**

* В полезной нагрузке транзакции у контрагента нет `vendor_data`, и он сохранён как внешний снимок.
* Регистр `vendor_data` отличается.

**Решение.**

* Всегда передавайте `counterparty.vendor_data`, если контрагент является субъектом на вашей платформе.
* Используйте одинаковый регистр везде: `vendor_data` чувствителен к регистру.

## Транзакции зависают в статусе AWAITING\_USER

**Симптом.** Транзакции остаются в `AWAITING_USER`, потому что пользователь так и не завершает сессию устранения.

**Причины.**

* Пользователь не открыл URL сессии устранения.
* Сессия устранения истекла.
* Транзакция является переводом Travel Rule, который библиотечное правило, например `travel-rule-pending-action`, перевело в `AWAITING_USER`. Didit не создаёт сессию устранения по умолчанию для транзакции Travel Rule, поэтому, если правило не указывает собственный сценарий устранения, нет ссылки, которую можно доставить.

**Решение.**

* Ссылку для доставки возвращает поле `remediation_session_url` в ответе по транзакции. Передайте её пользователю повторно.
* Для транзакции Travel Rule урегулируйте перевод на вкладке **Travel Rule**, затем измените статус транзакции самостоятельно, так как урегулирование перевода само по себе не переводит транзакцию из `AWAITING_USER`.
* Сессии устранения следуют тому же шаблону, что и [быстрый старт KYC](https://docs.didit.me/ru/getting-started/quick-start.md): подпишитесь на webhook о завершении.
* Задайте в своей системе тайм-аут, чтобы помечать устаревшие транзакции как истёкшие, если устранение так и не завершилось.

## Превышение лимита при создании

**Симптом.** `429 Too Many Requests` при всплесках высокой нагрузки.

**Решение.**

* Учитывайте заголовок `Retry-After`.
* Ограничивайте частоту запросов на стороне клиента при всплесках трафика.
* Обратитесь в поддержку, чтобы повысить лимиты при подтверждённом объёме трафика на продакшне.

См. [ограничение частоты запросов](https://docs.didit.me/ru/integration/rate-limiting.md).

## Дальнейшие шаги

> [card] [Руководство по интеграции](https://docs.didit.me/ru/transaction-monitoring/integration-guide.md)
>
> Полные шаблоны интеграции.

> [card] [Правила](https://docs.didit.me/ru/transaction-monitoring/rules.md)
>
> Как работает оценка правил.

> [card] [Webhook](https://docs.didit.me/ru/transaction-monitoring/webhooks.md)
>
> Механика webhook.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.