status is designed for programmatic branching. The optional subStatus provides operational detail without complicating your core logic.
Direction
Every transaction carries asourceToDestination field: a composite of the source and destination instrument categories.
OMS infers the direction from the source and destination instruments. You do not set it explicitly.
Status model
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:
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 underdata, so your handler reads the status (and, if needed, subStatus) directly off it. Polling GET /transactions/{transactionId} 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:
["*"] in subscriptions to receive every event type, or list specific event names to filter. The Webhooks endpoints support full CRUD (GET/PATCH/DELETE /webhooks/{webhookId}) plus lifecycle actions (POST /webhooks/{webhookId}/enable | /disable | /rotate-key | /test), and the create response returns a signingKey once, which you use to verify the Webhook-Signature header on incoming deliveries. Inspect and replay delivery history at GET /webhooks/{webhookId}/deliveries and POST /webhooks/{webhookId}/deliveries/retry.
Transactions emit one event, transaction.statusChanged, on every status transition described above, in either direction and on any rail. The full transaction arrives under data, so branch on data.status and use data.subStatus for detail. The envelope’s previousStatus names the status it left. To be notified when a transaction is held for compliance review, subscribe explicitly to transaction.fiatToCrypto.underReview, transaction.cryptoToFiat.underReview, or transaction.cryptoToCrypto.underReview; the * wildcard does not include them. 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 toprocessing. The same status model and webhook events apply.
Idempotency
AllPOST 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.