> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction lifecycle

> How a transaction moves through OMS from creation to completion, including statuses, sub-statuses, and webhook events.

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.

## Transaction types

| Type             | What it does                                                        |
| ---------------- | ------------------------------------------------------------------- |
| `fiatToCrypto`   | Fiat in, USDC delivered to a wallet                                 |
| `cryptoToFiat`   | USDC out of a wallet, fiat delivered to a bank, card, or cash agent |
| `cryptoToCrypto` | USDC moves from one wallet to another, or to an external address    |

OMS infers the type from the asset pair. You do not set it explicitly.

## Status model

```
processing                      (initial state; the quote is already accepted)
    │
    ├──► completed              (standard flows)
    │
    ├──► cashPickupReady        (cash off-ramp: pickup code issued)
    │        ├──► completed     (cash collected)
    │        └──► failed        (uncollected and expired, triggers a manual refund)
    │
    └──► failed
```

The four top-level statuses are `processing`, `cashPickupReady`, `completed`, and `failed`. A transaction begins at `processing` the moment it is created from a quote. `cashPickupReady` is the cash off-ramp state where a pickup code has been issued.

**Branch on `status` only.** The optional `subStatus` is a free-form string carrying operational detail (for example `fundsPulled` when the source funds are pulled, or `cashPickupExpired`). Use it for display and logging, not for control flow.

## Webhook events

OMS fires a webhook on every meaningful state change. Event names follow the pattern `transaction.{type}.{event}`:

```
transaction.fiatToCrypto.processing
transaction.fiatToCrypto.completed
transaction.fiatToCrypto.failed

transaction.cryptoToFiat.processing
transaction.cryptoToFiat.completed
transaction.cryptoToFiat.failed

transaction.cryptoToCrypto.completed
transaction.cryptoToCrypto.failed
```

Each payload contains the full transaction object. Polling `GET /transactions/{id}` is rarely necessary if webhooks are configured.

Webhook subscriptions are managed through the API (the Webhooks endpoints support full CRUD), in addition to the dashboard.

**Unrouted deposits:** `wallet.depositDetected` fires when crypto arrives at a wallet address outside any OMS-managed deposit address or transaction. Use this to handle unexpected inbound funds.

## 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.

<Tip>
  Set `Idempotency-Key` on every write request in production. It protects against double-execution without any coordination on your side.
</Tip>
