Skip to main content
Every transaction in OMS moves through a predictable set of statuses. The top-level status is designed for programmatic branching. The optional subStatus provides operational detail without complicating your core logic.

Direction

Every transaction carries a sourceToDestination field: a composite of the source and destination instrument categories.
ValueWhat it does
cryptoToCryptoUSDC moves from one wallet to another, or to an external address
cryptoToFiatAccountUSDC out of a wallet, fiat delivered to a bank account
cryptoToCashUSDC out of a wallet, delivered as a cash pickup
fiatAccountToCryptoFiat in from a bank account, USDC delivered to a wallet
cashToCryptoCash in from a retail deposit, USDC delivered to a wallet
OMS infers the direction from the source and destination instruments. You do not set it explicitly.

Status model

processing                      (initial state; the quote is already accepted)

    ├──► completed              (standard flows)

    ├──► awaitingAction         (non-terminal; blocked on developer, upstream, or compliance action)
    │        └──► processing    (once the hold clears)

    └──► failed
The four top-level statuses are processing, awaitingAction, completed, and failed. A transaction begins at processing the moment it is created from a quote. awaitingAction is a non-terminal hold state; the hold object explains the reason and carries a deadline, and the transaction returns to processing once cleared. The hold object is discriminated by its type field:
hold.typeMeaning
senderAttributionA deposit address received crypto from a sender not linked to a counterparty. Carries the inbound txHash and matchableExternalAccountCriteria; registering a matching walletExternal external account releases the hold.
depositAddressFrozenThe deposit address is frozen.
depositAddressInactiveThe deposit address’s destination external account became unusable. The cause object identifies the external account, its status, and the reason it became invalid.
Each hold carries since, an optional deadline, and resolvedAt once cleared. Branch on status only. The optional subStatus is a status-scoped string carrying operational detail namespaced by its parent status (for example processing.fundsPulled, processing.cashPickupReady, or completed.cashPickupCollected). Cash off-ramp lifecycle events surface here rather than as top-level statuses, and payout execution does too: processing.awaitingCryptoOut, processing.cryptoOut, processing.awaitingFiatOut, and processing.fiatOut track the crypto and fiat out-legs of a payout. Use subStatus for display and logging, not for control flow.

Webhook events

OMS fires a webhook on every meaningful state change. Each delivery carries the full transaction object, so your handler reads the status (and, if needed, subStatus) directly off the payload. Polling GET /transactions/{id} is rarely necessary once webhooks are configured. Subscribe to events through the Webhooks endpoints or the OMS Dashboard. A subscription is an endpoint URL plus the list of event types you want:
POST /webhooks
{
  "url": "https://your-app.example.com/oms/webhooks",
  "events": []
}
An empty events array (or ["*"]) subscribes to every event type. The Webhooks endpoints support full CRUD (GET/PATCH/DELETE /webhooks/{id}), and the create response returns a signing secret once, which you use to verify the Webhook-Signature header on incoming deliveries. Transaction events are namespaced by transfer type: transaction.fiatToCrypto.*, transaction.cryptoToFiat.*, and transaction.cryptoToCrypto.*, each with processing, completed, failed, and refund variants (plus cashPickupReady and codeExpired on the cash payout path). See the webhook events catalog for every event type and the delivery envelope.

Auto-created transactions

Deposit addresses, virtual accounts, and cash-ins bypass the quote step. OMS creates the transaction internally when funds arrive and moves it directly to processing. The same status model and webhook events apply.

Idempotency

All POST endpoints accept an Idempotency-Key header. Use a stable key (UUID tied to your internal order ID) to safely retry on network failure. OMS returns the same response for any subsequent request with the same key within the idempotency window.
Set Idempotency-Key on every write request in production. It protects against double-execution without any coordination on your side.