API documentation
The API gives your application server what the account does: the coin directory and rates, address balances and history, new addresses, fee calculation and sending transfers, notifications about incoming funds.
Contents
API address: https://api.coinvertus.net/v1
General rules
- A call is a POST to the API address with the call name, for example /v1/assets. {COIN} in the path is a ticker or coin ID from assets, {TASK_ID} is the task_id of a task.
- The body is a JSON object of at most 64 KB; a call without parameters may have no body. A successful response is the object or list itself, without a wrapper.
- Amounts are strings with a dot, in coin units, without trailing zeros. Time is an ISO 8601 string in UTC, for example 2026-10-04T12:00:00Z.
- network is the network code from assets. It is required when the coin exists in several networks (otherwise 400 A014).
- The error text uses the language from Accept-Language (Russian, English, Chinese); base your decisions on the error code.
| Call | Key right | Description |
|---|---|---|
POST /v1/assets | no key, if the call is open to guests | API coins and networks and what they support. |
POST /v1/rates | no key, if the call is open to guests | Coin and token rates, page by page. |
POST /v1/rate/{COIN} | no key, if the call is open to guests | Rate of one coin. |
POST /v1/checkaddress/{COIN} | no key, if the call is open to guests | Address check; with a key, whether it is yours. |
POST /v1/paybalance | read | Payment balance in USD. |
POST /v1/getbalance[/{COIN}] | read | Balances by coin and network. |
POST /v1/addresses/{COIN} | read | Issued addresses of a coin. |
POST /v1/txinfo/{COIN} | read | A transaction of your addresses by txid. |
POST /v1/transactions/{COIN} | read | History of your addresses. |
POST /v1/getnewaddress/{COIN} | addresses | A new address or a new tag. |
POST /v1/getfee/{COIN} | send | Network fee and service fee. |
POST /v1/spendinfo/{COIN} | send | Which addresses the funds will come from. |
POST /v1/preparetx/{COIN} | send | Send plan. |
POST /v1/posttx | send | Confirm the plan and queue the task. |
POST /v1/task/{TASK_ID} | send | State of a send task. |
POST /v1/task/{TASK_ID}/cancel | send | Cancel a queued task. |
Getting started
- Connect an authenticator app or verify your email in your account: API keys are created and changed only with a confirmation code.
- In “API keys”, create a key (up to 10 per account): tick its rights and list the IP addresses or subnets of your server — a request from any other address gets 403 A005.
- Save the key ID (ak_…) and the secret: the secret is shown once. Lost it — reissue it on the key page.
- For notifications, set the webhook address in “Webhooks” and save its secret (whsec_…).
- Before sending, top up the payment balance: the service fee is charged from it.
| Key right | Description |
|---|---|
read | Balances, addresses, transaction history, payment balance. |
addresses | Issuing new addresses. |
keys | Private keys of new addresses (priv in getnewaddress), together with the addresses right. |
send | Fee calculation, preparing and sending transfers, tasks. |
Request signature
A request with a key carries two headers. v1 is the hexadecimal HMAC-SHA256 of the string “t.POST.path.body” keyed with the API key secret. The path is as in the request address, starting with /v1/ (with the query string, if any); the body is exactly the bytes you send, an empty string for an empty body. t is Unix time in seconds: a signature that differs from the server clock by more than 5 minutes is rejected.
| Header | Description |
|---|---|
X-CVC-Key | Key ID: ak_ followed by 24 hexadecimal characters. |
X-CVC-Signature | Signature: t=<Unix time>,v1=<signature>. |
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>CVC may open the reference calls (assets, rates, rate, checkaddress) without a key: such a request goes without both headers and is limited by IP address. If the call is closed to guests — 401 A004.
Responses and errors
A refusal is an HTTP code and an error body: code is the error code, message is the text, fields lists the request fields that failed validation (when known).
{
"error": {
"code": "A014",
"message": "Specify network: the coin exists on several networks.",
"fields": [
"network"
]
}
}A request to the API address without a call returns 200 and {"status":"OK","version":"…"} with the application version; use it as an availability check. An unknown call returns 404 and {"status":"error","code":404}.
| HTTP status | Error code | Meaning |
|---|---|---|
400 | A002 | Invalid request: the body must be a JSON object up to 64 KB with valid fields. |
401 | A003 | The key or request signature failed verification. |
401 | A004 | This call requires an API key. |
403 | A005 | The request came from an address outside the key's IP allowlist. |
403 | A006 | The key lacks the right this call needs. |
403 | A007 | This call is not available on your plan. |
404 | 404 | No such call: the body is {"status":"error","code":404}, without the error field. |
503 | A009 | The call is disabled, the network or node is unavailable right now, or the address is busy with a previous transfer. Retry later. |
429 | A010 | Request limit exceeded. Retry after as many seconds as the Retry-After header says. |
500 | A011 | Internal error. Please retry later. |
405 | A012 | Use the POST method. |
404 | A013 | Coin not found. |
400 | A014 | Specify network: the coin exists on several networks. |
404 | A015 | Transaction not found. |
403 | A016 | The quota of addresses issued through the API in this network is used up. |
409 | A018 | Not enough funds for the amount and the network fee. |
422 | A019 | Fee calculation and sending of this coin via the API are not supported yet. |
409 | A020 | The payment balance does not cover the service fee. Top up the balance. |
404, 409 | A021 | The send plan was not found, has expired or is outdated. Prepare the transfer again. |
404 | A022 | Task not found. |
409 | A024 | The task can no longer be cancelled: only a queued task can be cancelled. |
Limits
Each call has its own limit of requests per second (1 by default) and, per your plan, per minute and per month; on top of that, the account ceiling from the plan applies. A month is a calendar month in UTC. When exceeded — 429 A010 with a Retry-After header. Guests are limited by IP address (IPv6 by /64 network). Calls that reach a network node (getfee, spendinfo, preparetx, plus checkaddress and getnewaddress for Monero and Zcash) are additionally limited on some networks: one key at most once every few seconds per network, and a per-minute ceiling on such calls for the whole network. The refusal is the same 429 A010 with Retry-After.
Reference calls
assets
The list of “coin × network” pairs the API serves, with what they support. Pairs change rarely — you can keep the directory on your side and refresh it daily.
[
{
"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"
]
}
]| Field | Description |
|---|---|
coin | Coin or token ticker — you can pass it as {COIN}. |
network, network_name, testnet | Network code for network, its name and the testnet flag. |
type, contract | coin is the network coin, token is a token with its contract address in contract. |
decimals | Digits after the dot in amounts. |
formats | Address formats you can request in getnewaddress. |
confirmations | How many confirmations make a transaction confirmed. |
can_send | The pair can be sent through the API: getfee, preparetx, posttx. |
multi_recipient | One transaction can have several recipients. |
tag | The recipient may need a destination tag — to[].tag. |
fee_levels | Fee levels that getfee returns and preparetx accepts in fee: UTXO networks with block-target estimates have fast, normal and low, all others only normal; an empty list means no sending. |
min_amount | Reserved: min_amount is null for now. |
rates, rate/{COIN}
Rates of catalog coins and tokens in USD, EUR, RUB, CNY and INR, 100 per page (page from 1; an empty page ends the list). coins is an optional list of tickers or IDs, up to 100. No rate — null, updated_at is the rate time. rate/{COIN} returns one such item.
{
"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}
Checks an address in the pair network. Request: address, network. Response: valid, address (canonical form), coin, network, format. With a key that has the read right — also is_mine (the address was issued to your account) and balance (its confirmed balance); without a key and for an address of another account — null.
Balances and history
paybalance
The payment balance the service fee is charged from: usd is available, reserved is held in withdrawal requests and in fees of unfinished tasks; auto_topup, threshold, topup_amount are the auto top-up settings (no threshold — false and null).
getbalance[/{COIN}]
Without {COIN} — the pairs where you have addresses; with {COIN} — all networks of the coin, or one if network is given. balance is confirmed, pending is incoming without confirmations, available can be sent now, fiat is balance in five currencies, addresses is the address count, stale means the data may lag behind the network.
[
{
"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}
Issued addresses of the pair in issue order, 100 per page (page): address, format, label, balance, pending, created_at. For a token — the addresses of its network with the token balance.
txinfo/{COIN}, transactions/{COIN}
txinfo is a transaction of your addresses by txid (as the network explorer shows it). A transaction dropped from the mempool is deleted by the monitor: it returns 404 A015, and the tx.dropped webhook reports it.
transactions is the history of your addresses in the pair, 100 per page, newest first, unconfirmed on top. Filters: address — one of your addresses, from and to — transaction time inclusive. New transactions shift the pages — a from/to window is better for reconciliation.
{
"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"
}| Field | Description |
|---|---|
direction | in is incoming, out is from your addresses. |
status | new waits for confirmations, confirmed has at least the pair confirmations, failed means the network rejected the transaction and charged the network fee. |
block, confirmations, time | Block, confirmations and transaction time; while the transaction is in the mempool, block and time are null. |
transfers | Movements on your addresses summed by address and direction. For UTXO, spending is whole inputs and change is a separate in line. tag is the destination tag of an incoming transfer. |
fee, fee_coin | Network fee of an outgoing transaction and its coin (for a token — the network coin). |
Issuing addresses
getnewaddress/{COIN} issues a new address in the pair network. Request: network, format (one of the pair formats), label (up to 190 characters), priv. In a network with destination tags the account has one address — the call issues a new tag for it. CVC sets the quota of addresses issued through the API per account in a network — beyond it, 403 A016.
{
"coin": "DOGE",
"network": "dogecoin-mainnet",
"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD",
"format": "base58",
"tag": null,
"privkey": null
}priv: true (needs the keys right) adds privkey to the response: the private key encrypted with AES-256-GCM. The encryption key is HMAC-SHA256(API key secret, “privkey”) as raw bytes, the value is base64(12-byte nonce ‖ ciphertext ‖ 16-byte tag). In networks where the key belongs to the node wallet, privkey is always null.
Sending: the flow
- getfee — network fee at the fast, normal, low levels and the service fee; spendinfo — which addresses the funds will come from.
- preparetx — the transfer plan: sources, recipients, fee, steps. The plan reserves nothing and lives 5 minutes (expires_at).
- Check the plan and confirm it: posttx with prepare_id and confirm = HMAC-SHA256(key secret, “key_id.fingerprint.prepare_confirm.prepare_time”), where key_id is the ID of the key that prepared the plan.
- posttx queues the task and charges the service fee; the queue sends the transfer within seconds. The outcome — task/{TASK_ID} or the task.done webhook.
| Field | Description |
|---|---|
to | Recipients: address and amount; tag is a destination tag, comment is a text for the recipient up to 120 characters where the network supports it. Several recipients (up to 100) only for pairs with multi_recipient; with send_all — one recipient without amount. |
from | Your source addresses (address); without from, addresses are picked automatically. In account-based networks — one address. |
order | Source selection order: desc (default) — larger addresses first, asc — smaller first. |
fee | preparetx: fast, normal (default) or low; in UTXO networks also a numeric rate in fee_rate_unit. In account-based networks only normal; for tokens that pay for energy also rent or burn. |
change | preparetx, UTXO networks: where change goes — auto (default, the address of the largest input), new (a new address) or your own address in this network. |
send_all | preparetx: true sends everything from the sources minus the fee. |
getfee and spendinfo
getfee takes the same to, from, order. fee_coin is the network fee coin (for a token — the network coin); fast, normal, low are amount plus five currencies, or null when the network has no such level or the amount with the fee does not fit at it (fits nowhere — 409 A018); service_fee_usd is the service fee; extra lists additional costs.
{
"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 | Meaning |
|---|---|
gas | The token address lacks the network coin: amount will come to it from another of your addresses, network_fee is the fee of that transfer. |
rent | Without provider — creating the recipient token account, if it does not exist yet. |
burn, rent | With provider — ways to pay for token energy: burning (burn) or renting (rent); selected marks the way fee normal will choose. |
spendinfo takes to and order. sources are funded addresses in order: address, balance (available), locked (busy with an unfinished transfer), use — how much sending will take from it; enough tells whether it is sufficient. For a token use is the token amount; getfee and preparetx check the fee.
preparetx: the send plan
Request: network, to, from, order, fee, change, send_all. Response: the plan and the data to confirm it in posttx. Not enough payment balance for the service fee — 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"
}| Field | Description |
|---|---|
tx.sources | Source addresses and how much leaves each one, network fee included. |
tx.recipients | Recipients and amounts; in networks with a tag or comment — tag and comment. |
tx.change | UTXO change: address and amount; no change — null. |
tx.network_fee, tx.fee_coin | Network fee and its coin. |
tx.fee_rate, tx.fee_rate_unit, tx.size, tx.replaceable | UTXO networks: rate and its unit, transaction size, whether it can be replaced by a transaction with a higher fee. |
tx.fee_payer, tx.rent | Tokens whose fee is paid by another of your addresses in the same transaction: that address and the charge for creating the recipient account. |
steps | Execution steps: gas — topping up gas first (from, to, amount, network_fee), rent — renting energy (provider, energy, cost), send — the transfer itself. |
expires_at, fingerprint | Plan expiry and fingerprint: the plan can be confirmed only before expires_at. |
posttx and the task
posttx takes prepare_id and confirm and returns the task object. Repeating it with the same prepare_id returns the same task, even after the plan expires, so posttx is safe to retry after a lost connection. A plan of another key or account — 404 A021, expired — 409 A021, wrong confirm — 400 A002. task/{TASK_ID} returns the same object.
{
"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 | Meaning |
|---|---|
queue | Queued; the task can be cancelled. |
processing | Being sent. |
gas | Waiting for the token gas top-up to confirm. |
rent | Waiting for the energy rental. |
sent | In the network, waiting for confirmations. |
unknown | The send outcome is unknown: the node did not answer. Do not repeat the transfer — reconciliation will settle it and the task will move on by itself. |
confirmed | Confirmed. |
failed | Not done — the reason is in error_code. |
dropped | The transaction dropped from the network without confirmations. |
cancelled | Cancelled by the client. |
| Field | Description |
|---|---|
task_start, task_sent, task_done | Queue time, send time and final status time; not yet — null. |
txid, gas_txid, confirmations | Transfer transaction, gas top-up transaction and confirmations; before sending — null. |
error_code | Reason code if the task was not done; otherwise null. |
tx, service_fee_usd | The plan from preparetx and the service fee charged for the task. |
error_code | Meaning |
|---|---|
A009 | The network or node was unavailable for more than 30 minutes, or the send outcome is unknown. |
A018 | By the time of sending, the address lacked funds. |
A021 | The plan is outdated (balance, fee or address changed after preparetx) or the account is blocked. |
A023 | The network rejected the transaction; the network fee was charged. |
A025 | The energy rental failed. |
task/{TASK_ID}/cancel cancels a task in queue — before the first attempt and between retries; once gas is sent or a rental is ordered, it cannot be cancelled. Later — 409 A024. Repeating it for a cancelled task returns that task.
Network specifics
- UTXO networks: several recipients, fast, normal, low levels or your own rate, change via change; sources are inputs from your addresses.
- Account-based networks: one source address and one recipient, only normal. An address with an unfinished transfer is busy until it confirms — the task waits up to 30 minutes.
- Networks with destination tags (tag in assets): to[].tag goes to the recipient; incoming transfers to your address differ by tag in transfers, and getnewaddress issues a new tag for the same address.
- A network with transfer comments: to[].comment is a text up to 120 characters; other networks reject the field (400 A002).
- Tokens: the fee is paid in the network coin from the same address. If it is short, the plan starts with a gas step: a top-up from your largest free address in the network, and the token leaves after it confirms.
- Tokens that pay for energy: fee normal rents from the cheapest connected provider, otherwise burns; rent or burn chooses manually. A failed rental — failed A025. Providers are connected in account settings, the “Helpers” tab.
- Tokens whose fee and recipient account creation are paid in the same transaction by your address with the most network coin: tx has fee_payer and rent, there is no gas step.
- Private networks: sending from one address, getfee is an upper estimate, the exact fee is in preparetx, privkey is unavailable; sending through the node wallet takes up to a few minutes.
Service fee and payment balance
The service fee follows your plan: a percent of the USD amount with a minimum and maximum; getfee and preparetx show it (service_fee_usd). It is charged from the payment balance on posttx and returned if the transfer did not reach the network, dropped or the task was cancelled. A confirmed transfer and one rejected by the network (failed A023) do not return it.
To keep sending from stalling on the balance, turn on auto top-up in your account (Payment balance → Auto top-up); the paybalance.low webhook warns when the balance falls below the threshold.
Webhooks
The webhook address is set in the account, the “Webhooks” section: an https address, with IP and Host if needed. The whsec_… secret is shown once; the check button sends ping. Webhooks are available on plans that include them.
A notification is a POST with a JSON body. Any 2xx response within 10 seconds is a success. Otherwise we retry after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 24 hours. Redirects are not followed; at most 64 KB of the response is read.
| Header | Description |
|---|---|
X-CVC-Event | Event name, same as event in the body. |
X-CVC-Delivery | event_id and attempt number. |
X-CVC-Signature | Signature: t=<Unix time>,v1=<signature>. |
v1 is the hexadecimal HMAC-SHA256 of the string “t.body” keyed with the webhook secret (whsec_…). Take the body exactly as the received bytes, before parsing JSON, and reject the notification if t differs from your clock by more than 5 minutes.
The same notification may arrive twice — handle each event_id once. Delivery order is not guaranteed: do not roll back a paid order because of an earlier notification.
| Event | When it is sent |
|---|---|
tx.new | A new transaction of your addresses. In networks without mempool watching it comes with the first confirmation. |
tx.confirmed | The transaction was confirmed or rejected by the network — see status. |
tx.dropped | A transaction reported by tx.new dropped from the network without confirmations. |
task.done | A send task reached a final status: confirmed, failed, dropped or cancelled. |
paybalance.low | The payment balance is below the auto top-up threshold: auto top-up is off (reason no_autotopup) or failed (autotopup_failed). |
ping | Test notification from your account. |
Transactions that happened before the webhook was turned on are not sent. The tx.* body carries the transaction object as in txinfo; task.done carries the task object; paybalance.low carries reason and the paybalance object.
{
"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 example
A signed call, a send plan and its confirmation:
<?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']);Receiving a webhook:
<?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);Decrypting privkey from 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));The example is simplified: on 429 and 503 retry with a pause, handle errors by code.