Міграція з AMLBot
Якщо ваш сервіс уже перевіряє адреси й транзакції через API AMLBot, ви можете перейти на Leeri, не чіпаючи його код запитів. Leeri надає AMLBot-сумісний ендпоінт, який відтворює контракт обміну даними поле в поле: ті самі запити у форматі форми, той самий токен MD5, той самий конверт відповіді й той самий цикл pending і recheck. Ця сторінка описує цей контракт так, як його реалізовано в Leeri.
Перехід за один день
Змінюються три змінні середовища, більше нічого.
| Змінна | На що змінити |
|---|---|
AMLBOT_URL | https://api.leeri.ai/compat/amlbot |
AMLBOT_ID | accessId вашого compat-облікового запису. |
AMLBOT_KEY | Секрет того самого compat-облікового запису. |
Побудова запитів, обчислення токена, кодування форми, імена полів і ваш цикл pending лишаються точно такими, як були.
Compat-обліковий запис видає Leeri разом із вашим обліковим записом: напишіть на hello@leeri.ai. Він окремий від ключів ak_, які використовуються в нативному API, і причина технічна. Протоколу потрібно, щоб сервер перераховував токен MD5 із секрету у відкритому вигляді, а ключ API зберігається незворотно і його неможливо відновити. Compat-обліковий запис має власні accessId, секрет і ротацію. Під час ротації деякий час приймаються і старий, і новий секрет, тож перехід вашого сервісу на новий — це зміна конфігурації, а не простій.
Compat-обліковий запис належить до середовища, sandbox або live, як і ключ API. Почніть із sandbox-облікового запису: див. Перевірка циклу pending.
Запити
Обидва типи запитів — це POST із Content-Type: application/x-www-form-urlencoded на той самий URL. Який це запит, визначають наявні поля.
| Поле | Перевірка адреси | Перевірка транзакції |
|---|---|---|
accessId | обов'язкове | обов'язкове |
token | обов'язкове | обов'язкове |
hash | адреса для скринінгу | хеш транзакції |
asset | обов'язкове | обов'язкове |
address | не надсилається | адреса транзакції для скринінгу |
direction | не надсилається | deposit або withdrawal |
asset — це символ точно так, як у Підтримуваних активах. Невідомі поля відхиляються. direction приймає скорочене значення withdrawa, яке надсилають деякі клієнти, і читає його як withdrawal.
Токен
token = MD5("{hash}:{key}:{accessId}")
hash — це значення поля hash, яке ви надсилаєте, key — ваш compat-секрет, accessId — ваш compat-accessId. Результат — дайджест у нижньому регістрі, 32 hex-символи.
Токен обчислюється один раз за початковим запитом перевірки й надсилається без змін під час кожного recheck. Його ніколи не перераховують із uid перевірки. Ваш клієнт уже поводиться саме так; не змінюйте цього.
- curl
- Node.js
- Python
TOKEN=$(printf '%s' "$ADDRESS:$AMLBOT_KEY:$AMLBOT_ID" | openssl md5 | awk '{print $NF}')
curl -s -X POST "$AMLBOT_URL" \
--data-urlencode "accessId=$AMLBOT_ID" \
--data-urlencode "token=$TOKEN" \
--data-urlencode "hash=$ADDRESS" \
--data-urlencode "asset=TRX"
import { createHash } from 'node:crypto';
const { AMLBOT_URL, AMLBOT_ID, AMLBOT_KEY } = process.env;
const token = createHash('md5').update(`${address}:${AMLBOT_KEY}:${AMLBOT_ID}`).digest('hex');
const response = await fetch(AMLBOT_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ accessId: AMLBOT_ID, token, hash: address, asset: 'TRX' }),
});
const body = await response.json();
import hashlib
import os
import requests
url = os.environ["AMLBOT_URL"]
access_id = os.environ["AMLBOT_ID"]
key = os.environ["AMLBOT_KEY"]
token = hashlib.md5(f"{address}:{key}:{access_id}".encode()).hexdigest()
response = requests.post(
url,
data={"accessId": access_id, "token": token, "hash": address, "asset": "TRX"},
timeout=30,
)
body = response.json()
Для перевірки транзакції надішліть хеш транзакції як hash і додайте address та direction. Токен і далі MD5("{hash}:{key}:{accessId}") із цим хешем транзакції.
Відповіді
На верхньому рівні лише result і balance. Корисне навантаження вкладено в data.
{
"result": true,
"balance": 4210,
"data": {
"status": "success",
"uid": "5b0c3f64-1a52-4c8e-9f3e-2f6c1d7a9e10",
"riskscore": 0.74,
"signals": {
"atm": 0,
"child_exploitation": 0,
"dark_market": 0,
"dark_service": 0,
"decentralized_exchange_contract": 0,
"enforcement_action": 0,
"exchange": 0.05,
"exchange_fraudulent": 0,
"gambling": 0,
"illegal_service": 0,
"infrastructure_as_a_service": 0,
"liquidity_pools": 0,
"malware": 0,
"marketplace": 0,
"merchant_services": 0,
"miner": 0,
"mixer": 0.12,
"other": 0,
"p2p_exchange": 0,
"p2p_exchange_mlrisk_high": 0,
"payment": 0,
"ransom": 0,
"risky_exchange": 0,
"sanctions": 0,
"scam": 0,
"seized_assets": 0,
"stolen_coins": 0,
"terrorism_financing": 0,
"unnamed_service": 0.31,
"wallet": 0,
"unnamed_entity_low_risk": 0,
"unnamed_entity_medium_risk": 0,
"unnamed_entity_high_risk": 0
},
"address": "TEXAMPLEexampleEXAMPLEexample00000",
"fiat_code_effective": "USD",
"counterparty": null,
"reportedAddressBalance": null,
"addressDetailsData": null,
"blackListsConnections": false,
"hasBlackListFlag": false,
"pdfReport": "https://…",
"memo": null,
"asset": "TRX",
"network": "tron",
"timestamp": "2026-10-27 09:14:04"
}
}
Значення ілюстративні. Перевірка транзакції відповідає тими самими полями й додає amount, risky_volume, risky_volume_fiat, fiat, direction і tx.
Чотири поля керування потоком
| Поле | Яку гілку воно визначає |
|---|---|
result | Успіх (true) або збій (false). |
data.status | Остаточна відповідь чи ще pending. |
balance | Гілка вичерпаного балансу. |
data.uid | Що опитує recheck. |
Усі інші поля — дані для показу.
Статус
data.status | Значення |
|---|---|
success | Перевірка остаточна, а data містить результат. |
pending | Перевірка в черзі. data містить лише status, uid, asset, network, address і timestamp. Опитуйте, як описано в Pending і recheck. |
failed, error | Завершальні статуси контракту. Подальший recheck їх ніколи не розв'язує, тож припиніть опитування. Перевірку, що завершилася без вердикту, Leeri повідомляє через result: false, описаний нижче. |
Збої повертають HTTP 200
Збій — це не HTTP-помилка. Ендпоінт відповідає 200 і ставить result у false:
{
"result": false,
"balance": 0,
"description": "AML check failed\nInvalid token"
}
description має два рядки. Перший — фіксований текст AML check failed, а причина стоїть у другому рядку, звідки ваш клієнт її вже й читає.
| Причина в другому рядку | Значення | Що робити |
|---|---|---|
Invalid token | accessId невідомий, відкликаний чи прострочений, токен не збігається, або recheck називає uid, який ніколи не приймався для цього облікового запису. Усе це відповідає однаково. | Перевірте обліковий запис і обчислення токена. Під час recheck переконайтеся, що надсилаєте початковий токен. |
Out of balance | Ваш ліміт і попередньо поповнений баланс вичерпано. | Поповніть і повторіть. Раніше повтор не допоможе. |
Analysis unavailable, please retry | Джерело даних, від якого залежить вердикт, було недоступне. Нічого не стягується. | Повторіть пізніше. |
Service temporarily unavailable, please retry | Неочікуваний збій з нашого боку. | Повторіть з експоненційною затримкою. |
| Повідомлення про валідацію | Актив не підтримується, адреса чи хеш транзакції мають хибну форму для активу, direction не є напрямом, або поле пропущено чи невідоме. | Виправте запит. Повтор без змін дає ту саму відповідь. |
| Повідомлення про ємність | Ємність для звернень заповнена. Нічого не приймається й не стягується. | Повторіть після короткої паузи. |
Єдина відповідь не 200 на цьому ендпоінті — обмеження частоти запитів: він стоїть за тими самими загальними лімітерами, що й нативне API, і відповідає 429 із Retry-After. Див. Обмеження частоти запитів і ліміти.
Баланс
balance — це кількість перевірок, які Leeri ще обслужить для вас: залишок ліміту вашого плану плюс те, що ще можна купити за попередньо поповнений баланс. Це не буквальний попередньо поповнений баланс, який майже весь здоровий розрахунковий період дорівнює 0, бо ліміт витрачається першим. Точний попередньо поповнений баланс — у вашому рахунку та кабінеті. Після збою автентифікації balance дорівнює 0.
Оцінка ризику й сигнали
riskscore— частка від 0 до 1, отримана масштабуванням оцінки Leeri від 0 до 100. Це ніколи не ціле число зі 100.signalsмістить фіксований словник із 33 ключів, показаний вище. Кожен ключ присутній у кожній відповіді, і більшість дорівнює0. Кожне значення — частка експозиції. Знахідки й експозицію Leeri згруповано в ці ключі для сумісності протоколу; це групування, а не відповідність категорій один до одного.- Коли сама перевірена адреса має позначення, що пояснює більшу частину оцінки, наприклад адреса санкційної сутності,
signalsназиває цю категорію зі значенням1, а кожен інший ключ —0.riskscoreне змінюється. - Попередження безпеки гаманця, яке застерігає власника адреси й нічого не каже про її ризик, ніколи не відображається в
riskscoreчиsignals. blackListsConnectionsдорівнюєfalse, а не порожньому масиву, коли збігів немає. Перевіряйте самеfalse, бо порожній масив істинний.timestamp— рядок видуYYYY-MM-DD HH:MM:SS, ніколи не число Unix.
Доказовий звіт
data.pdfReport — постійне посилання на доказовий звіт перевірки, що входить у ціну перевірки. PDF формується під час першого відкриття посилання. Посилання дорівнює null у рідкісному випадку, коли звіт не вдалося побудувати, і решта відповіді це не зачіпає. У pending-перевірки pdfReport ще немає. Звіт може прочитати кожен, хто має посилання, тож поводьтеся з ним як зі звітом.
Поля, що лишаються порожніми
reportedAddressBalance, addressDetailsData і memo завжди null. counterparty дорівнює null, якщо жодна знахідка не називає біржу власником адреси. Баланси перевіреної адреси на момент перевірки є в доказовому звіті.
Pending і recheck
Коли перевірка не може завершитися в межах запиту, відповідь має result: true, data.status: "pending" і uid. Опитуйте так:
POST https://api.leeri.ai/compat/amlbot/recheck
Шлях без кінцевого слеша. Поля форми: accessId, uid і початковий token.
- curl
- Node.js
- Python
curl -s -X POST "$AMLBOT_URL/recheck" \
--data-urlencode "accessId=$AMLBOT_ID" \
--data-urlencode "uid=$UID" \
--data-urlencode "token=$TOKEN"
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
let body = firstResponse;
for (let attempt = 1; body.result && body.data.status === 'pending' && attempt <= 10; attempt += 1) {
await sleep(30_000);
const response = await fetch(`${AMLBOT_URL}/recheck`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ accessId: AMLBOT_ID, uid: body.data.uid, token }),
});
body = await response.json();
}
import time
body = first_response
attempt = 0
while body["result"] and body["data"]["status"] == "pending" and attempt < 10:
attempt += 1
time.sleep(30)
body = requests.post(
f"{url}/recheck",
data={"accessId": access_id, "uid": body["data"]["uid"], "token": token},
timeout=30,
).json()
- Відповідь має той самий конверт, що й початкова перевірка: усе ще
pending, остаточний результат абоresult: false. - Recheck читає вже прийняту перевірку. Він нічого нового не запускає й не тарифікується.
- Токен має збігатися з тим, що передано в початковому запиті. Інший токен або
uid, який цей обліковий запис ніколи не приймав, даєInvalid token. - Цикл, який уже виконує ваш клієнт, опитує кожні 30 секунд до 10 спроб, тобто бюджет 5 хвилин. Leeri зберігає відповідність між
uidі початковим токеном 30 хвилин після прийняття перевірки, тож цей цикл у неї добре вкладається. Після цього recheck відповідаєInvalid token.
Перевірка циклу pending
Для sandbox-облікового запису перевірка адреси для активу BTC та адреси 1PENDNGCHECKADDRESSFRSANDBXTEST99 завжди відповідає pending, тож ви можете пройти весь цикл уже першого дня. Див. Sandbox і live. Та сама адреса під live-обліковим записом завершується як зазвичай.
Тарифікація
Compat-перевірка тарифікується за тими самими правилами, що й нативна. Спершу списується залишок ліміту, потім попередньо поповнений баланс. Повторна перевірка тієї самої адреси в тому самому ланцюгу протягом 7 днів безкоштовна. Невдала перевірка, відхилений запит і вердикт, що частковий через недоступне джерело даних, не тарифікуються. Доказовий звіт входить у перевірку. Подробиці — в Обмеження частоти запитів і ліміти. Тарифи — на сторінці цін.
Коли буде час: нативне API
Сумісний ендпоінт залишає вашу інтеграцію без змін. Нативне API — це те, на що варто переходити, коли хочеться більшого від кожного вердикту:
- Кожна знахідка посилається на джерело, на якому ґрунтується, а вердикт закріплений, тож його можна відтворити пізніше. Див. Перевірки адрес і Rederive.
- Вебхук доставляє кожну завершену перевірку, тож опитувати нічого.
Обидві поверхні працюють на тому самому рушії й тому самому наборі правил, і їх можна використовувати разом з одним обліковим записом. Питання щодо міграції: hello@leeri.ai.