REST API / v1
Build something
without borders.
Create an invoice from your server, redirect the customer to the checkout URL, and listen for the webhook.
https://api.coinavio.com/v1Authentication
Create an API key in Dashboard → Developers. Send it as a bearer token. Keep it on your server; never expose it in a browser.
Authorization: Bearer gw_xxxxxxxxxxxxxxxxxxxx.<secret>
1. Create an invoice
Prices are always in USD. The customer chooses the coin and network on the checkout page.
POST https://api.coinavio.com/v1/invoices
Content-Type: application/json
Authorization: Bearer <apiKey>
{
"priceAmount": "49.99",
"orderId": "order-1001",
"description": "Pro plan, 1 year",
"successUrl": "https://shop.example.com/thanks?order=1001",
"cancelUrl": "https://shop.example.com/cart",
"metadata": { "customerId": "c_42" }
}
→ 201
{
"id": "inv_...",
"status": "NEW",
"price": { "amount": "49.99", "currency": "USD" },
"checkoutUrl": "https://pay.example.com/pay/inv_...",
"expiresAt": "2026-01-01T12:30:00.000Z",
...
}Redirect the customer to checkoutUrl. Sending the same orderId twice returns the same invoice.
2. Read an invoice
GET https://api.coinavio.com/v1/invoices/{id}
GET https://api.coinavio.com/v1/invoices?status=PAID&limit=20&cursor=<lastId>Statuses: NEW → PENDING → CONFIRMING → PAID | OVERPAID | UNDERPAID | EXPIRED | CANCELLED. Treat PAID and OVERPAID as success. UNDERPAID means the customer sent less than required after the deadline; the received amount is still credited to your balance.
3. Webhooks
Set your endpoint in Dashboard → Developers. We POST a JSON event and retry with exponential backoff for about two hours until you return a 2xx.
POST https://shop.example.com/webhooks/paygate
X-Webhook-Id: evt_...
X-Webhook-Timestamp: 1735732800000
X-Webhook-Signature: t=1735732800000,v1=<hex hmac>
{
"id": "evt_...",
"type": "invoice.paid",
"createdAt": "...",
"data": { "invoice": { ...same shape as GET /v1/invoices/{id} } }
}Event types: invoice.pending, invoice.confirming, invoice.paid, invoice.overpaid, invoice.underpaid, invoice.expired, invoice.payment_confirmed, withdrawal.completed, withdrawal.failed, withdrawal.rejected.
Verifying the signature (Node.js)
import { createHmac, timingSafeEqual } from "crypto";
export function verify(secret, header, rawBody) {
if (typeof header !== "string") return false;
const parts = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
if (!parts.t || !parts.v1 || !Number.isFinite(Number(parts.t))) return false;
if (Math.abs(Date.now() - Number(parts.t)) > 5 * 60_000) return false;
const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
return expected.length === parts.v1.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}Always verify against the raw request body, and make your handler idempotent on the event id.
Supported assets
GET https://api.coinavio.com/v1/assets (public)
USDT is available on Ethereum, BNB Chain, TRON and TON. Native ETH, BNB, TRX and TON are also supported. Always use the selected network when sending a payment.