Документация 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/paybalancereadПлатёжный баланс в 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/posttxsendПодтверждение плана и постановка задачи.
POST /v1/task/{TASK_ID}sendСостояние задачи отправки.
POST /v1/task/{TASK_ID}/cancelsendОтмена задачи в очереди.

С чего начать

  1. Подключите в кабинете приложение-аутентификатор или подтвердите почту: ключи API создаются и меняются только с кодом подтверждения.
  2. В разделе «Ключи API» создайте ключ (до 10 на аккаунт): отметьте права и укажите белый список IP-адресов или подсетей вашего сервера — запрос с другого адреса получит 403 A005.
  3. Сохраните ID ключа (ak_…) и секрет: секрет показывается один раз. Потеряли — перевыпустите его на странице ключа.
  4. Для уведомлений укажите адрес вебхука в разделе «Вебхуки» и сохраните его секрет (whsec_…).
  5. Перед отправками пополните платёжный баланс: с него списывается комиссия сервиса.
Право ключаОписание
readБалансы, адреса, история транзакций, платёжный баланс.
addressesВыдача новых адресов.
keysПриватные ключи новых адресов (priv в getnewaddress) — вместе с правом addresses.
sendРасчёт комиссии, подготовка и отправка переводов, задачи.
Открыть ключи API

Подпись запроса

Запрос с ключом несёт два заголовка. v1 — HMAC-SHA256 в шестнадцатеричном виде от строки «t.POST.путь.тело», ключ — секрет ключа API. Путь — как в адресе запроса, начиная с /v1/ (со строкой запроса, если она есть); тело — ровно те байты, что вы отправляете, у пустого тела — пустая строка. t — время Unix в секундах: подпись, которая расходится с часами сервера больше чем на 5 минут, отклоняется.

ЗаголовокОписание
X-CVC-KeyID ключа: 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Код ошибкиЧто значит
400A002Неверный запрос: тело — JSON-объект до 64 КБ с полями нужного вида.
401A003Ключ или подпись запроса не прошли проверку.
401A004Для этого вызова нужен ключ API.
403A005Запрос пришёл с адреса не из белого списка ключа.
403A006У ключа нет права, которое нужно вызову.
403A007Вызов недоступен на вашем тарифе.
404404Такого вызова нет: тело ответа {"status":"error","code":404}, без поля error.
503A009Вызов выключен, сеть или нода сейчас недоступны либо адрес занят прошлым переводом. Повторите позже.
429A010Превышен лимит запросов. Повторите через столько секунд, сколько в заголовке Retry-After.
500A011Внутренняя ошибка. Повторите запрос позже.
405A012Используйте метод POST.
404A013Монета не найдена.
400A014Укажите network: монета есть в нескольких сетях.
404A015Транзакция не найдена.
403A016Исчерпана квота адресов, выданных через API, в этой сети.
409A018Не хватает средств на сумму и комиссию сети.
422A019Расчёт и отправка этой монеты через API пока не поддерживаются.
409A020Не хватает платёжного баланса на комиссию сервиса. Пополните баланс.
404, 409A021План отправки не найден, истёк или устарел. Подготовьте отправку заново.
404A022Задача не найдена.
409A024Задачу уже нельзя отменить: отменить можно только задачу в очереди.

Лимиты

У каждого вызова свой лимит запросов в секунду (по умолчанию — 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, contractcoin — монета сети, 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"
}
ПолеОписание
directionin — входящая, out — с ваших адресов.
statusnew — ждёт подтверждений, 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.

Приватный ключ даёт полный доступ к деньгам адреса: запрашивайте его, только если храните ключи сами и защищённо.

Отправка: порядок

  1. getfee — комиссия сети на уровнях fast, normal, low и комиссия сервиса; spendinfo — с каких адресов уйдут деньги.
  2. preparetx — план перевода: источники, получатели, комиссия, шаги. План ничего не резервирует и живёт 5 минут (expires_at).
  3. Проверьте план и подтвердите его: posttx с prepare_id и confirm = HMAC-SHA256(секрет ключа, «key_id.fingerprint.prepare_confirm.prepare_time»), где key_id — ID ключа, подготовившего план.
  4. posttx ставит задачу в очередь и списывает комиссию сервиса; очередь отправляет перевод в течение нескольких секунд. Итог — task/{TASK_ID} или вебхук task.done.
ПолеОписание
toПолучатели: address и amount; tag — тег назначения, comment — текст получателю до 120 символов, где сеть это поддерживает. Несколько получателей (до 100) — только у пар с multi_recipient; при send_all — один получатель без amount.
fromСвои адреса-источники (address); без from адреса подбираются сами. В сетях с аккаунтами — один адрес.
orderПорядок подбора источников: desc (по умолчанию) — сначала крупные адреса, asc — мелкие.
feepreparetx: fast, normal (по умолчанию) или low; в UTXO-сетях — ещё ставка числом в единицах fee_rate_unit. В сетях с аккаунтами — только normal; у токенов с оплатой энергии — ещё rent или burn.
changepreparetx, UTXO-сети: куда вернуть сдачу — auto (по умолчанию, адрес самого крупного входа), new (новый адрес) или свой адрес этой сети.
send_allpreparetx: 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.replaceableUTXO-сети: ставка и её единица, размер транзакции, можно ли заменить её транзакцией с большей комиссией.
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 КБ.

Уведомления приходят с разных адресов — не ограничивайте приём по IP, проверяйте подпись.
ЗаголовокОписание
X-CVC-EventСобытие, как event в теле.
X-CVC-Deliveryevent_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 повторяйте запрос с паузой, ошибки разбирайте по коду.