Invoices & lifecycle
The eight invoice states, the allowed transitions, and how each maps to a webhook event.
An invoice is a request to receive a specific fiat amount, paid as a specific crypto amount on a specific network, within a time-to-live window. It is the core unit of work on the platform.
The eight states#
Non-terminal states#
- CREATED — invoice exists; no deposit yet.
- PENDING — deposit seen in the mempool or earliest block; below confirmation target.
- CONFIRMING — confirmations accumulating.
- UNDERPAID — confirmed but below requested amount. Non-terminal because the buyer may top up on many chains.
Terminal states#
- CONFIRMED — paid, confirmed, amount matches. Fulfil the order.
- EXPIRED — TTL elapsed without a confirming payment. Do not fulfil.
- OVERPAID — paid more than requested. Fulfil; handle surplus off-platform.
- LATE_PAYMENT — payment confirmed after expiry. Exceptional; reconcile manually.
Transitions trigger webhooks#
Every transition above emits a webhook with the event type matching the new state (lowercase, dot-prefixed). See the canonical table in Event types.
Timestamps on every invoice#
created_at— when the platform accepted the create request.expires_at—created_at + ttl_minutes. Default TTL is 30 min.confirmed_at— set only when the invoice reaches CONFIRMED or OVERPAID.
What you control#
- TTL — on invoice create (
ttl_minutes). Shorter is tighter UX but more expiries. - Deposit address — derived by the platform from the merchant's HD wallet; you never choose it.
- Exchange rate — locked at create time from the configured rate source. Buyers benefit from a stable fiat → crypto conversion for the duration of the invoice.
What the platform controls#
- Confirmation target per network — e.g. 2 for Bitcoin, 12 for Ethereum. See Payments & confirmations.
- State machine enforcement — invalid transitions are rejected server-side.
- Webhook delivery — one dispatch per transition, retried automatically with backoff. See Delivery semantics.