API для разработчиков

Те же проверки, что в кабинете, для ваших программ: AML-аудит адреса, след средств (куда ушли) и источник средств (откуда пришли) в сетях TRON и Ethereum. Платите теми же запросами с того же счёта и по той же цене.

Адрес службы https://api.cifrasled.ru, все методы под /v1. Полное описание методов и полей — в OpenAPI: по нему можно собрать клиента генератором.

Начало работы

  1. Пополните счёт и включите второй фактор в настройках кабинета. Ключ даёт постоянный доступ к запросам счёта, поэтому без этого его не завести.
  2. В кабинете, в разделе «API», заведите ключ. Начните с тестового cs_test_…: он не ходит в сеть и ничего не списывает.
  3. Проверьте, что ключ работает:
curl https://api.cifrasled.ru/v1/key \
  -H "Authorization: Bearer $CIFRASLED_KEY"

Запустите аудит адреса. Ответ придёт сразу, со статусом running:

curl https://api.cifrasled.ru/v1/audits \
  -H "Authorization: Bearer $CIFRASLED_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: payout-20261021-0042" \
  -d '{"address": "T9yD14Nj9j7xAB4dbGeiX9h8unkKLxmGkn"}'

HTTP/1.1 202 Accepted
Location: /v1/checks/6b1f0c2e-…

{"id": "6b1f0c2e-…", "object": "check", "type": "audit",
 "status": "running", "progress": [ … ], "queries_spent": 0, … }

Заберите результат по номеру проверки. Аудит занимает от нескольких секунд до минуты, след средств — до нескольких минут. Опрашивайте не чаще раза в три секунды или задайте у ключа адрес вебхука.

curl https://api.cifrasled.ru/v1/checks/6b1f0c2e-… \
  -H "Authorization: Bearer $CIFRASLED_KEY"

Ключи и защита

Ключ передаётся только заголовком Authorization: Bearer …. Ключ в адресе запроса не принимается: адреса оседают в журналах прокси и в истории браузера.

cs_live_…
Боевой ключ: настоящие данные сети, списывает запросы.
cs_test_…
Тестовый: подставные ответы, ничего не списывает.

Ключ показывается один раз, при создании. Мы храним только его отпечаток и не можем ни показать ключ снова, ни восстановить. Храните его как пароль: в хранилище секретов, а не в коде и не в репозитории.

  • Только с сервера. Ключ в браузере, мобильном приложении или расширении достаётся любому, кто их откроет.
  • Права. У ключа отмечено, какие проверки он может запускать: audit, trace, source. Остальное отвечает 403 scope_denied.
  • Адреса. Ключу можно разрешить обращаться только с ваших адресов или сетей. С другого адреса ответ — 403 ip_not_allowed.
  • Месячный предел. Сколько запросов ключ может потратить за календарный месяц по Москве. Ошибка в цикле не выберет весь счёт.
  • Смена ключа. Заведите новый, переключите программу, отзовите старый. Отзыв действует сразу. Проверки, запущенные старым ключом, остаются доступны новому.
  • Кто завёл. Ключ работает, пока его создатель управляет счётом. Если владелец уберёт администратора из команды, его ключи перестанут действовать сразу: 401 key_orphaned.

О каждом новом ключе приходит письмо владельцу счёта и тому, кто ключ завёл. Если ключ заводили не вы, отзовите его и смените пароль.

Проверки

POST /v1/audits
AML-аудит: можно ли иметь дело с адресом. Право audit.
POST /v1/traces
След VASP: куда ушли средства с адреса, до бирж и других точек остановки. Право trace.
POST /v1/sources
AML-источник: откуда пришли средства и насколько они чисты. Право source.

Адрес сети определяется по виду: T… из 34 знаков — TRON, 0x… из 42 — Ethereum. Какие сети подключены, видно в GET /v1/key.

