Invoice lifecycle
Statuses, timers, and what each signal means for fulfillment.
An invoice is created via POST /v1/invoices. The customer pays on hosted checkout (checkoutUrl). You learn about progress from webhooks and optional status polling.
Happy path
CREATED → CONFIRMING → PAID → SETTLED- You create the invoice → customer opens checkout and picks chain/token
- Transfer detected →
CONFIRMING/invoice.payment_detected - Chain finality within the checkout window →
PAID/invoice.paid(fulfill here) - Platform sweep completes →
SETTLED/invoice.settled(accounting)
Statuses
| Status | Meaning |
|---|---|
CREATED | Waiting for payment |
CONFIRMING | Transfer seen; waiting for finality |
PAID | Paid in time — safe to fulfill |
UNDERPAID | Partial payment; top-up window open |
EXPIRED_UNDERPAID | Top-up window ended still short |
LATE_PAID | Paid after the 1h window — funds accepted, not standard fulfillment |
OVERPAID | Amount above required (ops review; no auto-sweep in Phase 1) |
SETTLED | Sweep done; fee split applied |
EXPIRED | No payment before the 1h window ended |
Timers
| Timer | Duration | Starts |
|---|---|---|
| Checkout window | 1 hour | Invoice creation |
| Underpaid top-up | 30 minutes | First partial payment |
There is no separate grace setting. Payment that finalizes after the 1h window becomes LATE_PAID, not PAID.
What to fulfill on
| Signal | Fulfill goods? |
|---|---|
invoice.paid / status PAID | Yes |
invoice.late_paid / LATE_PAID | No (unless you explicitly opt in) |
invoice.settled / SETTLED | Accounting only — money moved |
invoice.underpaid | Wait for top-up |
invoice.expired / invoice.expired_underpaid | Close the order |
Polling (optional)
Prefer webhooks. If you must poll:
curl http://api.localhost:4000/v1/invoices/<id>/status \
-H "Authorization: Bearer test_..."Returns status, amount, amountReceived, and expiresAt.
Full detail: Get invoice.
Amounts and checkout
- Amounts are decimal strings in major units (up to 6 decimal places).
"10.50"= 10.50 USDC/USDT. - Token/chain are chosen at checkout, unless the merchant locked them with
networkId/tokenon create — then checkout shows a fixed route. - Create/get responses include deposit
addresseswithchainNameand thetokensaccepted on each chain — only those tokens should be sent to that address. - Deposit addresses are pre-computed only for chains enabled for that invoice environment (
test→ local/testnets,live→ mainnets), optionally filtered by create constraints.
Reorgs
Rarely, a previously seen payment can be invalidated. You receive invoice.payment_invalidated. Do not fulfill solely on payment_detected — wait for invoice.paid.
Related
- Webhooks — events and signature verification
- Create invoice
- Authentication — test vs live