Use cases and examples

CoinVertus API in practice: accepting payments, a wallet in your service, network analytics and a PHP client.

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.