Statuses & Lifecycles
Every state machine in one place: what each status means, which are terminal, and which webhook fires on each transition.
Status values are stable API contract, and the same vocabulary is used everywhere: in GET responses, in webhook payloads, and throughout these docs. Resources progress forward only. Nothing moves backwards through its chain.
This page is the single home for every state diagram. Concept pages link here rather than redrawing one.
Endorsement
The public KYC reading. See Verification & Endorsements.
| Status | Terminal | Meaning | Webhook on entry |
|---|---|---|---|
incomplete | no | Requested, but something it needs is outstanding. The missing bucket lists what you owe | none |
pending | no | Under review. Nothing is owed right now | none |
issues | no | Retryable ask. The buckets name it | endorsement.request_for_information |
approved | sticky | The currency's features are open | endorsement.approved |
rejected | yes | Final adverse decision | endorsement.rejected |
approved is sticky in the direction that matters: a scoped re-check or a
retryable ask never demotes an approved endorsement.
Verification round
One review attempt, listed at GET /api/customers/{id}/verifications.
| Status | Terminal | Meaning |
|---|---|---|
submitted | no | Sent for review |
under_review | no | Under review |
approved | yes | This round passed |
request_for_information | yes | This round asked for something. rejection_reasons names it |
rejected | yes | This round refused |
expired | yes | The round aged out |
Rounds carry no webhooks of their own. Decisions surface on the customer's endorsements, which is the reading to build on.
Customer
| Status | Terminal | Meaning |
|---|---|---|
pending | no | Created, not yet active |
active | no | Normal |
rejected | yes | Refused |
frozen | no | Every API call for this customer is refused |
Deposit
| Status | Terminal | Meaning | Webhook |
|---|---|---|---|
detected | no | The bank credit was seen | deposit.received |
confirmed | no | Funds confirmed on the rail | none |
orchestrating | no | Conversion in progress. Also where a deposit waits when corridor inventory is momentarily short | none |
completed | yes | Converted and delivered | none |
returned | yes | Sent back to the sender | deposit.returned |
failed | yes | Could not be processed. Contact support | none |
on_hold | no | Compliance hold, needs review before it proceeds | deposit.on_hold |
Conversion
| Status | Terminal | Meaning | Webhook |
|---|---|---|---|
created | no | Opened for a deposit | conversion.created |
routing | no | Route and rate being fixed | none |
executing | no | Executing the conversion | none |
settling | no | Delivery in flight | none |
completed | yes | Fees and FX settled, delivered_amount final | conversion.completed |
failed | yes | Execution failed. Funds are never lost mid-flight | none |
refunding | no | Reversal path back toward the sender | none |
refunded | yes | Reversal complete | none |
requires_attention | no | Parked for operator review | none |
Payout
| Status | Terminal | Meaning | Webhook |
|---|---|---|---|
created | no | Delivery prepared | none |
submitted | no | Broadcast on chain | none |
completed | yes | Confirmed. tx_hash is the proof | payout.completed |
failed | yes | Chain-level failure. Funds return to orchestration | none |
returned | yes | Delivery reversed | none |
Virtual account
| Status | Terminal | Meaning | Webhook |
|---|---|---|---|
pending | no | Provisioning at the banking rail | none |
active | no | Live. Deposit instructions are valid | virtual_account.activated |
frozen | no | Temporarily not accepting deposits | none |
closed | yes | Permanently closed | none |
Wallet
| Status | Terminal | Meaning |
|---|---|---|
active | no | Live: receives and sends |
frozen | no | Blocked from sending, still receives |
closed | yes | Permanently closed |
A send against a non-active wallet returns 400 wallet_not_active.
Wallet operation
The lifecycle of every send from a wallet. There is no other way funds leave.
| Status | Terminal | Meaning | Webhook on entry |
|---|---|---|---|
authorization_required | no | Built, waiting for your signature. Nothing has moved. The authorization and signing objects ride the response only in this state | none |
authorized | no | Your signature was accepted. Execution begins | none |
signing | no | Obtaining the signature from the signing network | none |
signed | no | Signature obtained | none |
submitting | no | Assembling and broadcasting | none |
submitted | no | On chain, awaiting confirmation | none |
confirmed | yes | Landed. tx_hash is the proof | wallet.operation_confirmed |
failed | yes | Nothing moved. Creating a replacement is safe | wallet.operation_failed |
expired | yes | Not authorized inside the 30-second window. Nothing moved | none |
returned | yes | Moved, then reversed on chain. Reconcile before re-sending | none |
failed and returned are not interchangeable. failed means the money
never moved, so a retry is safe. returned means it moved and came back,
so retrying blindly can send twice.
Build handlers on two rules. Statuses only move forward through their chain, and every state you must react to has a webhook. Anything without a webhook is an intermediate state you can treat as "in progress".