Payload schema
The exact JSON body every webhook delivery carries — rendered from the canonical payload snapshot.
Every webhook delivery carries the same JSON payload, regardless of event type. The event type is in the status field and is also mirrored in the X-Webhook-Event header.
Fields#
| Field | Type | Description | Example |
|---|---|---|---|
| invoice_id | string (UUID) | Primary identifier of the invoice. | a1b2c3d4-… |
| merchant_id | string (UUID) | Merchant that owns the invoice. | 11111111-… |
| external_id | string | null | Merchant-supplied idempotency key. | order-2026-0117-001 |
| description | string | null | Free-form description copied from the create-invoice request. | Order #1234 |
| metadata | object | null | Arbitrary JSON metadata from the create-invoice request. Use this to reconcile with your own records. | {"order_id":"1234","sku":"ABC"} |
| status | string (enum) | Current invoice status. See event types table for the state machine. | confirmed |
| fiat_amount | string (decimal) | Requested fiat amount as a fixed-decimal string. | 49.99 |
| fiat_currency | string (ISO 4217) | Fiat currency code, uppercase. | USD |
| crypto_amount | string (decimal) | Computed crypto amount at invoice-create time, rounded to the currency's payment precision. | 0.00082145 |
| crypto_currency | string | Cryptocurrency code, uppercase. | BTC |
| crypto_network | string | Network name, lowercase. | bitcoin |
| deposit_address | string | Address the buyer must fund. | bc1q… |
| exchange_rate | string (decimal) | Crypto per one fiat unit at invoice-create time. | 0.0000164 |
| created_at | string (ISO 8601) | null | Invoice creation timestamp (UTC). | 2026-04-17T12:00:00Z |
| expires_at | string (ISO 8601) | null | Invoice expiry timestamp (UTC). | 2026-04-17T12:30:00Z |
| confirmed_at | string (ISO 8601) | null | Confirmation timestamp if the invoice reached a terminal paid state. | 2026-04-17T12:14:03Z |
Example#
{
"invoice_id": "3f1a9b0e-2c7b-4a1c-9d2a-1f0e8a7b6c5d",
"merchant_id": "11111111-2222-3333-4444-555555555555",
"external_id": "order-2026-0117-001",
"description": "Order #1234 — 2 t-shirts",
"metadata": { "order_id": "1234", "sku": "ABC" },
"status": "confirmed",
"fiat_amount": "49.99",
"fiat_currency": "USD",
"crypto_amount": "0.00082145",
"crypto_currency": "BTC",
"crypto_network": "bitcoin",
"deposit_address": "bc1qx0...",
"exchange_rate": "0.0000164",
"created_at": "2026-04-17T12:00:00Z",
"expires_at": "2026-04-17T12:30:00Z",
"confirmed_at": "2026-04-17T12:14:03Z"
}
Merchant-supplied fields#
Three fields are passthrough from your original POST /api/invoices request:
external_id— use this for idempotency on your side. If you create an invoice twice with the sameexternal_id, you get the same invoice back.description— free-form; show to operators.metadata— arbitrary JSON. Put your internal order ID, customer reference, SKU, whatever you need for reconciliation. See Reconcile with metadata.
These fields make the webhook self-contained: a receiver can reconcile against its own records without a second round-trip to the platform.
Headers#
Every delivery carries:
Content-Type: application/jsonX-Webhook-ID— UUID per delivery attempt (stable across retries of the same event).X-Webhook-Timestamp— Unix epoch seconds at dispatch.X-Webhook-Signature—sha256=<hex>HMAC. See Signature scheme.X-Webhook-Event— the event type string (e.g.invoice.confirmed).
Stability#
The payload schema is versioned. Adding a field is a backward-compatible change and does not bump the major version. Removing or renaming a field will always bump the major version and be announced in the changelog with a deprecation window.