Документация API
Добавьте нужные адреса в любой из 23 сетей и получайте уведомление о каждой входящей транзакции: подписанный webhook, событие API, сообщение в Telegram или email, публикацию в Discord либо Slack.
Аутентификация
В каждом запросе передавайте API-ключ в заголовке Authorization. Доступны два ключа: ck_test_… (sandbox — бесплатная имитация транзакций) и ck_live_… (production).
$ curl https://api.cryptanio.com/v1/watches \
-H "Authorization: Bearer ck_live_4t9G…R1SC"
Быстрый старт
Одного запроса достаточно, чтобы начать наблюдение. Следующая транзакция по адресу вызовет первое уведомление — обычно через несколько секунд после попадания в блок.
$ curl -X POST https://api.cryptanio.com/v1/watches \
-H "Authorization: Bearer ck_live_…" \
-H "Content-Type: application/json" \
-d '{
"chain": "ethereum",
"address": "0x7c3A1d4E8b2f6C9a0D5e8F1b4C7a2E5d8B1f9eF2",
"asset": "USDC",
"notify": ["webhook", "telegram"],
"meta": { "invoice_id": "inv_8817" }
}'
{
"id": "wch_01J5WQ4T9GZ3MH8B",
"status": "active",
"chain": "ethereum",
"address": "0x7c3A…9eF2",
"asset": "USDC"
}
Настройте получателей webhook, Telegram, email, Discord и Slack в кабинете либо создайте webhook через API получателей событий, а затем выберите каналы для каждого watch в поле notify. Сначала проверьте интеграцию в sandbox: watches, созданные с ключом ck_test_, можно запустить вручную запросом POST /v1/simulate.
API наблюдений
Объект watch — это один адрес и один актив в одной сети. Именно такие объекты учитывает тариф. Все методы API расположены по адресу https://api.cryptanio.com/v1.
| Метод API | Назначение |
|---|---|
| POST/v1/watches | Создаёт watch. Возвращает 201 с объектом watch. |
| GET/v1/watches | Возвращает список watches с фильтрами по chain, status, meta.invoice_id. |
| GET/v1/watches/:id | Возвращает один watch и его последние платежи. |
| DELETE/v1/watches/:id | Останавливает наблюдение. Транзакции в обработке ещё некоторое время будут приходить в течение защитного периода. |
| GET/v1/payments | Ищет обнаруженные платежи по watch, адресу, идентификатору транзакции или периоду времени. |
| GET/v1/chains | Возвращает сети текущего развёртывания, их правила подтверждения и поддержку токенов. Ключ не требуется. |
| GET/v1/events | Повторно получает доставленные события за период до 30 дней — резервный способ восстановления после недоступности endpoint. |
Поля запроса
| Поле | Тип | Описание |
|---|---|---|
| chain | string | Одно из значений bitcoin, ethereum, solana, tron, ton, bsc, base, xrp, dash. Обязательное поле. Актуальный список возвращает GET /v1/chains. |
| address | string | Адрес получения. Для Solana передавайте кошелёк: связанные token accounts вычисляются и отслеживаются автоматически. |
| asset | string | "native" (по умолчанию), поддерживаемый символ, например USDC, USDT или DAI, либо идентификатор актива для конкретной сети. Актуальные правила активов возвращает GET /v1/chains; сеть без поддержки токенов принимает только native. |
| notify | string[] | Любое из значений webhook, telegram, email, discord, slack. По умолчанию: ["webhook"]. |
| watch_outgoing | boolean | Также уведомлять, когда средства уходят с этого адреса. Исходящие переводы приходят отдельными типами событий — debit.*, но не payment.* — поэтому существующая обработка входящих платежей не меняется. Не каждая сеть поддерживает исходящие операции: неподдерживаемая сеть отклонит создание watch с явной ошибкой, а не выполнит запрос частично. |
| expires_at | string | Необязательное время в формате RFC 3339. Подходит для инвойсов: watch отключится автоматически. |
| meta | object | До 10 собственных пар ключ-значение, которые возвращаются в каждом уведомлении. |
Новый адрес может получить статус pending. По умолчанию новый адрес в аккаунте, где уже есть адреса, активируется не сразу, а поле active_at показывает время включения. Защитное окно даёт владельцу возможность заметить адрес, который он не добавлял: уведомление отправляется во все подключённые каналы сразу после добавления, а удаление ожидающего адреса ничего не стоит. Первый адрес и все sandbox-адреса активируются сразу; задержку можно изменить или отключить в кабинете.
Webhooks
Каждое изменение состояния отправляется одним HTTP POST на ваш endpoint. Доставка работает по принципу at-least-once: повторы возможны и ожидаемы. Удаляйте дубликаты по (chain, tx_id, index, address, asset) или просто по event_id.
| Заголовок | Значение |
|---|---|
| X-Event-Id | Уникальный идентификатор события (ULID). Также присутствует в теле как event_id. |
| X-Event-Type | Один из двенадцати типов ниже. Маршрутизируйте по этому заголовку, а не по полю внутри тела. |
| X-Timestamp | Unix-время в секундах на момент подписи; входит в подписываемые данные. |
| X-Signature | HMAC-SHA256 в hex-формате для строки <timestamp>.<body>. |
| X-Attempt | Номер попытки доставки, начиная с 1. |
Типы событий
Три семейства намеренно разделены. Маршрутизация идёт по типу, поэтому вывод средств или изменение multisig нельзя случайно принять за входящий платёж из-за непрочитанного поля.
| Тип | Что означает |
|---|---|
| payment.pending | Средства поступили, и сеть увидела транзакцию. Финальности ещё нет. |
| payment.confirmed | Средства поступили, транзакция подтверждена. По этому событию можно выдавать товар. |
| payment.rolled_back | Реорганизация отменила входящую транзакцию. Платёж считается несостоявшимся. |
| debit.pending | Средства уходят с адреса. Только для watches с параметром watch_outgoing. |
| debit.confirmed | Средства ушли, транзакция подтверждена. |
| debit.rolled_back | Реорганизация отменила исходящую транзакцию. |
| contract.approval | Для вашего адреса выдано разрешение на расходование. |
| contract.owner_added | В отслеживаемом multisig появился новый владелец. |
| contract.owner_removed | Из multisig удалён владелец. |
| contract.threshold_changed | Изменилось необходимое число подписей. |
| contract.permissions_changed | Заменён встроенный в сеть набор разрешений аккаунта, включая порог подписей. |
| asset.unexpected | Поступил неожиданный актив. Средства действительно перемещены, но ничего не зачислено. |
Две формы тела, а не двенадцать. Семейства payment.* и debit.* содержат объект payment с суммой. Семейство contract.* и событие asset.unexpected содержат объект contract вместо него — без суммы и глубины подтверждения, потому что эти события ничего не переводят.
Тело события
{
"event_id": "01J5WQ4T9GZ3MH8B2E7KD6R1SC",
"event_type": "payment.confirmed",
"chain": "ethereum",
"occurred_at": "2026-08-16T13:52:01Z",
"watch_id": "wch_01J5WQ4T9GZ3MH8B",
"payment": {
"tx_id": "0x9b41f2…c77d",
"index": 2,
"height": 20731442,
"address": "0x7c3A…9eF2",
"asset": "USDC",
"contract": "0xA0b8…eB48",
"amount_raw": "250000000",
"decimals": 6,
"amount": "250",
"confirmations": 12,
"meta": { "invoice_id": "inv_8817" },
"fiat": {
"currency": "USD",
"value": 250.00,
"rate": 1,
"rate_at": "2026-08-16T13:00:00Z"
}
}
}
{
"event_id": "01J5WQ8N2PB4KC7XR3TE9MDA5F",
"event_type": "debit.confirmed",
"chain": "bitcoin",
"occurred_at": "2026-08-16T14:07:44Z",
"watch_id": "wch_01J5WQ4T9GZ3MH8B",
"payment": {
"tx_id": "c1d89fd9…fc8f",
"index": 0,
"height": 964207,
"address": "bc1qltw…uxjh",
"asset": null,
"amount_raw": "435000",
"decimals": 8,
"direction": "out",
"confirmations": 3
}
}
{
"event_id": "01J5WQ9X6RT2VN5HB8KQ4WZE7M",
"event_type": "contract.owner_added",
"chain": "ethereum",
"occurred_at": "2026-08-16T14:19:02Z",
"contract": {
"tx_id": "0x4ae1…b902",
"log_index": 4,
"height": 20731509,
"address": "0x7c3A…9eF2",
"kind": "owner_added",
"detail": { "owner": "0x91Bd…4c7A" }
}
}
- direction принимает значение "in" или "out" и всегда присутствует у платежа. Направление также следует из типа события; используйте удобный вариант, но не определяйте его по знаку суммы — суммы никогда не бывают отрицательными.
- Каждое значение в detail передаётся строкой. Allowance имеет тип uint256, который не помещается в JSON number.
- match_key содержит назначение, переданное самой сетью: комментарий TON или reference Solana Pay. Поле отсутствует в сетях и платежах без такого значения — то есть в большинстве случаев.
- mode принимает значение "live" или "test": какое окружение отправило событие. Значение находится в подписанном теле, а не только в заголовке, поэтому тестовый запрос нельзя выдать production-endpoint без этой пометки.
- amount_raw — строка в минимальных единицах актива. JSON numbers теряют точность после 2⁵³ и не вмещают Ethereum uint256 — используйте целочисленный тип произвольной точности. amount — удобная десятичная строка для отображения, но не для вычислений.
- Ваш объект meta возвращается внутри payment, а не рядом. Всё, что передано при создании watch — invoice_id, номер заказа или идентификатор клиента — приходит в payment.meta, поэтому одного чтения достаточно для получения платежа и его назначения.
- index разделяет несколько зачислений в одной транзакции: индекс выхода Bitcoin, индекс лога Ethereum, ноль в Solana.
- meta повторяет данные, прикреплённые к watch, и позволяет маршрутизировать события без запроса к базе данных.
- fiat показывает стоимость платежа на момент поступления, использованный курс и время его фиксации — выгрузка сегодня и через месяц даст одинаковое число. Поле отсутствует, если курс недоступен или токен не удалось определить: для сверки отсутствие значения лучше догадки. Токены определяются по контракту через ценовой источник, поэтому жёстко заданный список не требуется.
Повторные попытки
- Тайм-аут одной попытки: 10 s. Любой ответ не 2xx или отсутствие ответа запускает повторную попытку.
- Экспоненциальная задержка от 2 s до 15 минут, в течение 24 часов.
- Всё же пропустили событие? GET /v1/events повторно отдаёт события за последние 30 дней.
Проверка подписей
Подпись — это HMAC-SHA256 в hex-формате для строки <timestamp>.<raw body> с секретом webhook в качестве ключа (кабинет → Webhooks). Сравнивайте за постоянное время и отклоняйте устаревшие timestamp, чтобы закрыть повторное воспроизведение.
const crypto = require("node:crypto");
function verify(secret, timestamp, rawBody, signature) {
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signature));
}
// reject if |now − timestamp| > 300 s, then verify
func verify(secret, ts string, body []byte, sig string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(ts))
mac.Write([]byte("."))
mac.Write(body)
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(sig))
}
Поток событий
GET /v1/stream — поток Server-Sent Events с теми же данными, которые получает webhook. Он подходит там, куда webhook не доберётся: ноутбук за NAT, локальная разработка или браузерная панель реального времени.
$ curl -N https://api.cryptanio.com/v1/stream \
-H "Authorization: Bearer ck_live_…"
: connected
retry: 5000
event: payment
data: {"event_id":"01J5WQ…","event_type":"payment.confirmed", … }
: ping
- Каждое событие использует event: payment, а data: содержит тот же JSON, который был бы отправлен webhook: одинаковые поля и форма позволяют использовать один парсер.
- Строки, начинающиеся с двоеточия, — комментарии и встроенный keep-alive SSE. Одна приходит при подключении, затем каждые двадцать секунд, чтобы отличить тихий аккаунт от разорванного соединения.
- Это не архив событий. Приходят только события, возникшие во время подключения. Пропущенные данные доступны через GET /v1/events за последние 30 дней.
- Переподключайтесь свободно — параметр retry: 5000 указывает стандартному EventSource вернуться через пять секунд; браузерные реализации делают это автоматически.
API получателей событий
Подписывайте URL на события аккаунта без открытия кабинета — например, при создании tenant или для staging-окружения, которое должно получать те же платежи, что production.
| Метод API | Назначение |
|---|---|
| POST /v1/endpoints | Подписывает URL с протоколом https://. Возвращает endpoint и его secret — секрет показывается только один раз. |
| GET /v1/endpoints | Возвращает подписки аккаунта. Секреты повторно не показываются. |
| DELETE /v1/endpoints/:id | Останавливает доставку на endpoint. |
| GET /v1/health | Проверяет доступность и возвращает текущую версию. Ключ не требуется. |
{
"url": "https://example.com/hooks/cryptanio",
"label": "staging"
}
→ 201
{
"id": "ep_01J5WQ4T9GZ3MH8B",
"url": "https://example.com/hooks/cryptanio",
"label": "staging",
"secret": "0460765e9292…544ce",
"source": "api",
"created_at": "2026-08-16T13:52:01Z"
}
- Каждый endpoint подписывает события собственным секретом, который возвращается один раз при создании. Проверяйте подпись как описано выше; для ротации создайте новый endpoint и удалите старый.
- Только https. Событие содержит адрес будущего платежа, поэтому передавать его открытым текстом нельзя.
- До двадцати на аккаунт. Это не тарифный лимит: превращение одного платежа в сотню доставок расходует исходящий трафик и ресурсы чужого endpoint, а обычной интеграции достаточно нескольких адресатов.
API инвойсов
Запросите конкретную сумму и получите событие при её поступлении. Инвойс берёт адрес из вашей адресной книги, удерживает его на время заказа и сопоставляет точную поступившую сумму — не нужно угадывать, какой платёж относится к какой корзине.
Это модуль приёма платежей. Каждый аккаунт получает десять инвойсов в месяц; платный тариф увеличивает лимит. Адреса берутся из вашей адресной книги — API не создаёт место получения средств. Изменение платёжного адреса требует пароля и уведомления во всех каналах и выполняется в кабинете.
| Метод API | Назначение |
|---|---|
| POST/v1/invoices | Создаёт инвойс. Возвращает 201 с адресом и точной суммой для отображения. |
| GET/v1/invoices | Возвращает список с фильтрами по project, chain, status. |
| GET/v1/invoices/:id | Возвращает текущее состояние одного инвойса. |
| POST/v1/invoices/:id/cancel | Отменяет инвойс и освобождает адрес. Запись остаётся доступной, чтобы отменённый заказ можно было найти. |
Поля запроса
| Поле | Тип | Описание |
|---|---|---|
| chain | string | Обязательное поле. Список совпадает с GET /v1/chains. |
| amount | string | Обязательная десятичная строка в единицах актива — "12.50", не центы и не float. JSON number потеряет младшие разряды токена с 18 знаками после запятой. |
| asset | string | Символ актива. По умолчанию используется нативная монета сети. |
| reference | string | Ваш идентификатор заказа. Возвращается в каждом событии, поэтому отдельное сопоставление не нужно. |
| project | string | Проект или направление бизнеса. По умолчанию используется первый проект; пул адресов не смешивается между проектами. |
| address | string | Закрепляет один из ваших адресов вместо выбора из пула. Несколько открытых заказов смогут использовать его одновременно и различаться по сумме. |
| tolerance | string | Допустимая недоплата, которая всё ещё считается оплатой, например из-за удержанной у отправителя сетевой комиссии. Пустое значение требует точного совпадения. |
| expires_in | number | Минуты. Инвойс удерживает адрес на весь срок, поэтому значение ограничено сверху. |
{
"chain": "bitcoin",
"amount": "0.0125",
"reference": "order-4471",
"expires_in": 30
}
→ 201
{
"id": "chg_01J5WQ4T9GZ3MH8B",
"status": "pending",
"reference": "order-4471",
"chain": "bitcoin",
"asset": "BTC",
"address": "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
"asked": "0.0125",
"amount": "0.01250002",
"amount_raw": "1250002",
"decimals": 8,
"sandbox": false,
"expires_at": "2026-08-16T14:22:01Z",
"created_at": "2026-08-16T13:52:01Z"
}
- Показывайте amount, а сверяйте по amount_raw. Если другой открытый заказ на том же адресе уже ждёт такую же круглую сумму, мы добавим несколько минимальных единиц, чтобы различить платежи. asked — согласованная с покупателем сумма; amount — сумма, которая должна фактически поступить.
- Инвойс закрывается теми же событиями, что и остальные процессы. Webhook срабатывает на платёж, а инвойс одновременно переходит в paid. Отдельного потока событий для подписки нет.
- Два состояния требуют решения человека. underpaid и late устанавливают needs_decision и ожидают: Cryptanio не решает за вас, считать ли оплатой недостающую сумму или перевод после срока. Обработайте их в кабинете.
- Тестовый ключ создаёт только sandbox-инвойсы на sandbox-адресах. Интеграционные тесты могут работать весь день, не резервируя адреса реальных заказов: освобождённый адрес ждёт 48 часов перед возвратом в пул, и активные тесты иначе быстро исчерпали бы его.
Жизненный цикл платежа
Каждый платёж проходит явную машину состояний. Каждый переход создаёт одно уведомление, а настроенные каналы получают отдельные доставки.
| Состояние | Значение | Когда приходит |
|---|---|---|
| pending | Транзакция находится в блоке, который ещё может быть отменён. | Через несколько секунд после включения в блок — покажите прогресс на странице оплаты. |
| confirmed | Глубина или финальность достигла уровня, который сеть считает необратимым. | Для каждой сети действует своё правило: финальность протокола в Ethereum, BNB Chain и Base; finalized slot в Solana; solidified block в TRON; ChainLock в Dash; validated ledger в XRP; глубина 3 в Bitcoin. По этому событию можно выдавать товар. |
| rolled_back | Блок покинул цепочку из-за реорганизации либо транзакция завершилась ошибкой. | Только при наличии подтверждения, никогда по отсутствию данных. Событие редкое, но именно оно делает остальные два статуса надёжными. |
Платёж, отменённый реорганизацией и позже снова включённый в блок, создаёт новую последовательность pending → confirmed с новой ревизией — журнал событий остаётся полным и упорядоченным.
Лимиты и оплата
Тарифы мониторинга различаются только объёмом: все сети, каналы и весь API доступны на каждом уровне, включая бесплатный объём. Отличается только уровень поддержки. Полные цены — на странице мониторинга.
| Тариф | Адресов под наблюдением | Уведомлений в месяц | Цена |
|---|---|---|---|
| Бесплатно | 5 | 1,000 | $0 |
| Start | 50 | 10,000 | $9 / месяц |
| Pro | 500 | 100,000 | $29 / месяц |
| Scale | 5,000 | 1,000,000 | $99 / месяц |
- Watch = один адрес + один актив. Учитываются активные watches; удалённые или истёкшие сразу освобождают место.
- Уведомление = одно изменение состояния. Отправка в несколько каналов и повторная доставка одного события не увеличивают использование.
- Превысили лимит? Когда тарифицируемый перерасход выключен, как по умолчанию, уведомления продолжают приходить ещё 48 часов, а мы сообщаем по email: без неожиданных списаний и молча потерянных событий. Если вы сами включите перерасход, оплата ограничится заданным месячным пределом.
- Лимит API: 10 запросов/с на бесплатном уровне, 50 запросов/с на платных тарифах. 429 с заголовком Retry-After при превышении.
Остались вопросы?
Напишите на hello@cryptanio.com — обычно инженер отвечает в течение нескольких часов.