След и источник начинаются с конкретного перевода. Укажите его хэш в tx_id: так проверка начнётся ровно с него. Если хэша нет, передайте сумму строкой в amount и актив в asset, а время в incident_at (для следа) или received_at (для источника) поможет выбрать нужный перевод, если на эту сумму их несколько.

curl https://api.cifrasled.ru/v1/traces \
  -H "Authorization: Bearer $CIFRASLED_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: case-7781" \
  -d '{"address": "T…", "tx_id": "a3f1…64 знака"}'

Повтор без двойного списания

Придумайте Idempotency-Key до отправки (8–128 знаков: латиница, цифры, -, _) и при обрыве связи повторяйте запрос с тем же ключом. Вторая проверка не запустится: вернётся прежняя с заголовком Idempotent-Replayed: true. Тот же ключ с другим адресом или другим видом проверки — 409 idempotency_conflict. Без заголовка каждый запрос запускает новую проверку.

Статусы

running
Идёт. В progress — план работы: что сделано, что идёт, что впереди.
done
Готово. Результат — в поле по виду проверки: audit, trace или source.
failed
Не удалась. Причина — в error.message, отложенные запросы вернулись на счёт.

Список проверок, запущенных ключами счёта, — GET /v1/checks, свежие сверху, по 20 (до 100 через limit). Следующая страница — с before, равным created_at последней строки. Проверки, которые сотрудники делали в кабинете, в список не попадают. Документ PDF готовой проверки — GET /v1/checks/{id}/report.pdf.

Результат

У аудита главное — audit.verdict: ответ advice, уровень risk и оценка score от 0 до 100. Каждый вывод обоснован в reasons и markers; пробелы в данных отмечены в coverage и не выдаются за чистоту.

dangerous
Иметь дело нельзя: санкции, заморозка эмитентом, мошеннические метки.
careful
Есть тревожные признаки: решайте после разбора причин.
acceptable
Ограничений и тревожных признаков не найдено.
no_data
Проверить не удалось. Это не одобрение.

У следа и источника — точки, где след остановился (endpoints), с причиной reason: exchange (биржа, у неё есть владелец счёта), frozen (заморожено эмитентом), mixer, swap, rest (средства лежат на адресе), no-data, truncated и другие. Доля, судьба которой известна, — в resolved_pct. Суммы — десятичными строками в единицах актива: числом они теряли бы младшие разряды.

Пересказ модели обычным языком — в conclusion. Он объясняет вывод, но не меняет его, и может отсутствовать.

Метки адресов (labels, endpoints[].label) пишут посторонние люди. Показывайте их как текст, а в таблицах экранируйте: значение, начинающееся с =, станет формулой у того, кто откроет файл.

Вебхуки

Если у ключа задан адрес вебхука, по завершении каждой его проверки придёт POST с событием check.completed или check.failed. В теле — та же запись проверки, что отдаёт GET /v1/checks/{id}.

POST /ваш/адрес
Cifrasled-Event: check.completed
Cifrasled-Delivery: 0d9c…
Cifrasled-Signature: t=1761052800,v1=5257a869e7ec…

{"id": "0d9c…", "object": "event", "type": "check.completed",
 "livemode": true, "data": {"check": { … }}}

Подпись — HMAC-SHA256 секретом вебхука от строки t.тело. Секрет показывается один раз, вместе с ключом. Проверяйте подпись по сырому телу запроса, до разбора JSON, и отвергайте сообщения старше пяти минут:

# Python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    ts = int(parts.get("t", "0"))
    if abs(time.time() - ts) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))
// Node.js
import crypto from "node:crypto";

