Create an invoice via API
POST /api/invoices with idempotency, metadata, and the fields that actually matter.
Creating an invoice is a single POST. The fields that matter most on day one are fiat_amount, fiat_currency, crypto_currency, crypto_network, and external_id.
Request#
POST /api/invoices
Headers: Authorization: Bearer <api-key>, Content-Type: application/json.
{
"fiat_amount": "49.99",
"fiat_currency": "USD",
"crypto_currency": "BTC",
"crypto_network": "bitcoin",
"ttl_minutes": 30,
"external_id": "order-2026-0117-001",
"description": "Order #1234",
"metadata": { "order_id": "1234", "customer_id": "cust_42" },
"webhook_url": "https://example.com/webhooks/crypto-merchant"
}
Required fields#
fiat_amount— decimal string.fiat_currency— ISO 4217, uppercase (USD,EUR…).crypto_currency— uppercase (BTC,ETH,USDT…).crypto_network— lowercase (bitcoin,ethereum,tron…). See the currencies table.
Recommended fields#
external_id— your own unique identifier. Enables idempotency. Strongly recommended.description— shown to operators in the dashboard.metadata— any JSON you want echoed back in every webhook. See Reconcile with metadata.
Optional fields#
ttl_minutes— default 30. Minimum sensible value is 5; maximum 1440.webhook_url— overrides the merchant's default webhook URL for this one invoice. Most integrations leave this unset.
Samples#
cURL#
curl -X POST https://api.example.com/api/invoices \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fiat_amount": "49.99",
"fiat_currency": "USD",
"crypto_currency": "BTC",
"crypto_network": "bitcoin",
"external_id": "order-2026-0117-001",
"metadata": { "order_id": "1234" }
}'
TypeScript (fetch)#
type CreateInvoiceInput = {
fiat_amount: string;
fiat_currency: string;
crypto_currency: string;
crypto_network: string;
external_id?: string;
description?: string;
metadata?: Record<string, unknown>;
ttl_minutes?: number;
};
export async function createInvoice(input: CreateInvoiceInput, apiKey: string) {
const res = await fetch("https://api.example.com/api/invoices", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(input),
});
if (!res.ok) {
throw new Error(`invoice create failed: ${res.status} ${await res.text()}`);
}
return res.json();
}
Python (httpx)#
import httpx
def create_invoice(input: dict, api_key: str) -> dict:
with httpx.Client(timeout=10) as client:
r = client.post(
"https://api.example.com/api/invoices",
headers={"Authorization": f"Bearer {api_key}"},
json=input,
)
r.raise_for_status()
return r.json()
Response#
A 201 with the full invoice object (same shape as the webhook payload). Cache the invoice_id — you will use it for subsequent reads and reconciliation.
Errors#
400— validation failure. Body is a structured error object naming the offending field.401— missing or bad API key.422— currency/network combination not supported. See Payments & confirmations for the supported matrix.5xx— retry with exponential backoff; the request is not guaranteed idempotent unless you supplyexternal_id.
Next steps#
- Make your create call idempotent — Idempotency with external_id.
- Wire up the webhook handler — Consume webhooks.