POST /apiv2/screening
Заказ AML-проверки блокчейн-адреса: единая структура ответа для каждого провайдера и любого состояния заказа, десятичные числа в виде строк и единый формат ошибок.
URL эндпоинта
POST https://netts.io/apiv2/screeningЗаголовки запроса
| Header | Required | Description |
|---|---|---|
| Content-Type | Да | application/json |
| X-API-KEY | Да | Ваш API-ключ из панели управления Netts |
| X-Idempotency-Key | Нет | Ваш собственный ключ для безопасных повторных запросов. См. Идемпотентность |
Тело запроса
{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait_for_result": true
}Параметры
| Parameter | Type | Required | Description |
|---|---|---|---|
| address | string | Да | Проверяемый адрес, от 10 до 128 символов |
| network | string | Да | Тикер сети. Тикеры, поддерживаемые каждым провайдером, возвращаются методом GET /apiv2/screening/providers |
| provider | string | Да | elliptic или bitok. Значения по умолчанию нет |
| wait_for_result | boolean | Нет | true ожидает результат до 15 секунд. По умолчанию false |
| language | string | Нет | Язык отчета. Только en |
Неизвестные поля отклоняются. Тело запроса, содержащее поле, отсутствующее в таблице выше, возвращает 400 с кодом 4001.
Поле provider обязательно и не имеет значения по умолчанию. Вы всегда сами выбираете провайдера, которого оплачиваете.
В схеме provider является произвольной строкой, а не перечислением. На сегодняшний день принимаются два значения; добавление третьего провайдера не должно ломать интеграцию тех, кто валидирует ответы по схеме. Актуальный список, поддерживаемые каждым провайдером сети и используемые шкалы оценок возвращаются методом GET /apiv2/screening/providers.
Примеры
cURL — ожидание результата
curl -X POST https://netts.io/apiv2/screening \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-d '{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait_for_result": true
}'cURL — подтверждение приема и опрос статуса
curl -X POST https://netts.io/apiv2/screening \
-H "Content-Type: application/json" \
-H "X-API-KEY: your_api_key" \
-d '{
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "bitok"
}'Ответ — 202 Accepted с заголовком Location, указывающим на заказ.
Python
import requests
from decimal import Decimal
url = "https://netts.io/apiv2/screening"
headers = {
"Content-Type": "application/json",
"X-API-KEY": "your_api_key",
}
payload = {
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic",
"wait_for_result": True,
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code in (200, 202):
body = response.json()
print("Order:", body["order"]["client_order_id"])
print("Status:", body["order"]["status"])
if body["risk"]["score"] is not None:
# Parse provider numbers as Decimal, never as float
print("Score:", Decimal(body["risk"]["score"]), "of", body["risk"]["scale"]["max"])
print("Level:", body["risk"]["level"], "-", body["risk"]["level_source"])
print("Charged:", body["billing"]["charged_amount"], body["billing"]["charged_currency"])
else:
problem = response.json()
print(problem["code"], problem["title"], "-", problem["detail"])Коды ответа
| Situation | Code | Headers |
|---|---|---|
| Заказ создан, проверка выполняется в фоне | 202 Accepted | Location: /apiv2/screening/{client_order_id} |
Результат возвращен в ответе (wait_for_result) | 200 OK | — |
| Использован результат недавней проверки, списание не производилось | 200 OK | — |
| У адреса нет активности в блокчейне, списание не производилось | 200 OK | — |
| Ошибка | см. Ошибки | Content-Type: application/problem+json |
Ответы, содержащие результат проверки, отправляются с заголовком Cache-Control: private, no-store.
Ответ
{
"schema_version": 2,
"order": {
"client_order_id": "A90D21F68C9AEA2",
"status": "completed",
"api_version": "v2",
"cache_hit": false,
"created_at": "2026-09-13T08:14:29.614988Z",
"started_at": "2026-09-13T08:14:30.288251Z",
"completed_at": "2026-09-13T08:14:34.993174Z"
},
"request": {
"address": "YOUR_ADDRESS_HERE",
"network": "trx",
"provider": "elliptic"
},
"billing": {
"charged": true,
"price_usdt": "0.98",
"base_amount": "2.882421",
"markup_amount": "0",
"charged_amount": "2.882421",
"charged_currency": "TRX",
"exchange_rate": "0.33999200",
"payment_status": "pending"
},
"precheck": {
"activity_checked": true,
"activity_status": "active",
"source": "tron-address-checker"
},
"check": {
"provider": "elliptic",
"provider_check_id": "b4903a5d-9f22-4075-b51b-beb40b419b97",
"checked_at": "2026-09-13T08:14:32.144000Z",
"status": "completed",
"provider_status": "complete"
},
"risk": {
"score": "0.9634087310611608",
"scale": { "min": 0, "max": 10 },
"level": "low",
"level_source": "computed",
"provider_level": null,
"policy": "netts-risk-v1",
"by_direction": {
"source": "0.12332156899576921",
"destination": "0.9634087310611608"
}
},
"sanctions": {
"self": false,
"self_entities": null,
"exposure": {
"entity": "HTX (formerly Huobi) - Post-Sanctions - UK Sanctions List - 26 May 2026",
"category": "Exchange",
"share_fraction": "0.004409451392423414",
"proximity": "indirect",
"hops": 3,
"direction": "source",
"rule_name": "Sanctioned, TF & CSAM"
},
"items": []
},
"exposure": [
{
"category": "Exchange",
"share_fraction": "0.1888065152442461",
"direction": "source",
"hops": 2,
"is_screened_address": false,
"entities": [
{ "name": "Binance", "category": "Exchange", "is_vasp": true,
"is_primary": true, "is_after_sanction_date": null }
]
}
],
"rules": [
{ "name": "Sanctioned, TF & CSAM", "type": "exposure", "level": null,
"score": "0.061426483114820525", "share_fraction": null, "category": null,
"proximity": null, "direction": "source", "detected_at": null }
],
"entities": [
{ "name": "Unknown", "category": "Unknown", "is_vasp": null,
"is_primary": true, "is_after_sanction_date": false }
],
"primary_entity": {
"name": "Unknown", "category": "Unknown", "is_vasp": null,
"is_primary": true, "is_after_sanction_date": false
},
"sanctioned_entities": [],
"wallet": {
"inflow_usd": "354663.6116669158",
"outflow_usd": "80248.63081808022"
},
"provider_data": { }
}Набор полей никогда не меняется
Каждый перечисленный выше блок присутствует в каждом ответе, независимо от провайдера и состояния заказа. То, что провайдер не предоставляет, возвращается как null; пустой список передается как [], а не null; блок, в котором пока нет данных, заполняется значениями null, а не опускается. Единый парсер способен обработать как только что принятую проверку, так и ту же проверку после ее завершения.
Два правила для вашего кода:
- игнорируйте неизвестные вам поля. Новые поля добавляются в эти блоки без выпуска новой версии. Отклонение неизвестного поля является ошибкой на вашей стороне;
provider_dataне является частью контракта. Структура этого объекта зависит от провайдера и меняется вместе с ним. Все гарантии контракта распространяются исключительно на вышеперечисленные блоки.
order
| Field | Type | Description |
|---|---|---|
| client_order_id | string | Идентификатор заказа, используемый для последующего получения результата |
| status | string | pending, processing, completed, skipped, failed |
| api_version | string | Версия контракта, создавшего заказ |
| cache_hit | boolean | true, если был повторно использован недавний результат и списание не производилось |
| created_at | string | RFC 3339, UTC, микросекунды |
| started_at | string | null | Время запуска запроса к провайдеру. null для skipped |
| completed_at | string | null | Время получения результата |
| error | string | Только для failed: причина ошибки |
| reason | string | Только для skipped: address_inactive |
Все временные метки указаны в UTC по стандарту RFC 3339 с суффиксом Z и точностью до микросекунд.
billing
| Field | Type | Description |
|---|---|---|
| charged | boolean | Были ли списаны средства |
| price_usdt | string | Базовая цена провайдера в USDT |
| base_amount | string | Стоимость заказа в валюте списания без наценки субаккаунта |
| markup_amount | string | Наценка субаккаунта. "0" для прямого аккаунта |
| charged_amount | string | Сумма, фактически списанная с баланса |
| charged_currency | string | TRX |
| exchange_rate | string | null | Курс, использованный для конвертации |
| payment_status | string | paid, pending, failed, not_charged, postpaid |
payment_status имеет значение pending в течение короткого времени после успешной проверки: списание сначала холдируется и подтверждается в течение часа. failed означает, что средства были возвращены. not_charged означает, что списание не создавалось (повторно использованный результат или неактивный адрес). postpaid — см. Постоплатные аккаунты.
precheck
Перед платной проверкой адрес проверяется на наличие активности в блокчейне. Адрес без активности не отправляется провайдеру и не тарифицируется.
| Field | Type | Description |
|---|---|---|
| activity_checked | boolean | Выполнялась ли предварительная проверка. false в сетях, где она не поддерживается |
| activity_status | string | active, inactive, unknown |
| source | string | null | Название сервиса или механизма проверки |
Значение unknown не отменяет платную проверку: если сервис проверки активности недоступен, адрес считается активным.
check
| Field | Type | Description |
|---|---|---|
| provider | string | Провайдер, выполнивший проверку |
| provider_check_id | string | null | Собственный идентификатор проверки провайдера — укажите его при оспаривании результата с ним |
| checked_at | string | null | Время формирования результата провайдером |
| status | string | См. таблицу ниже |
| provider_status | string | null | Исходный статус провайдера без изменений |
order.status | check.status | Meaning |
|---|---|---|
pending | pending | Заказ принят, еще не запущен |
processing | running | Провайдер обрабатывает запрос |
completed | completed | Результат получен |
failed | failed | Ошибка до вызова или во время вызова провайдера |
skipped | not_performed | У адреса нет активности; провайдер не вызывался, средства не списывались |
risk
| Field | Type | Description |
|---|---|---|
| score | string | null | Собственная оценка провайдера в виде десятичной строки |
| scale | object | min и max шкалы данного провайдера |
| level | string | none, low, medium, high, severe |
| level_source | string | computed — уровень рассчитан нами по оценке; provider — передан провайдером напрямую |
| provider_level | string | null | Исходное обозначение уровня от провайдера, если оно возвращается |
| policy | string | Название политики пороговых значений, netts-risk-v1 |
| by_direction | object | Оценка с разделением на source и destination, если поддерживается провайдером |
Оценка риска никогда не пересчитывается в другую шкалу. Elliptic использует диапазон 0–10, а BitOK — 0–1, и 7 баллов по одной шкале ни в каком смысле не эквивалентны 0.7 по другой. Шкала передается в ответе, чтобы интеграция, разработанная для одного провайдера, не интерпретировала некорректно данные другого после изменения конфигурации.
Уровень риска приведен к единой терминологии во всем API. Если провайдер возвращает собственный уровень, мы передаем его без изменений и указываем это в level_source; если нет — мы рассчитываем уровень на основе оценки по порогам netts-risk-v1 и указываем соответствующий источник. Одно и то же обозначение используется в ответе API, панели управления и PDF-отчете для одной и той же проверки.
exposure[], rules[], entities[]
exposure[] содержит детализацию средств по категориям контрагентов. rules[] перечисляет сработавшие правила провайдера. entities[] указывает сущности, к которым принадлежит сам адрес; primary_entity выбирает одну из них по фиксированному правилу — сущность, которую провайдер отметил как основную, в противном случае первую из них, иначе null. sanctioned_entities[] содержит те сущности из entities[], которые помечены как активные после даты введения санкций.
Доли выражаются дробями, а не процентами
Каждая доля в ответе представлена единым полем share_fraction — десятичной строкой в диапазоне от "0" до "1".
Elliptic reports 31.574732212596924 % -> "share_fraction": "0.31574732212596924"
BitOK reports 0.8488 -> "share_fraction": "0.8488"Провайдеры используют разные единицы измерения: одна и та же треть объема связей возвращается как 31.57 у одного и 0.3157 у другого. Единое поле, содержащее оба варианта, было бы невозможно разобрать без знания провайдера. Исходное число провайдера в его оригинальных единицах сохраняется в provider_data.
Числа передаются в виде строк
Каждое число, поступающее от провайдера (оценки, доли, объемы в USD), а также каждая сумма в блоке billing, передаются в виде десятичной строки.
"score": "0.9634087310611608"Парсинг этого значения как числа JSON в JavaScript, Go или любом другом языке с двоичной плавающей точкой приводит к неточностям, и отображаемое значение перестает совпадать с данными провайдера. Обрабатывайте эти поля с помощью десятичных типов: Decimal в Python, BigDecimal в Java, decimal.Decimal или обычная строка в JavaScript.
Собственные поля системы (scale.min, scale.max, hops) передаются как обычные числа JSON.
Повторное использование недавнего результата
При повторной проверке того же адреса, сети и провайдера в течение 60 секунд возвращается предыдущий результат, и списание не производится.
Каждый запрос по-прежнему создает отдельный заказ со своим client_order_id; в повторно использованном ответе выставляется "cache_hit": true, а в блоке billing возвращается "charged": false со статусом "payment_status": "not_charged". Идентификатор исходного заказа, из которого был взят результат, не раскрывается — он может принадлежать другому аккаунту.
Повторное использование работает только в пределах одного аккаунта. Результат проверки, выполненной другим пользователем, вам никогда не возвращается.
Идемпотентность
Передавайте заголовок X-Idempotency-Key с собственным значением для обеспечения безопасности повторных запросов: одинаковый ключ с тем же телом запроса вернет сохраненный ответ вместо заказа повторной проверки.
| Situation | Code | Response |
|---|---|---|
| Первый запрос с этим ключом еще выполняется | 409 | 4090 |
| Тот же ключ, но другое тело запроса | 409 | 4093 |
| Тот же ключ и то же тело запроса, выполнение завершено | сохраненный код | сохраненный ответ |
Если вы не передаете заголовок, ключ генерируется автоматически на основе API-ключа, адреса, провайдера и вашего IP-адреса с окном в две секунды. Это защищает от случайного двойного клика и повтора на уровне шлюза, но не от повторного запроса через минуту: такой запрос будет считаться новым заказом и будет тарифицирован.
Error Responses
Каждая ошибка приложения возвращается по стандарту RFC 9457 с заголовком Content-Type: application/problem+json:
{
"type": "https://doc.netts.io/api/v2/errors/insufficient-funds",
"title": "Insufficient funds",
"status": 403,
"detail": "Insufficient funds. Required: 2.888742 TRX, Available: 1.203000 TRX",
"instance": "/apiv2/screening",
"code": 1004,
"required_trx": "2.888742",
"available_trx": "1.203000"
}Поля type, title, status, detail и instance являются стандартными. Числовой code — расширение: опирайтесь на него при обработке ошибок. Дополнительные поля зависят от типа ошибки и должны игнорироваться, если они вам неизвестны.
| Code | HTTP | Meaning |
|---|---|---|
4000 | 400 | Некорректный JSON в теле запроса |
4001 | 400 | Поле не прошло валидацию или передано неизвестное поле |
4002 | 403 | Провайдер недоступен для вашего аккаунта |
4003 | 400 | Некорректный формат идентификатора заказа |
4004 | 400 | Провайдер не поддерживает указанную сеть |
4010 | 401 | API-ключ не передан |
4011 | 401 | API-ключ или IP-адрес отклонен |
4040 | 404 | Заказ не найден |
4041 | 404 | Аккаунт не найден |
4090 | 409 | Запрос с данным ключом идемпотентности еще выполняется |
4091 | 409 | Дублирующийся запрос |
4093 | 409 | Данный ключ идемпотентности был использован с другим телом запроса |
1004 | 403 | Недостаточно средств на балансе |
5000 | 500 | Внутренняя ошибка |
5001 | 500 | Списание средств не удалось |
5002 | 500 | Заказ не был создан |
5030 | 503 | Провайдер временно недоступен |
Ошибки другого формата
Некоторые сбои происходят на уровне шлюза до того, как запрос достигает приложения, и они возвращаются в формате шлюза. Любой ответ, у которого Content-Type отличается от application/problem+json, следует классифицировать следующим образом:
| Situation | HTTP | Body |
|---|---|---|
| API-ключ отсутствует или не принят | 401 | {"detail":{"code":-1,"msg":"Invalid or missing API key"}} |
| Превышен лимит запросов | 429 | {"message":"API rate limit exceeded"} |
| Неизвестный путь или метод не поддерживается маршрутом | 404 / 405 | {"detail":"Method Not Allowed"} |
Ограничения частоты запросов
5 запросов в секунду и 150 в минуту, суммарно для всех эндпоинтов проверок.
Постоплатные аккаунты
Аккаунты с постоплатной системой расчетов используют тот же эндпоинт, URL, заголовки и тело запроса, что и остальные. Отличие заключается в механизме оплаты проверки:
- Средства с депозита не списываются. Стоимость каждой выполненной проверки в долларах США (например, $0.98 для Elliptic) начисляется к задолженности аккаунта в валюте расчетов, зафиксированной в вашем договоре. Оплата производится по счетам в соответствии с условиями договора.
- Для аккаунта устанавливается кредитный лимит. Пока задолженность находится в пределах лимита, проверки принимаются даже при нулевом депозите.
- Оплачиваются только успешно завершенные проверки. Проверка с ошибкой, адрес без активности (
skipped) и повторно использованный недавний результат бесплатны.
Постоплатная система расчетов подключается командой Netts для аккаунта по запросу.
billing постоплатной проверки
"billing": {
"charged": false,
"price_usdt": "0.98",
"base_amount": "2.960725",
"markup_amount": "0",
"charged_amount": "2.960725",
"charged_currency": "TRX",
"exchange_rate": "0.33100000",
"payment_status": "postpaid"
}| Field | Description |
|---|---|
| charged | false: с депозита ничего не списывается |
| price_usdt | Стоимость проверки в долларах США. Эта сумма добавляется к задолженности аккаунта |
| charged_amount | Та же стоимость в TRX, для справки |
| payment_status | postpaid. Для завершившейся ошибкой или пропущенной проверки — not_charged |
Достигнут кредитный лимит (402)
{
"type": "https://doc.netts.io/api/v2/errors/credit-limit-reached",
"title": "Postpaid credit limit reached",
"status": 402,
"detail": "Postpaid credit limit reached.",
"instance": "/apiv2/screening",
"code": 1004,
"payment_mode": "postpaid",
"reason": "limit_reached"
}Проверка не заказывается, начисление средств не производится. Прием новых проверок возобновляется после учета платежа или увеличения лимита.
Коды ошибок постоплаты
| Code | HTTP | Description |
|---|---|---|
1004 | 402 | Достигнут кредитный лимит постоплаты |
5032 | 503 | Цена временно недоступна |
5034 | 503 | Биллинг временно недоступен — проверка не принята |
5036 | 503 | Проверка кредитного лимита временно недоступна — повторите попытку позже |
При всех указанных выше ответах заказ не создается и списание не начисляется.
Примечания
- Тарификация: фиксированная цена за проверку у каждого провайдера, см. GET /apiv2/screening/providers; списывается с TRX-баланса по курсу на момент списания.
- Время обработки: большинство проверок завершаются за несколько секунд; проверка адреса с большой историей транзакций может занять до трех минут. Используйте асинхронный режим и запрашивайте результат методом GET /apiv2/screening/{client_order_id}.
- Неактивные адреса возвращают статус
skippedи не тарифицируются. - Необработанный ответ провайдера никогда не возвращается. Поле
provider_dataпредставляет собой отфильтрованную проекцию; данные, относящиеся к нашему аккаунту у провайдера, а не к проверяемому адресу, никому не раскрываются.
Отчеты
Эндпоинт возвращает исключительно JSON. Форматы PDF и Markdown не поддерживаются.
Все компоненты, необходимые для формирования отчета, уже присутствуют в ответе: унифицированный блок данных и provider_data. Генерация отчета на вашей стороне позволяет получить документ нужного вам вида — с вашим брендингом, языком и структурой, что особенно важно при перепродаже проверок: отчет с логотипом нашей платформы не подходит для передачи конечному клиенту.
Если вам требуется отчет в качестве официального подтверждения для третьей стороны (банка, регулятора, контрагента), учитывайте, что неподписанный PDF-файл не имеет юридической силы независимо от того, кто его создал: его можно отредактировать в текстовом редакторе за минуту. Для верифицируемого документа требуется цифровая подпись или публичная страница проверки подлинности, что представляет собой отдельную функциональность. Если перед вами стоит такая задача, сообщите требования вашего контрагента.
Для тех же самых проверок в панели управления Netts доступны визуальные отчеты в формате PDF на семнадцати языках.
См. также
- GET /apiv2/screening/{client_order_id} — получение результатов проверки
- GET /apiv2/screening/history — история ваших проверок с пагинацией по курсору
- GET /apiv2/screening/providers — провайдеры, цены, поддерживаемые сети, шкалы оценок
- GET /apiv2/screening/price — стоимость проверки для конкретного провайдера
- Санкции в результатах AML — структура блока
sanctionsи флаги провайдеров