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

# Cash-in

> How to let a customer deposit physical cash at a retail location and receive USDC in their wallet.

<Note>
  **Before you start:** the OMS API is in early access. Every endpoint, including the ones in this guide, requires an early-access API key. [Request access](https://info.polygon.technology/get-early-access?utm_source=docs\&utm_medium=card\&utm_campaign=oms_access) before you begin.

  Authenticate by exchanging your API key and secret for a bearer token at `POST /auth/token`, then send it as `Authorization: Bearer {accessToken}` on every request. Every mutating request (`POST` and `PATCH`) also requires an `Idempotency-Key` header. See [Get started](/payments/get-started) for the full flow.
</Note>

<div style={{border:"1px solid #C8CFE1",borderRadius:"12px",overflow:"hidden",marginBottom:"24px"}}>
  <div style={{background:"linear-gradient(180deg,#EAE4F5 0%,#F6F3FB 100%)",borderBottom:"1px solid #D5C4F2",padding:"10px 16px",fontSize:"11px",fontWeight:"700",color:"#670DE5",letterSpacing:"0.06em",textTransform:"uppercase"}}>Cash-in flow</div>

  <div style={{borderBottom:"1px solid #EEF0F9",padding:"9px 16px",display:"flex",alignItems:"center",gap:"10px"}}>
    <span style={{color:"#929EBA",fontSize:"11px",fontWeight:"700",minWidth:"16px",textAlign:"right"}}>1</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>App</span>
    <span style={{color:"#670DE5",fontWeight:"700"}}>→</span>
    <span style={{background:"#EAE4F5",color:"#670DE5",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"700",whiteSpace:"nowrap"}}>OMS</span>
    <span style={{fontFamily:"'Geist Mono',ui-monospace,monospace",fontSize:"12px",color:"#141635"}}>POST /cash-ins (source, destination, cash)</span>
  </div>

  <div style={{borderBottom:"1px solid #EEF0F9",padding:"9px 16px",display:"flex",alignItems:"center",gap:"10px"}}>
    <span style={{color:"#929EBA",fontSize:"11px",fontWeight:"700",minWidth:"16px",textAlign:"right"}}>2</span>
    <span style={{background:"#EAE4F5",color:"#670DE5",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"700",whiteSpace:"nowrap"}}>OMS</span>
    <span style={{color:"#48526F",fontWeight:"700"}}>→</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>App</span>
    <span style={{fontFamily:"'Geist Mono',ui-monospace,monospace",fontSize:"12px",color:"#141635"}}>\{depositInstructions: \{code: "XXX XXX", expiresAt}}</span>
  </div>

  <div style={{borderBottom:"1px solid #EEF0F9",padding:"9px 16px",display:"flex",alignItems:"center",gap:"10px"}}>
    <span style={{color:"#929EBA",fontSize:"11px",fontWeight:"700",minWidth:"16px",textAlign:"right"}}>3</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>App</span>
    <span style={{color:"#670DE5",fontWeight:"700"}}>→</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>Customer</span>
    <span style={{fontSize:"13px",color:"#141635"}}>Show deposit code + nearby location</span>
  </div>

  <div style={{borderBottom:"1px solid #EEF0F9",padding:"9px 16px",display:"flex",alignItems:"center",gap:"10px"}}>
    <span style={{color:"#929EBA",fontSize:"11px",fontWeight:"700",minWidth:"16px",textAlign:"right"}}>4</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>Customer</span>
    <span style={{color:"#670DE5",fontWeight:"700"}}>→</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>Retail</span>
    <span style={{fontSize:"13px",color:"#141635"}}>Present code, hand over cash</span>
  </div>

  <div style={{borderBottom:"1px solid #EEF0F9",padding:"9px 16px",display:"flex",alignItems:"center",gap:"10px"}}>
    <span style={{color:"#929EBA",fontSize:"11px",fontWeight:"700",minWidth:"16px",textAlign:"right"}}>5</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>Retail</span>
    <span style={{color:"#670DE5",fontWeight:"700"}}>→</span>
    <span style={{background:"#EAE4F5",color:"#670DE5",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"700",whiteSpace:"nowrap"}}>OMS</span>
    <span style={{fontSize:"13px",color:"#141635"}}>Confirm deposit + actual amount</span>
  </div>

  <div style={{borderBottom:"1px solid #EEF0F9",padding:"9px 16px",display:"flex",alignItems:"center",gap:"10px"}}>
    <span style={{color:"#929EBA",fontSize:"11px",fontWeight:"700",minWidth:"16px",textAlign:"right"}}>6</span>
    <span style={{background:"#EAE4F5",color:"#670DE5",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"700",whiteSpace:"nowrap"}}>OMS</span>
    <span style={{fontSize:"13px",color:"#141635",marginLeft:"4px"}}>Auto-create cashToCrypto transaction</span>
  </div>

  <div style={{padding:"9px 16px",display:"flex",alignItems:"center",gap:"10px"}}>
    <span style={{color:"#929EBA",fontSize:"11px",fontWeight:"700",minWidth:"16px",textAlign:"right"}}>7</span>
    <span style={{background:"#EAE4F5",color:"#670DE5",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"700",whiteSpace:"nowrap"}}>OMS</span>
    <span style={{color:"#670DE5",fontWeight:"700"}}>→</span>
    <span style={{background:"#EEF0F9",color:"#48526F",padding:"2px 8px",borderRadius:"4px",fontSize:"11px",fontWeight:"600",whiteSpace:"nowrap"}}>App</span>
    <span style={{fontFamily:"'Geist Mono',ui-monospace,monospace",fontSize:"12px",color:"#141635"}}>Webhooks: cashIn.completed, transaction.fiatToCrypto.completed</span>
  </div>
</div>

## Prerequisites

Before creating a cash-in, you need:

1. **A customer** with a `cst_` ID and the `usd` endorsement active (required for cash flows).
2. **A cash location**, retrieved from `GET /cash-locations` with `provider`, `latitude`, `longitude`, and `flow=cash_in`. This is the retail location where the customer will deposit cash. Each result includes a `locId` and a `cashLocationReference`, which you pass on the cash-in's `cash` field as `locationId` and `locationReference` respectively.
3. **A crypto destination wallet**: an OMS custodial wallet (`wlt_`) referenced by `destination.wallet.id`, or an external wallet referenced by `destination.wallet.blockchainAddress` or `destination.wallet.externalAccount`.
4. **A webhook endpoint** subscribed to the `cashIn.*` and `transaction.fiatToCrypto.*` events, registered with `POST /webhooks` or in the OMS Dashboard.

## Limits

The following limits apply to cash-ins:

| Limit               | Value                                |
| ------------------- | ------------------------------------ |
| Transaction minimum | \$20                                 |
| Transaction maximum | \$500 (\$1,000 at Walmart locations) |
| Daily maximum       | \$1,500 and 3 transactions           |
| Weekly maximum      | \$3,500 and 12 transactions          |
| Monthly maximum     | \$5,000 and 20 transactions          |

## How Cash-In Works

Cash-In is a specialized, ephemeral flow for in-person cash deposits. Unlike Deposit Addresses (persistent, reusable, crypto-source), a cash-in generates a one-time deposit code valid for 1 hour. The customer presents the code at a retail location, deposits cash, and OMS auto-converts to crypto.

Key differences from other funding methods:

* **Indicated amount, not exact amount.** You provide an optional `source.indicatedAmount`. OMS uses this to generate upfront estimates. The actual deposit amount is determined by how much cash the customer deposits at the counter. If you omit `indicatedAmount`, no estimates are returned.
* **Amounts are estimated at creation, finalized after deposit.** At creation the `source` and `destination` amounts are derived from `indicatedAmount`. Once the customer deposits cash, they are recalculated on the actual amount.
* **No quote step.** Cash-In auto-creates a transaction when the deposit is received, similar to Deposit Addresses and Virtual Accounts.
* **Gas sponsorship.** `sponsorGas` defaults to `true`, so OMS absorbs the on-chain gas for the destination delivery. The absorbed cost appears as the top-level `sponsorGasCost`. At launch all fees and gas are `0.00`.

## Step 1: Create a Cash-In Code

```
POST /cash-ins
Authorization: Bearer {accessToken}
Idempotency-Key: ci_order_789
Content-Type: application/json
```

```json theme={null}
{
  "customerId": "cst_01H9Xa...",
  "source": {
    "asset": "usd",
    "indicatedAmount": "200.00"
  },
  "destination": {
    "asset": "usdc",
    "network": "polygon",
    "wallet": { "id": "wlt_01H9Xb..." }
  },
  "cash": {
    "locationId": "loc_01H9Xd...",
    "locationReference": "R1JFRU5ET1QtMjQzNDpsYXQ9MzguNDk1MTMzLGxuZz0tMTIxLjUwNTMzNg=="
  },
  "sponsorGas": true,
  "metadata": {
    "orderId": "ord_789"
  }
}
```

**Required fields:** `customerId`, `source`, `destination`, and `cash`.

**`source.asset`** (required): the deposit currency; `usd`.

**`source.indicatedAmount`** (optional): the expected deposit amount. OMS uses this value to generate upfront estimates in the response. If omitted, no estimates are returned. The actual deposit amount is determined by how much cash the customer deposits at the location.

**`destination`** (required): the crypto the deposit is converted to. Set `asset` and `network`, and identify the wallet with `wallet.id` (an OMS wallet, `wlt_`), `wallet.blockchainAddress` (an external on-chain address), or `wallet.externalAccount` (a registered external account).

**`cash`** (required): the retail location. Set `locationId` (from the `locId` field of `GET /cash-locations`) and `locationReference` (from the `cashLocationReference` field), which selects a specific store.

**`sponsorGas`** (optional): defaults to `true`, so OMS absorbs the on-chain gas for the destination delivery. Only `true` is currently supported.

### Response, `201 Created`

```json theme={null}
{
  "id": "ci_01H9Xy...",
  "object": "cashIn",
  "type": "fiatToCrypto",
  "status": "pending",
  "customerId": "cst_01H9Xa...",
  "source": {
    "asset": "usd",
    "indicatedAmount": "200.00",
    "amountGross": "200.00",
    "amountNet": "200.00",
    "feesDeducted": { "total": "0.00", "developer": "0.00", "oms": "0.00", "gas": "0.00" }
  },
  "destination": {
    "asset": "usdc",
    "network": "polygon",
    "amountGross": "199.00",
    "amountNet": "199.00",
    "feesDeducted": { "total": "0.00", "developer": "0.00", "oms": "0.00", "gas": "0.00" },
    "wallet": {
      "id": "wlt_01H9Xb...",
      "blockchainAddress": "0x7B3a9F2c4D1eA8bF6390cE5d2B7fA104C8e3D9b1"
    }
  },
  "cash": {
    "locationId": "loc_01H9Xd...",
    "locationReference": "R1JFRU5ET1QtMjQzNA=="
  },
  "location": {
    "name": "CVS Pharmacy #4521",
    "address": "123 Main St, New York, NY 10001"
  },
  "rates": {
    "pair": "usd/usdc",
    "exchangeRate": "0.9950",
    "effectiveRate": "0.9950"
  },
  "fixedAmountSide": "source",
  "sponsorGas": true,
  "sponsorGasCost": "0",
  "depositInstructions": {
    "code": "483 291",
    "expiresAt": "2026-03-16T19:30:00Z",
    "locationName": "CVS Pharmacy #4521",
    "locationAddress": "123 Main St, New York, NY 10001"
  },
  "transactionId": null,
  "metadata": {
    "orderId": "ord_789"
  },
  "createdAt": "2026-03-16T18:30:00Z",
  "updatedAt": "2026-03-16T18:30:00Z"
}
```

**What to show the customer:**

* `depositInstructions.code`: the code they present at the retail counter ("483 291").
* `depositInstructions.locationName` and `locationAddress`: where to go.
* `depositInstructions.expiresAt`: the code is valid for 1 hour.
* The estimated economics based on `indicatedAmount` (\$200.00): `source` and `destination` each carry `amountGross`, `amountNet`, and a `feesDeducted` breakdown, and the top-level `rates` object carries `pair`, `exchangeRate`, and `effectiveRate`. Show the customer what they would receive at this deposit amount.

At launch all fee components are `0.00`. `transactionId` is `null` until the deposit is confirmed. OMS fires the `cashIn.created` event when the code is issued.

## Step 2: Customer Deposits Cash

The customer visits the location and presents their code at the counter. This step happens outside OMS, at the retail location's payment terminal. OMS is notified when the deposit is received.

If the code expires before the customer arrives, you can refresh it (see "Refreshing an Expired Code" below).

## Step 3: Deposit Received, Cash-In Completes

Once the retail partner confirms the deposit, OMS recalculates pricing on the actual amount, converts USD to the destination crypto, and delivers it. The cash-in moves to `completed`, OMS fires the `cashIn.completed` event, and the cash-in's `transactionId` is populated. Read the cash-in to see the final state:

```
GET /cash-ins/ci_01H9Xy...
Authorization: Bearer {accessToken}
```

```json theme={null}
{
  "id": "ci_01H9Xy...",
  "object": "cashIn",
  "type": "fiatToCrypto",
  "status": "completed",
  "subStatus": "settled",
  "customerId": "cst_01H9Xa...",
  "source": {
    "asset": "usd",
    "indicatedAmount": "200.00",
    "amountGross": "200.00",
    "amountNet": "200.00",
    "feesDeducted": { "total": "0.00", "developer": "0.00", "oms": "0.00", "gas": "0.00" }
  },
  "destination": {
    "asset": "usdc",
    "network": "polygon",
    "amountGross": "199.00",
    "amountNet": "199.00",
    "feesDeducted": { "total": "0.00", "developer": "0.00", "oms": "0.00", "gas": "0.00" },
    "wallet": {
      "id": "wlt_01H9Xb...",
      "blockchainAddress": "0x7B3a9F2c4D1eA8bF6390cE5d2B7fA104C8e3D9b1"
    }
  },
  "cash": {
    "locationId": "loc_01H9Xd...",
    "locationReference": "R1JFRU5ET1QtMjQzNA=="
  },
  "location": {
    "name": "CVS Pharmacy #4521",
    "address": "123 Main St, New York, NY 10001"
  },
  "rates": {
    "pair": "usd/usdc",
    "exchangeRate": "0.9950",
    "effectiveRate": "0.9950"
  },
  "fixedAmountSide": "source",
  "sponsorGas": true,
  "sponsorGasCost": "0",
  "depositInstructions": {
    "code": "483 291",
    "expiresAt": "2026-03-16T19:30:00Z",
    "locationName": "CVS Pharmacy #4521",
    "locationAddress": "123 Main St, New York, NY 10001"
  },
  "transactionId": "txn_01H9Xz...",
  "metadata": { "orderId": "ord_789" },
  "createdAt": "2026-03-16T18:30:00Z",
  "updatedAt": "2026-03-16T18:47:00Z",
  "completedAt": "2026-03-16T18:47:00Z"
}
```

**What changed from the creation response:**

* `status` is now `completed` and `subStatus` is `settled`.
* The `source` and `destination` amounts are recalculated on the actual deposit amount (they were estimated from `indicatedAmount` at creation).
* `completedAt` is populated.
* `transactionId` links to the auto-created transaction (the `txn_` ID). Read that transaction to see the on-chain delivery hash.

## Step 4: Auto-Created Transaction

When the cash-in completes, OMS auto-creates a transaction with `sourceToDestination: cashToCrypto`. It follows the standard processing → completed lifecycle, firing the fiat-funded transaction events (`transaction.fiatToCrypto.*`). Its `precursor` identifies the originating cash-in.

### Webhook: `transaction.fiatToCrypto.processing`

```json theme={null}
{
  "eventId": "evt_01H9Xw2...",
  "eventName": "transaction.fiatToCrypto.processing",
  "resourceType": "transaction_fiat_to_crypto",
  "resourceId": "txn_01H9Xz...",
  "occurredAt": "2026-03-16T18:47:05Z",
  "payload": {
    "id": "txn_01H9Xz...",
    "object": "transaction",
    "sourceToDestination": "cashToCrypto",
    "status": "processing",
    "subStatus": "processing.fundsPulled",
    "customerId": "cst_01H9Xa...",
    "precursor": {
      "type": "cashIn",
      "details": { "cashInId": "ci_01H9Xy..." }
    },
    "source": {
      "party": { "relationship": "customer", "customerId": "cst_01H9Xa...", "entityType": "individual" },
      "type": "cash",
      "category": "cash",
      "details": {
        "asset": "usd",
        "cashLocationId": "loc_01H9Xd...",
        "cashLocationReference": "R1JFRU5ET1QtMjQzNA=="
      }
    },
    "destination": {
      "party": { "relationship": "customer", "customerId": "cst_01H9Xa...", "entityType": "individual" },
      "type": "walletOms",
      "category": "crypto",
      "details": {
        "id": "wlt_01H9Xb...",
        "asset": "usdc",
        "network": "polygon",
        "blockchainAddress": "0x7B3a9F2c...e3D9b1",
        "custodyType": "custodial",
        "txHash": null
      }
    },
    "pricing": {
      "source": { "asset": "usd", "amountGross": "200.00", "amountNet": "200.00", "feesDeducted": { "total": "0.00", "developer": "0.00", "oms": "0.00", "gas": "0.00" } },
      "destination": { "asset": "usdc", "amountGross": "199.00", "amountNet": "199.00", "feesDeducted": { "total": "0.00", "developer": "0.00", "oms": "0.00", "gas": "0.00" } },
      "pair": "usd/usdc",
      "exchangeRate": "0.9950",
      "effectiveRate": "0.9950",
      "fixedAmountSide": "source",
      "sponsorGas": true,
      "sponsorGasCost": "0.00"
    },
    "estimatedArrival": null,
    "error": null,
    "hold": null,
    "metadata": { "orderId": "ord_789" },
    "createdAt": "2026-03-16T18:47:05Z",
    "updatedAt": "2026-03-16T18:47:05Z",
    "expiresAt": null
  }
}
```

**Key fields on the auto-created transaction:**

* `precursor.type: "cashIn"`: links this transaction back to the originating cash-in (`details.cashInId`).
* `sourceToDestination: "cashToCrypto"`: the source was a cash deposit; the destination is crypto.
* `source.type: "cash"`: there is no blockchain transaction on the source side.
* All amounts live in `pricing`; the sides carry only identity and instrument detail.

### Webhook: `transaction.fiatToCrypto.completed`

OMS fires `transaction.fiatToCrypto.completed` when the crypto lands. The envelope is the same shape; in the payload, `status` is now `completed`, `subStatus` is `null`, and `destination.details.txHash` is populated with the on-chain hash.

At this point the flow is done. The customer deposited \$200.00 cash at CVS Pharmacy #4521, and the converted USDC was delivered to wallet `wlt_01H9Xb...` on Polygon. At launch all fee components are `0.00`.

## Refreshing an Expired Code

If the customer doesn't arrive before the code expires, refresh it to issue a new code with a new 1-hour window. The previous code is invalidated.

```
POST /cash-ins/ci_01H9Xy.../refresh
Authorization: Bearer {accessToken}
Idempotency-Key: ci_refresh_789_2
```

The response is the full cash-in object with a fresh `depositInstructions.code` and an `expiresAt` extended by another hour. Everything else stays the same:

```json theme={null}
{
  "id": "ci_01H9Xy...",
  "object": "cashIn",
  "status": "pending",
  "depositInstructions": {
    "code": "917 042",
    "expiresAt": "2026-03-16T20:30:00Z",
    "locationName": "CVS Pharmacy #4521",
    "locationAddress": "123 Main St, New York, NY 10001"
  },
  "transactionId": null
}
```

**Constraints:** Refresh can only be called while the cash-in is in `pending` status. If the cash-in has already `completed` or `expired`, the call returns `422 Unprocessable`.

## Code Expiration

If the code expires without a deposit, the cash-in moves to `expired` and OMS fires the `cashIn.expired` event. You can also detect this by reading the cash-in:

```
GET /cash-ins/ci_01H9Xy...
Authorization: Bearer {accessToken}
```

The response shows `"status": "expired"` and `transactionId: null`. An expired cash-in is terminal: no transaction is created and no money moves. If the customer still wants to deposit cash, create a new cash-in.

## Polling

You can read the cash-in status at any time:

```
GET /cash-ins/ci_01H9Xy...
Authorization: Bearer {accessToken}
```

Or list cash-ins, optionally filtered by customer:

```
GET /cash-ins?customerId=cst_01H9Xa...
Authorization: Bearer {accessToken}
```

The list response is `{ data: [...], hasMore, nextCursor }`. Page with the `limit` and `cursor` query parameters.

## Failure Handling

Cash-In failures can happen at two levels:

**Cash-In level:** The code expires before the customer deposits cash. The cash-in moves to `expired` and no transaction is created. No money moved, no refund needed. OMS fires `cashIn.expired`; you can also detect this by reading the cash-in.

**Transaction level:** The cash deposit is received but crypto delivery fails. The auto-created transaction moves to `failed` and you receive a `transaction.fiatToCrypto.failed` event with the payload's `error` object populated:

```json theme={null}
{
  "eventId": "evt_01H9Xw5...",
  "eventName": "transaction.fiatToCrypto.failed",
  "resourceType": "transaction_fiat_to_crypto",
  "resourceId": "txn_01H9Xz...",
  "occurredAt": "2026-03-16T18:50:00Z",
  "payload": {
    "id": "txn_01H9Xz...",
    "object": "transaction",
    "sourceToDestination": "cashToCrypto",
    "status": "failed",
    "subStatus": null,
    "customerId": "cst_01H9Xa...",
    "precursor": { "type": "cashIn", "details": { "cashInId": "ci_01H9Xy..." } },
    "error": {
      "code": "onChainRevert",
      "message": "Delivery transaction reverted on-chain"
    },
    "metadata": { "orderId": "ord_789" },
    "createdAt": "2026-03-16T18:47:05Z",
    "updatedAt": "2026-03-16T18:50:00Z"
  }
}
```

Cash refunds are handled outside OMS at the retail location.

## Compliance Review

A transaction triggered by a cash-in may be held for compliance review. It stays in `processing` with `subStatus` `processing.underReview`. Do not surface this to the customer. Once resolved, the transaction proceeds to `completed` or `failed`, firing `transaction.fiatToCrypto.completed` or `transaction.fiatToCrypto.failed`.

## Summary: Webhook Events

The cash-in flow delivers two event streams: the cash-in's own lifecycle events, and the fiat-funded transaction events fired on the auto-created transaction. See [Webhook events](/api-reference/webhook-events) for the envelope and the full catalog.

| Event                                 | When                                                                                     |
| ------------------------------------- | ---------------------------------------------------------------------------------------- |
| `cashIn.created`                      | The deposit code was issued                                                              |
| `cashIn.completed`                    | The cash was deposited and converted; `transactionId` links the auto-created transaction |
| `cashIn.expired`                      | The code expired before a deposit was made                                               |
| `transaction.fiatToCrypto.processing` | Cash received, crypto delivery underway                                                  |
| `transaction.fiatToCrypto.completed`  | Crypto delivered to the destination                                                      |
| `transaction.fiatToCrypto.failed`     | Crypto delivery failed; see `payload.error`                                              |

Each event carries the full resource object under `payload`. Branch on the event name or `payload.status`; treat `subStatus` as optional operational detail.

## Key Points

* **Indicated amount for upfront estimates.** Pass an optional `source.indicatedAmount`. OMS returns estimated amounts at creation; final amounts are calculated when the customer deposits. If omitted, no estimates are returned.
* **Amounts and rates on the cash-in.** The `source` and `destination` each carry `amountGross`, `amountNet`, and a `feesDeducted` breakdown; the top-level `rates` object carries `pair`, `exchangeRate`, and `effectiveRate`. At launch all fee components are `0.00`.
* **Gas sponsorship.** `sponsorGas` defaults to `true`; OMS absorbs the destination gas. The absorbed cost shows as the top-level `sponsorGasCost` (`"0"` at launch).
* **Codes expire in 1 hour.** Call `POST /cash-ins/{cashInId}/refresh` to issue a new code if the customer needs more time. Only works while `status` is `pending`.
* **Cash-In is single-use.** Once a deposit is received or the code expires, the cash-in is terminal. Create a new one for the next deposit.
* **Two event streams.** The cash-in fires `cashIn.created`, `cashIn.completed`, and `cashIn.expired`; the auto-created transaction fires `transaction.fiatToCrypto.*`. Subscribe to both, or read the cash-in with `GET /cash-ins/{cashInId}` if you prefer polling.
* **The source is cash.** There is no blockchain transaction on the source side; the auto-created transaction's `sourceToDestination` is `cashToCrypto`.
* **The destination is an OMS or external wallet.** Identify it with `destination.wallet.id` (an OMS wallet, `wlt_`), `destination.wallet.blockchainAddress` (an external on-chain address), or `destination.wallet.externalAccount` (a registered external account).