export function verify(secret, header, rawBody, tolerance = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const ts = Number(parts.t);
  if (!ts || Math.abs(Date.now() / 1000 - ts) > tolerance) return false;
  const expected = crypto.createHmac("sha256", secret)
    .update(`${ts}.`).update(rawBody).digest("hex");
  const got = String(parts.v1 ?? "");
  return got.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
}
  • Ответьте 2xx в течение 15 секунд, а тяжёлую обработку ведите после ответа.
  • При другом ответе или молчании повторим через 1, 5, 15 минут, час, 3, 6 и 12 часов, а затем перестанем. Результат при этом остаётся доступен по GET /v1/checks/{id}.
  • Одно событие может прийти дважды. Различайте их по id события.
  • Адрес — только https:// с доступным из интернета именем. Сообщения уходят с адреса 2.58.16.209, перенаправлений не выполняем.

Ошибки

Тело ошибки одинаковое у всех методов. Ветвитесь по code: текст в message написан для человека и может уточняться. request_id присылайте в поддержку вместо ключа.

{"error": {"code": "invalid_address", "param": "address",
           "message": "Адрес TRON начинается с T", "request_id": "c41e…"}}
HTTPcodeЧто делать
400invalid_requestПоле в param не годится. Исправьте запрос.
400invalid_addressАдрес не той длины, не той сети или с опечаткой.
400network_unavailableСеть адреса не подключена. Список — в GET /v1/key.
401unauthorizedКлюча нет, он неверен или отозван.
401key_orphanedСоздатель ключа больше не управляет счётом. Заведите новый.
402insufficient_balanceНе хватает запросов. Пополните счёт в кабинете.
402key_limit_reachedКлюч выбрал месячный предел. Поднимите его в кабинете.
403ip_not_allowedАдреса обращения нет в списке ключа.
403scope_deniedКлючу не разрешён этот вид проверок.
404not_foundНет такой проверки на этом счёте.
409idempotency_conflictКлюч повтора уже занят другой проверкой.
409check_not_readyДокумент появится, когда проверка завершится.
429rate_limitedПодождите столько секунд, сколько в Retry-After.
429concurrency_limitedДождитесь завершения одной из идущих проверок.
503upstream_unavailableИсточник данных сети недоступен. Запросы не списаны.
503report_unavailableСлужба печати недоступна. Повторите позже.
500internal_errorНаша ошибка. Повторите позже с тем же Idempotency-Key.

Пределы

60 в минуту
Запросов к API на один ключ. В ответах — заголовок RateLimit-Limit.
3 проверки
Одновременно идущих на один ключ.
20 в минуту
Документов PDF на один ключ.

Сверх предела ответ — 429 с заголовком Retry-After. Если пределов не хватает, напишите на info@cifrasled.ru: поднимем для вашего ключа.

Списание

Цены в запросах — GET /v1/prices, остаток ключа — GET /v1/balance. Аудит стоит фиксированно. След и источник считаются по работе: каждый раскрытый адрес цепочки — запрос, поэтому указана цена самого короткого хода и минимальный остаток для запуска.

При запуске запросы откладываются, по завершении списывается сделанное, остальное возвращается. За неудавшуюся проверку не списывается ничего. Каждое списание видно в журнале счёта в кабинете с пометкой «API».

Тестовый режим

Ключ cs_test_… принимает те же запросы, но не обращается к сети и ничего не списывает. Проверка «идёт» три секунды, затем отдаёт подставной результат. Исход выбирается полем test_scenario:

/v1/audits
acceptable, careful, dangerous, failed
/v1/traces
traced, failed
/v1/sources
clean, tainted, failed

Тестовые проверки хранятся сутки и видны только тестовым ключам, не больше 1000 в сутки на ключ. У них нет документа PDF и вебхуков. В ответах livemode: false. Боевой ключ поле test_scenario отклоняет.

Версии и хранение

Версия — в пути: /v1. Внутри неё могут появляться новые поля и новые значения перечислений, поэтому разбирайте ответ так, чтобы незнакомое не ломало программу. Удалить или переименовать поле, изменить его смысл можно только в новой версии; о ней предупредим письмом владельцам ключей, а /v1 продолжит работать.

Результат проверки хранится семь дней (expires_at), затем удаляется вместе со следами доставки вебхуков. Забирайте результат к себе. Порядок обработки данных — в политике.