Проверка адресов¶
Один эндпоинт, чтобы прогнать адрес через нашего AML-провайдера прежде, чем отправлять на него деньги.
curl -X POST https://api.pay.nullswap.com/api/v1/aml/check-address \
-H "x-api-key: sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"address": "0xfedcba0987654321fedcba0987654321fedcba09",
"chainId": "1c9a7f36-5f2b-4a83-9d51-0e6b7c8d9a10"
}'
{
"amlResultId": "5c6d7e8f-9a0b-41c2-8d34-5e6f7a8b9c0d",
"merchantId": "9f1d2c3b-4a5e-4f60-8b71-2c3d4e5f6a7b",
"address": "0xfedcba0987654321fedcba0987654321fedcba09",
"chainId": "1c9a7f36-5f2b-4a83-9d51-0e6b7c8d9a10",
"status": "PASSED",
"score": 12,
"tags": [],
"checkedAt": "2026-01-14T09:00:00.000Z",
"fromCache": false
}
| Поле | Тип | Обяз. | Примечания |
|---|---|---|---|
address |
string | да | Адрес для скрининга, в нативном формате сети |
chainId |
uuid | да | В какой сети его интерпретировать |
Важны оба параметра: одна и та же строка в разных сетях — это разные адреса, а EVM-адрес, проверенный по Ethereum и по BNB Chain, — два разных вопроса с двумя, возможно, разными ответами.
Чтение вердикта¶
status |
Значение |
|---|---|
PASSED |
Проверен, ничего компрометирующего не нашлось |
FAILED |
Проверен и помечен |
SKIPPED |
Не проверен. У провайдера нет покрытия либо скрининг здесь неприменим |
SKIPPED — это не PASSED
Это отсутствие ответа, а не ответ «чисто». Принимать такие адреса или нет — ваша политика, но
решение должно быть осознанным. Написав status !== "FAILED", вы молча согласились принимать
любой непроверяемый адрес.
| Поле | Примечания |
|---|---|
score |
Целочисленная оценка риска. Чем выше, тем рискованнее. При SKIPPED бессмысленна |
tags |
Метки провайдера, напр. ["mixer", "sanctions"]. При чистом результате пусто |
checkedAt |
Когда прошёл скрининг — а не когда вы его запросили. При попадании в кеш будет в прошлом |
fromCache |
Переиспользован ли недавний результат вместо новой проверки |
amlResultId |
Указывайте его, если хотите, чтобы вердикт пересмотрели |
Не стройте на score собственные пороги. Наши уже зашиты в status, а шкалу провайдера мы
неизменной не держим. Решайте по status, а score и tags оставьте для своего аудит-лога.
Чем этот эндпоинт не является¶
Его вызов не проверяет входящий платёж
Платежи проверяются автоматически и отдельно, а результат попадает в поля платежа amlStatus и
amlResultId. Этот маршрут — самостоятельная проверка по требованию, которую запускаете вы.
PASSED здесь не меняет ни одной записи инвойса или платежа: им нельзя ни разблокировать
депозит на статическом кошельке со статусом WITHHELD, ни превратить DIRTY-баланс в CLEAN.
И это не шлагбаум перед выплатами. Ни
POST /api/v1/merchant/withdrawals, ни
возврат сюда не обращаются. Нужен скрининг перед
отправкой денег — вызывайте его сами и действуйте по ответу.
Где его стоит вызывать¶
Окупается один сценарий: проверить адрес назначения до того, как вы его приняли.
flowchart TD
A["Клиент присылает адрес для выплаты"] --> B["POST /aml/check-address"]
B --> C{"status"}
C -- "PASSED" --> D["Сохранить в адресную книгу<br/>и продолжить"]
C -- "FAILED" --> E["Отказать и сообщить клиенту,<br/>что адрес отклонён"]
C -- "SKIPPED" --> F["Решает ваша политика"]
D --> G["POST /merchant/withdrawals"]
Два частных случая:
- Адрес возврата.
POST .../refundрегистрирует возврат, который вы уже отправили, — забрать его назад нельзя. Проверяйте адрес, пока клиент ещё на странице. - Адрес назначения для вывода. Проверьте один раз при добавлении в адресную книгу, а не перед каждой выплатой.
Кеширование и стоимость¶
Если проверить тот же адрес повторно, пока не истекло окно актуальности у провайдера, ответ придёт с
fromCache: true, а checkedAt будет указывать на первую проверку. Это дешевле и быстрее, но и
результату при этом может быть несколько часов. Затребовать свежий вердикт через этот эндпоинт
нельзя — держите это в голове, когда решение ответственное.
Кешируйте и у себя. Проверять один и тот же адрес при каждой загрузке страницы — пустая работа: достаточно проверить его, когда он у вас появился, и повторить, если по вашим меркам результат устарел.
Ошибки¶
| Статус | message |
Причина |
|---|---|---|
400 |
InvalidRequestBodyError |
Нет address или chainId, либо chainId не uuid |
403 |
MerchantIsBlockedError |
Мерчант заблокирован |
404 |
ChainWithIdNotFoundError |
Неизвестный chainId |
422 |
EmptyAMLAddressError |
address есть, но пуст или состоит из одних пробелов |
502 |
AMLServiceError |
Провайдер скрининга недоступен или не ответил вовремя |
502 — это не вердикт
AMLServiceError значит, что на вопрос так и не ответили, — это не тихий SKIPPED. Повторите
запрос; если и повтор не удался, обращайтесь с адресом как с непроверенным, а не как с чистым.