reference
API Checkout Reference
API Checkout Reference
This is the engineering and user-facing documentation for the Merchant API QR Code Checkout flow. It allows merchants to create cryptocurrency payment orders and receive signed webhooks upon completion, without requiring customers to authenticate with Daxchain.
Endpoints
Orders are rows in payment_intents with kind = 'order' — the standalone api_orders table was merged into the unified intent model (see unified-intents).
- Create Order:
POST /api/v1/payments/orders - Fetch Order:
GET /api/v1/payments/uuid/{id} - Fetch by order id:
GET /api/v1/payments/order/{id}
Access is gated by the orders_enabled feature flag on the merchant.
Authentication
Both endpoints accept API keys provisioned via the merchant configuration surface at /my/orders/config (the merchant-facing console lives at /api-orders).
- Bearer Token:
Authorization: Bearer <api-key> - Custom Header:
x-api-key: <api-key>
Order Lifecycle
An order intent transitions through the following payment_intent_status values:
pending: Order minted. A dedicated deposit address (Fireblocks sub-vault) is allocated and monitoring begins.detected: An inbound transaction has been seen on-chain but has not yet met the required confirmation threshold.confirmed: The payer delivered exactly the expected crypto amount (within tolerance).underpaid: The payer delivered less than expected. The actual amount is credited; merchant reconciliation required.overpaid: The payer delivered more than expected. The actual amount is credited.expired: The TTL was reached before any funds were detected. The address is no longer monitored.void: Manually cancelled by the merchant or an admin.
⚠️ This page previously listed a
holdstate. There is noholdvalue in thepayment_intent_statusenum — the enum isdraft,pending,detected,confirmed,underpaid,overpaid,due,expired,void. Note also thatdue(used by invoices) is absent from the list above.
Webhooks and Signatures
Once an order reaches a terminal paid state (confirmed, underpaid, overpaid, or expired), Daxchain POSTs a webhook payload to the merchant's configured callback_url.
Signature Verification
Signatures are delivered in the HTTP headers, not the payload body, aligning with standard ecosystem practices (e.g., Stripe, GitHub).
content-type: application/json
x-daxchain-event: payment.confirmed
x-daxchain-signature: sha256=<hex-signature>
The signature is an HMAC-SHA256 hash computed over the raw bytes of the request body. Merchants must compute it on their side using their configured webhook_secret and perform a constant-time comparison.
signature = "sha256=" + hmac_sha256(webhook_secret, raw_request_body)
Payload Schemas
Current (Minimal) Shape
Note: This matches the current implementation in worker/jobs/webhook.ts and the dev simulator.
{
"event": "payment.confirmed",
"order_id": "ORD-1001", // Merchant-supplied order reference
"session_id": "uuid", // Daxchain internal row UUID
"amount": 100, // EUR major units
"currency": "EUR",
"crypto_amount": "161290000", // Minor units, decimal-string (BigInt-safe)
"asset": "BTC",
"txn_id": "0x…",
"blockchain_txid": "0x…",
"confirmation_status": "confirmed",
"timestamp": "2026-05-03T12:34:56Z",
}
Planned (Extended) Shape Note: The system will transition to this shape to provide explicit over/under metrics natively in the payload.
{
"event": "payment.underpaid", // .confirmed / .underpaid / .overpaid / .expired
"order_id": "ORD-1001",
"session_id": "uuid",
"merchant_user_id": "uuid",
"amount_eur": 100.0,
"neto_eur": 99.5, // amount - platform fee
"currency": "EUR",
"crypto_amount_expected": "0.00161290", // major units, decimal-string
"crypto_amount_paid": "0.00150000", // actual on-chain delivery
"delta_minor": "-11290", // paid - expected, signed; minor units
"crypto_neto": "0.00149005",
"asset": "BTC",
"network": "BTC",
"deposit_address": "bc1q…",
"tx_hash": "0x…",
"confirmations": { "current": 6, "required": 3 },
"status": "underpaid",
"timestamp": "2026-05-03T12:34:56Z",
}