Use cases and examples
CoinVertus API in practice: accepting payments, a wallet in your service, network analytics and a PHP client.
Contents
API address: https://api.coinvertus.net/v1
Use cases
Three typical scenarios: accepting payments on your own, a wallet inside your service and network analytics. The examples show the order of calls; full fields are in the sections above.
As SCI: accepting payments
Each order gets its own address via getnewaddress with label = the order number. An incoming payment arrives as the tx.new webhook, the confirmation as tx.confirmed; close the order on confirmed. Without a webhook, reconcile with txinfo. A ready payment page with an invoice and statuses is the SCI interface.
# Order created: a dedicated address (right: addresses)
POST /v1/getnewaddress/DOGE {"network": "dogecoin-mainnet", "label": "order-1042"}
-> {"coin": "DOGE", "network": "dogecoin-mainnet", "address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD", ...}
# The buyer pays: webhook tx.new, then tx.confirmed
{"event": "tx.confirmed", "transaction": {"txid": "c0c0…", "direction": "in", "status": "confirmed",
"transfers": [{"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD", "amount": "250"}]}}
# No webhook received: reconcile (right: read)
POST /v1/txinfo/DOGE {"network": "dogecoin-mainnet", "txid": "c0c0…"}As a wallet: balances and sending
Balances — getbalance, history — transactions. A transfer: estimate with getfee, plan with preparetx, confirm with posttx and confirm, then track the task — task or the task.done webhook. The money has left only when the task is confirmed.
# Balances and history (right: read)
POST /v1/getbalance/DOGE {"network": "dogecoin-mainnet"}
POST /v1/transactions/DOGE {"network": "dogecoin-mainnet", "page": 1}
# Transfer (right: send)
POST /v1/getfee/DOGE {"network": "dogecoin-mainnet", "to": [{"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD", "amount": "100"}]}
POST /v1/preparetx/DOGE {"network": "dogecoin-mainnet", "to": [{"address": "D8vFz4p1L37jdg47HXKtSHA5uYLYxbGgPD", "amount": "100"}], "fee": "normal"}
-> {"prepare_id": "prep_…", "prepare_confirm": "…", "prepare_time": 1789647000, "fingerprint": "…", ...}
POST /v1/posttx {"prepare_id": "prep_…", "confirm": "hex(HMAC-SHA256(secret, key_id.fingerprint.prepare_confirm.prepare_time))"}
-> {"task_id": "task_…", "task_info": "queue", ...}
POST /v1/task/task_… {}
-> {"task_info": "confirmed", "txid": "b7b7…", ...} (or the task.done webhook)As analytics: network, blocks, addresses
Network and index state — chains, lastblock and info; data — blocks, block, tx and address in pages of 100, rates — rates. A key is optional for these calls when they are open to guests; with a key, your plan limits apply.
# Network and index state (key optional when open to guests)
GET /v1/chains
GET /v1/chains/dash/lastblock
GET /v1/chains/dash/info
# Blocks, transactions, addresses: pages of 100
GET /v1/chains/dash/blocks?page=1
GET /v1/chains/dash/block/2371204
GET /v1/chains/dash/tx/e7e7…
GET /v1/chains/dash/address/XcF5mKwWsiv3k394GBQNpYAuk3CVJ48Xnp?direction=in&page=2
# Rates
POST /v1/rates {"coins": ["DASH", "LTC"]}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.