Документация API
API даёт серверу вашего приложения то же, что кабинет: справочник монет и курсы, балансы и историю адресов, новые адреса, расчёт комиссии и отправку переводов, уведомления о поступлениях.
Содержание
Адрес API: https://api.coinvertus.net/v1
Общие правила
- Вызов — POST на адрес API с именем вызова, например /v1/assets. {COIN} в пути — тикер или ID монеты из assets, {TASK_ID} — task_id задачи.
- Тело — JSON-объект не больше 64 КБ; если параметров нет, тело можно не передавать. Успешный ответ — сам объект или список, без обёртки.
- Суммы — строками с точкой, в единицах монеты, без хвостовых нулей. Время — строка ISO 8601 в UTC, например 2026-10-04T12:00:00Z.
- network — код сети из assets. Он обязателен, если монета есть в нескольких сетях (иначе 400 A014).
- Текст ошибки приходит на языке из Accept-Language (русский, английский, китайский); решения принимайте по коду ошибки.
| Вызов | Право ключа | Описание |
|---|---|---|
POST /v1/assets | без ключа, если вызов открыт гостям | Монеты и сети API и их возможности. |
POST /v1/rates | без ключа, если вызов открыт гостям | Курсы монет и токенов страницами. |
POST /v1/rate/{COIN} | без ключа, если вызов открыт гостям | Курс одной монеты. |
POST /v1/checkaddress/{COIN} | без ключа, если вызов открыт гостям | Проверка адреса; с ключом — свой ли он. |
POST /v1/paybalance | read | Платёжный баланс в USD. |
POST /v1/getbalance[/{COIN}] | read | Балансы по монетам и сетям. |
POST /v1/addresses/{COIN} | read | Выданные адреса монеты. |
POST /v1/txinfo/{COIN} | read | Транзакция ваших адресов по txid. |
POST /v1/transactions/{COIN} | read | История ваших адресов. |
POST /v1/getnewaddress/{COIN} | addresses | Новый адрес или новый тег. |
POST /v1/getfee/{COIN} | send | Комиссия сети и комиссия сервиса. |
POST /v1/spendinfo/{COIN} | send | С каких адресов уйдут деньги. |
POST /v1/preparetx/{COIN} | send | План отправки. |
POST /v1/posttx | send | Подтверждение плана и постановка задачи. |
POST /v1/task/{TASK_ID} | send | Состояние задачи отправки. |
POST /v1/task/{TASK_ID}/cancel | send | Отмена задачи в очереди. |
С чего начать
- Подключите в кабинете приложение-аутентификатор или подтвердите почту: ключи API создаются и меняются только с кодом подтверждения.
- В разделе «Ключи API» создайте ключ (до 10 на аккаунт): отметьте права и укажите белый список IP-адресов или подсетей вашего сервера — запрос с другого адреса получит 403 A005.
- Сохраните ID ключа (ak_…) и секрет: секрет показывается один раз. Потеряли — перевыпустите его на странице ключа.
- Для уведомлений укажите адрес вебхука в разделе «Вебхуки» и сохраните его секрет (whsec_…).
- Перед отправками пополните платёжный баланс: с него списывается комиссия сервиса.
| Право ключа | Описание |
|---|---|
read | Балансы, адреса, история транзакций, платёжный баланс. |
addresses | Выдача новых адресов. |
keys | Приватные ключи новых адресов (priv в getnewaddress) — вместе с правом addresses. |
send | Расчёт комиссии, подготовка и отправка переводов, задачи. |
Подпись запроса
Запрос с ключом несёт два заголовка. v1 — HMAC-SHA256 в шестнадцатеричном виде от строки «t.POST.путь.тело», ключ — секрет ключа API. Путь — как в адресе запроса, начиная с /v1/ (со строкой запроса, если она есть); тело — ровно те байты, что вы отправляете, у пустого тела — пустая строка. t — время Unix в секундах: подпись, которая расходится с часами сервера больше чем на 5 минут, отклоняется.
| Заголовок | Описание |
|---|---|
X-CVC-Key | ID ключа: ak_ и 24 шестнадцатеричных знака. |
X-CVC-Signature | Подпись: t=<время Unix>,v1=<подпись>. |
t = 1789647000
msg = 1789647000.POST./v1/getbalance/DOGE.{"network":"dogecoin-mainnet"}
v1 = hex(HMAC-SHA256(secret, msg))
X-CVC-Key: ak_0f1e2d3c4b5a69788796a5b4
X-CVC-Signature: t=1789647000,v1=<v1>Справочные вызовы (assets, rates, rate, checkaddress) CVC может открыть и без ключа: такой запрос идёт без обоих заголовков, лимит считается по IP-адресу. Если вызов гостям закрыт — 401 A004.
Ответы и ошибки
Отказ — HTTP-код и тело error: code — код ошибки, message — текст, fields — поля запроса, не прошедшие проверку (если они известны).
{
"error": {
"code": "A014",
"message": "Укажите network: монета есть в нескольких сетях.",
"fields": [
"network"
]
}
}Запрос к адресу API без вызова отвечает 200 и {"status":"OK","version":"…"} с версией приложения — так проверяют доступность. Несуществующий вызов — 404 и {"status":"error","code":404}.
| Код HTTP | Код ошибки | Что значит |
|---|---|---|
400 | A002 | Неверный запрос: тело — JSON-объект до 64 КБ с полями нужного вида. |
401 | A003 | Ключ или подпись запроса не прошли проверку. |
401 | A004 | Для этого вызова нужен ключ API. |
403 | A005 | Запрос пришёл с адреса не из белого списка ключа. |
403 | A006 | У ключа нет права, которое нужно вызову. |
403 | A007 | Вызов недоступен на вашем тарифе. |
404 | 404 | Такого вызова нет: тело ответа {"status":"error","code":404}, без поля error. |
503 | A009 | Вызов выключен, сеть или нода сейчас недоступны либо адрес занят прошлым переводом. Повторите позже. |
429 | A010 | Превышен лимит запросов. Повторите через столько секунд, сколько в заголовке Retry-After. |
500 | A011 | Внутренняя ошибка. Повторите запрос позже. |
405 | A012 | Используйте метод POST. |
404 | A013 | Монета не найдена. |
400 | A014 | Укажите network: монета есть в нескольких сетях. |
404 | A015 | Транзакция не найдена. |
403 | A016 | Исчерпана квота адресов, выданных через API, в этой сети. |
409 | A018 | Не хватает средств на сумму и комиссию сети. |
422 | A019 | Расчёт и отправка этой монеты через API пока не поддерживаются. |
409 | A020 | Не хватает платёжного баланса на комиссию сервиса. Пополните баланс. |
404, 409 | A021 | План отправки не найден, истёк или устарел. Подготовьте отправку заново. |
404 | A022 | Задача не найдена. |
409 | A024 | Задачу уже нельзя отменить: отменить можно только задачу в очереди. |
Лимиты
У каждого вызова свой лимит запросов в секунду (по умолчанию — 1), а также в минуту и в месяц — по вашему тарифу; поверх действует общий потолок аккаунта из тарифа. Месяц — календарный, по UTC. При превышении — 429 A010 с заголовком Retry-After. Гостям лимит считается по IP-адресу (IPv6 — по сети /64). Вызовы, которые обращаются к ноде сети (getfee, spendinfo, preparetx, у Monero и Zcash — ещё checkaddress и getnewaddress), в части сетей ограничены дополнительно: один ключ — не чаще раза в несколько секунд в каждой сети, и общий потолок таких вызовов сети в минуту. Отказ — тот же 429 A010 с Retry-After.
Справочные вызовы
assets
Список пар «монета × сеть», которые обслуживает API, и их возможности. Пары меняются редко — справочник можно хранить у себя и обновлять раз в сутки.
[
{
"coin": "DOGE",
"name": "Dogecoin",
"network": "dogecoin-mainnet",
"network_name": "Dogecoin",
"testnet": false,
"type": "coin",
"contract": null,
"decimals": 8,
"formats": [
"base58"
],
"confirmations": 6,
"min_amount": null,
"can_send": true,
"multi_recipient": true,
"tag": false,
"fee_levels": [
"fast",
"normal",
"low"
]
}
]| Поле | Описание |
|---|---|
coin | Тикер монеты или токена — его можно передавать в {COIN}. |
network, network_name, testnet | Код сети для network, её название и признак тестовой сети. |
type, contract | coin — монета сети, token — токен с адресом контракта в contract. |
decimals | Знаков после точки в суммах. |
formats | Форматы адресов, которые можно запросить в getnewaddress. |
confirmations | Сколько подтверждений нужно, чтобы транзакция стала confirmed. |
can_send | Пару можно отправлять через API: getfee, preparetx, posttx. |
multi_recipient | В одной транзакции можно указать несколько получателей. |
tag | У получателя бывает тег назначения — to[].tag. |
fee_levels | Уровни комиссии, которые отдаёт getfee и принимает preparetx в fee: у UTXO с оценкой по блокам — fast, normal и low, у остальных — только normal; пустой список — отправки нет. |
min_amount | Зарезервировано: min_amount пока null. |
rates, rate/{COIN}
Курсы монет и токенов каталога в USD, EUR, RUB, CNY и INR, страницами по 100 (page от 1; пустая страница — конец списка). coins — необязательный список тикеров или ID, до 100. Нет курса — null, updated_at — время курса. rate/{COIN} возвращает один такой элемент.
{
"coin": "DOGE",
"id": "dogecoin",
"name": "Dogecoin",
"usd": "0.2251",
"eur": "0.2089",
"rub": "18.42",
"cny": "1.6237",
"inr": "18.91",
"updated_at": "2026-09-17T12:10:00Z"
}checkaddress/{COIN}
Проверяет адрес в сети пары. Запрос: address, network. Ответ: valid, address (в каноническом виде), coin, network, format. С ключом с правом read — ещё is_mine (адрес выдан вашему аккаунту) и balance (его подтверждённый баланс); без ключа и для чужого адреса — null.
Балансы и история
paybalance
Платёжный баланс, с которого списывается комиссия сервиса: usd — доступно, reserved — в заявках на вывод и в комиссиях незавершённых задач; auto_topup, threshold, topup_amount — настройки автопополнения (порога нет — false и null).
getbalance[/{COIN}]
Без {COIN} — пары, где у вас есть адреса; с {COIN} — все сети монеты или одна, если указан network. balance — подтверждённый баланс, pending — входящие без подтверждений, available — можно отправить сейчас, fiat — balance в пяти валютах, addresses — число адресов, stale — данные могут отставать от сети.
[
{
"coin": "DOGE",
"network": "dogecoin-mainnet",
"type": "coin",
"balance": "250",
"pending": "0",
"available": "250",
"fiat": {
"usd": "56.28",
"eur": "52.23",
"rub": "4605",
"cny": "405.93",
"inr": "4727.5"
},
"addresses": 3,
"updated_at": "2026-09-17T12:10:00Z",
"stale": false
}
]addresses/{COIN}
Выданные адреса пары в порядке выдачи, по 100 на страницу (page): address, format, label, balance, pending, created_at. У токена — адреса его сети с балансом токена.
txinfo/{COIN}, transactions/{COIN}
txinfo — транзакция ваших адресов по txid (в том виде, как его показывает обозреватель сети). Транзакцию, выпавшую из mempool, монитор удаляет: на неё 404 A015, а вебхук tx.dropped сообщит об этом.
transactions — история ваших адресов в паре по 100 на страницу, новые сверху, неподтверждённые первыми. Фильтры: address — свой адрес, from и to — время транзакции включительно. Новые транзакции сдвигают страницы — для сверки удобнее окно from/to.
{
"txid": "c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0",
"coin": "DOGE",
"network": "dogecoin-mainnet",
"direction": "in",
"status": "confirmed",
"confirmations": 6,
"block": 5912340,
"time": "2026-09-17T12:04:00Z",
"transfers": [
{
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"direction": "in",
"amount": "250",
"tag": null
}
],
"fee": null,
"fee_coin": "DOGE"
}| Поле | Описание |
|---|---|
direction | in — входящая, out — с ваших адресов. |
status | new — ждёт подтверждений, confirmed — подтверждений не меньше confirmations пары, failed — сеть отклонила транзакцию, комиссия сети списана. |
block, confirmations, time | Блок, подтверждения и время транзакции; пока транзакция в mempool, block и time равны null. |
transfers | Движения по вашим адресам, сложенные по адресу и направлению. У UTXO расход — входы целиком, сдача — отдельной строкой in. tag — тег назначения входящего перевода. |
fee, fee_coin | Комиссия сети исходящей транзакции и её монета (у токена — монета сети). |
Выдача адресов
getnewaddress/{COIN} выдаёт новый адрес в сети пары. Запрос: network, format (один из formats пары), label (подпись до 190 символов), priv. В сети с тегом назначения адрес аккаунта один — вызов выдаёт к нему новый tag. Квоту адресов, выданных через API, на аккаунт в сети задаёт CVC — сверх неё 403 A016.
{
"coin": "DOGE",
"network": "dogecoin-mainnet",
"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD",
"format": "base58",
"tag": null,
"privkey": null
}priv: true (нужно право keys) — в ответе privkey: приватный ключ, зашифрованный AES-256-GCM. Ключ шифрования — HMAC-SHA256(секрет ключа API, «privkey») в байтах, значение — base64(nonce 12 байт ‖ шифртекст ‖ метка 16 байт). В сетях, где ключ принадлежит кошельку ноды, privkey всегда null.
Отправка: порядок
- getfee — комиссия сети на уровнях fast, normal, low и комиссия сервиса; spendinfo — с каких адресов уйдут деньги.
- preparetx — план перевода: источники, получатели, комиссия, шаги. План ничего не резервирует и живёт 5 минут (expires_at).
- Проверьте план и подтвердите его: posttx с prepare_id и confirm = HMAC-SHA256(секрет ключа, «key_id.fingerprint.prepare_confirm.prepare_time»), где key_id — ID ключа, подготовившего план.
- posttx ставит задачу в очередь и списывает комиссию сервиса; очередь отправляет перевод в течение нескольких секунд. Итог — task/{TASK_ID} или вебхук task.done.
| Поле | Описание |
|---|---|
to | Получатели: address и amount; tag — тег назначения, comment — текст получателю до 120 символов, где сеть это поддерживает. Несколько получателей (до 100) — только у пар с multi_recipient; при send_all — один получатель без amount. |
from | Свои адреса-источники (address); без from адреса подбираются сами. В сетях с аккаунтами — один адрес. |
order | Порядок подбора источников: desc (по умолчанию) — сначала крупные адреса, asc — мелкие. |
fee | preparetx: fast, normal (по умолчанию) или low; в UTXO-сетях — ещё ставка числом в единицах fee_rate_unit. В сетях с аккаунтами — только normal; у токенов с оплатой энергии — ещё rent или burn. |
change | preparetx, UTXO-сети: куда вернуть сдачу — auto (по умолчанию, адрес самого крупного входа), new (новый адрес) или свой адрес этой сети. |
send_all | preparetx: true — отправить всё с источников за вычетом комиссии. |
getfee и spendinfo
getfee: те же to, from, order. fee_coin — монета комиссии сети (у токена — монета сети); fast, normal, low — amount и пять валют либо null, если уровня у сети нет или на нём сумма с комиссией не помещается (не помещается нигде — 409 A018); service_fee_usd — комиссия сервиса; extra — дополнительные расходы.
{
"coin": "DOGE",
"network": "dogecoin-mainnet",
"fee_coin": "DOGE",
"fast": {
"amount": "0.04452",
"usd": "0.2",
"eur": "0.01",
"rub": "0.5",
"cny": "0.04",
"inr": "0.47"
},
"normal": {
"amount": "0.02226",
"usd": "0.1",
"eur": "0.01",
"rub": "0.5",
"cny": "0.04",
"inr": "0.47"
},
"low": null,
"service_fee_usd": "0.10",
"extra": []
}extra.type | Что значит |
|---|---|
gas | На адресе токена мало монеты сети: amount придёт на него с другого вашего адреса, network_fee — комиссия этого перевода. |
rent | Без provider — создание счёта токена у получателя, если его ещё нет. |
burn, rent | С provider — способы оплаты энергии токена: сжигание (burn) или аренда (rent); selected — способ, который выберет fee normal. |
spendinfo: to и order. sources — адреса с деньгами по порядку order: address, balance (доступно), locked (занят незавершённым переводом), use — сколько с него возьмёт отправка; enough — хватит ли. У токена use — сумма токена, комиссию проверяют getfee и preparetx.
preparetx: план отправки
Запрос: network, to, from, order, fee, change, send_all. Ответ — план и данные для подтверждения в posttx. Не хватает платёжного баланса на комиссию сервиса — 409 A020.
{
"prepare_id": "prep_9a3f0c7d21b84e65f0a1c2d3",
"prepare_confirm": "5c0e8d1f7a2b4c6d9e3f1a0b2c4d6e8f",
"prepare_time": 1789647000,
"expires_at": "2026-09-17T12:15:00Z",
"fingerprint": "0995342725a2b11aa2260e7e84e6394754eef9dcc7412a222e2952b9d9589345",
"coin": "DOGE",
"network": "dogecoin-mainnet",
"tx": {
"sources": [
{
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"amount": "150.5"
}
],
"recipients": [
{
"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD",
"amount": "100"
}
],
"change": {
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"amount": "50.47774"
},
"network_fee": "0.02226",
"fee_coin": "DOGE",
"fee_rate": "100",
"fee_rate_unit": "koinu/vB",
"size": 226,
"replaceable": false
},
"steps": [
{
"type": "send"
}
],
"service_fee_usd": "0.10"
}| Поле | Описание |
|---|---|
tx.sources | Адреса-источники и сколько уйдёт с каждого вместе с комиссией сети. |
tx.recipients | Получатели и суммы; в сетях с тегом или комментарием — tag и comment. |
tx.change | Сдача UTXO: адрес и сумма; без сдачи — null. |
tx.network_fee, tx.fee_coin | Комиссия сети и её монета. |
tx.fee_rate, tx.fee_rate_unit, tx.size, tx.replaceable | UTXO-сети: ставка и её единица, размер транзакции, можно ли заменить её транзакцией с большей комиссией. |
tx.fee_payer, tx.rent | Токены, у которых комиссию платит другой ваш адрес той же транзакцией: этот адрес и плата за создание счёта у получателя. |
steps | Шаги исполнения: gas — сначала пополнение газа (from, to, amount, network_fee), rent — аренда энергии (provider, energy, cost), send — сам перевод. |
expires_at, fingerprint | Срок плана и его отпечаток: подтвердить план можно только до expires_at. |
posttx и задача
posttx: prepare_id и confirm. Ответ — объект задачи. Повтор с тем же prepare_id возвращает ту же задачу — и после срока плана, так что при обрыве связи posttx можно повторить. Чужой план — 404 A021, срок вышел — 409 A021, неверный confirm — 400 A002. task/{TASK_ID} возвращает тот же объект.
{
"task_id": "task_6f1c2a9b0d4e8f7a3c5b1d20",
"task_info": "confirmed",
"task_start": "2026-09-17T12:10:00Z",
"task_sent": "2026-09-17T12:10:04Z",
"task_done": "2026-09-17T12:20:12Z",
"prepare_id": "prep_9a3f0c7d21b84e65f0a1c2d3",
"coin": "DOGE",
"network": "dogecoin-mainnet",
"txid": "b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7",
"gas_txid": null,
"confirmations": 6,
"error_code": null,
"tx": {
"sources": [
{
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"amount": "150.5"
}
],
"recipients": [
{
"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD",
"amount": "100"
}
],
"change": {
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"amount": "50.47774"
},
"network_fee": "0.02226",
"fee_coin": "DOGE",
"fee_rate": "100",
"fee_rate_unit": "koinu/vB",
"size": 226,
"replaceable": false
},
"service_fee_usd": "0.1"
}task_info | Что значит |
|---|---|
queue | В очереди; задачу можно отменить. |
processing | Отправляется. |
gas | Ждёт подтверждения пополнения газа токена. |
rent | Ждёт аренды энергии. |
sent | В сети, ждёт подтверждений. |
unknown | Исход отправки неизвестен: нода не ответила. Не повторяйте перевод — итог определит сверка, и задача перейдёт дальше сама. |
confirmed | Подтверждена. |
failed | Не выполнена — причина в error_code. |
dropped | Транзакция выпала из сети без подтверждений. |
cancelled | Отменена клиентом. |
| Поле | Описание |
|---|---|
task_start, task_sent, task_done | Время постановки, отправки в сеть и конечного статуса; ещё не было — null. |
txid, gas_txid, confirmations | Транзакция перевода, транзакция пополнения газа и подтверждения; до отправки — null. |
error_code | Код причины, если задача не выполнена; иначе null. |
tx, service_fee_usd | План из preparetx и комиссия сервиса, списанная за задачу. |
error_code | Что значит |
|---|---|
A009 | Сеть или нода были недоступны дольше 30 минут, либо исход отправки неизвестен. |
A018 | К моменту отправки денег на адресе не хватило. |
A021 | План устарел (баланс, комиссия или адрес изменились после preparetx) либо аккаунт заблокирован. |
A023 | Сеть отклонила транзакцию; комиссия сети списана. |
A025 | Аренда энергии не удалась. |
task/{TASK_ID}/cancel отменяет задачу в queue — до первой попытки и между повторами; после отправки газа или заказа аренды отмены нет. Позже — 409 A024. Повтор по отменённой задаче возвращает её же.
Особенности сетей
- UTXO-сети: несколько получателей, уровни fast, normal, low или своя ставка, сдача — change; источники — входы с ваших адресов.
- Сети с аккаунтами: один адрес-источник и один получатель, только normal. Адрес с незавершённым переводом занят до его подтверждения — задача ждёт до 30 минут.
- Сети с тегом назначения (tag в assets): to[].tag уходит получателю; входящие на ваш адрес различаются по tag в transfers, а getnewaddress выдаёт новый тег к тому же адресу.
- Сеть с комментарием к переводу: to[].comment — текст до 120 символов; в остальных сетях поле отклоняется (400 A002).
- Токены: комиссия — монетой сети с того же адреса. Если её мало, план начинается шагом gas: пополнение с вашего самого крупного свободного адреса сети, а токен уходит после его подтверждения.
- Токены с оплатой энергии: fee normal — аренда у самого дешёвого подключённого провайдера, иначе сжигание; rent или burn — выбор вручную. Аренда не удалась — failed A025. Провайдеры подключаются в настройках аккаунта, вкладка «Помощники».
- Токены, у которых комиссию и создание счёта получателя платит ваш адрес с наибольшим остатком монеты сети той же транзакцией: в tx — fee_payer и rent, шага gas нет.
- Приватные сети: отправка с одного адреса, getfee — оценка сверху, точная комиссия — в preparetx, privkey недоступен; отправка через кошелёк ноды занимает до нескольких минут.
Комиссия сервиса и платёжный баланс
Комиссия сервиса — по тарифу: процент от суммы в USD с минимумом и максимумом; её показывают getfee и preparetx (service_fee_usd). Она списывается с платёжного баланса при posttx и возвращается, если перевод не дошёл до сети, выпал или задачу отменили. Подтверждённый перевод и отклонённый сетью (failed A023) комиссию не возвращают.
Чтобы отправки не вставали из-за баланса, включите автопополнение в кабинете (Платёжный баланс → Автопополнение); вебхук paybalance.low предупредит, если баланс опустится ниже порога.
Вебхуки
Адрес вебхука задаётся в кабинете, раздел «Вебхуки»: https-адрес, при необходимости IP и Host. Секрет whsec_… показывается один раз; кнопка проверки отправляет ping. Вебхуки доступны на тарифах, где они включены.
Уведомление — POST с телом в JSON. Успех — любой ответ 2xx в течение 10 секунд. Иначе повторяем через 1 минуту, 5 минут, 30 минут, 2 часа, 6 часов и 24 часа. Редиректы не выполняются, ответ читается не больше 64 КБ.
| Заголовок | Описание |
|---|---|
X-CVC-Event | Событие, как event в теле. |
X-CVC-Delivery | event_id и номер попытки. |
X-CVC-Signature | Подпись: t=<время Unix>,v1=<подпись>. |
v1 — HMAC-SHA256 в шестнадцатеричном виде от строки «t.тело», ключ — секрет вебхука (whsec_…). Берите тело ровно в тех байтах, что пришли, до разбора JSON, и отклоняйте уведомление, если t отличается от ваших часов больше чем на 5 минут.
Одно и то же уведомление может прийти дважды — обрабатывайте каждый event_id один раз. Порядок доставки не гарантирован: не откатывайте оплаченный заказ из-за более раннего уведомления.
| Событие | Когда приходит |
|---|---|
tx.new | Новая транзакция ваших адресов. В сетях без наблюдения за mempool приходит с первым подтверждением. |
tx.confirmed | Транзакция подтверждена или отклонена сетью — смотрите status. |
tx.dropped | Транзакция, о которой пришёл tx.new, выпала из сети без подтверждений. |
task.done | Задача отправки дошла до конечного статуса: confirmed, failed, dropped или cancelled. |
paybalance.low | Платёжный баланс ниже порога автопополнения: автопополнение выключено (reason — no_autotopup) или не удалось (autotopup_failed). |
ping | Тестовое уведомление из кабинета. |
Транзакции, случившиеся до включения вебхука, не присылаются. Тело tx.* — объект transaction, как в txinfo; task.done — объект task; paybalance.low — reason и объект paybalance.
{
"event": "tx.new",
"event_id": "evt_0123456789abcdef01234567",
"created_at": "2026-09-17T12:10:00Z",
"transaction": {
"txid": "c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0",
"coin": "DOGE",
"network": "dogecoin-mainnet",
"direction": "in",
"status": "confirmed",
"confirmations": 6,
"block": 5912340,
"time": "2026-09-17T12:04:00Z",
"transfers": [
{
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"direction": "in",
"amount": "250",
"tag": null
}
],
"fee": null,
"fee_coin": "DOGE"
}
}{
"event": "task.done",
"event_id": "evt_89abcdef0123456789abcdef",
"created_at": "2026-09-17T12:20:12Z",
"task": {
"task_id": "task_6f1c2a9b0d4e8f7a3c5b1d20",
"task_info": "confirmed",
"task_start": "2026-09-17T12:10:00Z",
"task_sent": "2026-09-17T12:10:04Z",
"task_done": "2026-09-17T12:20:12Z",
"prepare_id": "prep_9a3f0c7d21b84e65f0a1c2d3",
"coin": "DOGE",
"network": "dogecoin-mainnet",
"txid": "b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7",
"gas_txid": null,
"confirmations": 6,
"error_code": null,
"tx": {
"sources": [
{
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"amount": "150.5"
}
],
"recipients": [
{
"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD",
"amount": "100"
}
],
"change": {
"address": "DLp4hPWtqM8sQZoyk2vRj3TfGcX5nA7bUe",
"amount": "50.47774"
},
"network_fee": "0.02226",
"fee_coin": "DOGE",
"fee_rate": "100",
"fee_rate_unit": "koinu/vB",
"size": 226,
"replaceable": false
},
"service_fee_usd": "0.1"
}
}{
"event": "paybalance.low",
"event_id": "evt_456789abcdef0123456789ab",
"created_at": "2026-09-17T12:10:00Z",
"reason": "no_autotopup",
"paybalance": {
"usd": "3.2",
"reserved": "0.1",
"auto_topup": false,
"threshold": "5",
"topup_amount": "20"
}
}Пример на PHP
Подписанный вызов, план отправки и его подтверждение:
<?php
const CVC_API = 'https://api.coinvertus.net/v1';
function cvcCall(string $method, array $params = []): array
{
$keyId = getenv('CVC_API_KEY_ID');
$secret = getenv('CVC_API_SECRET');
$path = '/v1/' . $method;
$body = $params === [] ? '' : json_encode($params, JSON_UNESCAPED_SLASHES);
$t = time();
$v1 = hash_hmac('sha256', $t . '.POST.' . $path . '.' . $body, $secret);
$curl = curl_init(CVC_API . '/' . $method);
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-CVC-Key: ' . $keyId,
'X-CVC-Signature: t=' . $t . ',v1=' . $v1,
],
]);
$response = json_decode((string) curl_exec($curl), true);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
if ($status !== 200) {
throw new RuntimeException($status . ' ' . ($response['error']['code'] ?? '') . ' ' . ($response['error']['message'] ?? ''));
}
return $response;
}
$balances = cvcCall('getbalance/DOGE');
$plan = cvcCall('preparetx/DOGE', [
'to' => [['address' => 'D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD', 'amount' => '100']],
]);
// Проверьте план: получатели, network_fee, service_fee_usd — и подтвердите его.
$confirm = hash_hmac('sha256', getenv('CVC_API_KEY_ID') . '.' . $plan['fingerprint'] . '.'
. $plan['prepare_confirm'] . '.' . $plan['prepare_time'], getenv('CVC_API_SECRET'));
$task = cvcCall('posttx', ['prepare_id' => $plan['prepare_id'], 'confirm' => $confirm]);
// Итог — вебхук task.done или опрос task/{TASK_ID}.
$task = cvcCall('task/' . $task['task_id']);Приём вебхука:
<?php
$secret = getenv('CVC_API_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$t = null;
$signatures = [];
foreach (explode(',', $_SERVER['HTTP_X_CVC_SIGNATURE'] ?? '') as $pair) {
[$name, $value] = array_pad(explode('=', trim($pair), 2), 2, '');
if ($name === 't') {
$t = $value;
} elseif ($name === 'v1') {
$signatures[] = strtolower($value);
}
}
$expected = hash_hmac('sha256', $t . '.' . $body, $secret);
$valid = $t !== null && ctype_digit($t) && abs(time() - (int) $t) <= 300
&& array_filter($signatures, fn (string $v1): bool => hash_equals($expected, $v1)) !== [];
if (!$valid) {
http_response_code(400);
exit;
}
$hook = json_decode($body, true);
if (!$events->remember($hook['event_id'])) {
http_response_code(200);
exit;
}
switch ($hook['event']) {
case 'tx.new':
case 'tx.confirmed':
case 'tx.dropped':
$ledger->apply($hook['transaction']);
break;
case 'task.done':
$payouts->finish($hook['task']['task_id'], $hook['task']['task_info'], $hook['task']['txid']);
break;
case 'paybalance.low':
$alerts->notify($hook['reason'], $hook['paybalance']['usd']);
break;
}
http_response_code(200);Расшифровка privkey из getnewaddress:
<?php
$raw = base64_decode($response['privkey']);
$key = hash_hmac('sha256', 'privkey', getenv('CVC_API_SECRET'), true);
$privkey = openssl_decrypt(substr($raw, 12, -16), 'aes-256-gcm', $key, OPENSSL_RAW_DATA,
substr($raw, 0, 12), substr($raw, -16));Пример упрощён: при 429 и 503 повторяйте запрос с паузой, ошибки разбирайте по коду.