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

# Deposit addresses

> How to create a persistent crypto deposit address that auto-converts incoming funds.

<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 {token}` on every request. See [Get started](/payments/get-started) for the full flow.
</Note>

<Note>
  Deposit address provisioning and management is not yet available in the OMS API. To be notified when it launches, register your interest.

  <Card title="Register interest" icon="envelope" href="https://info.polygon.technology/get-early-access?utm_source=docs&utm_medium=card&utm_campaign=oms_access">
    Share your use case and we'll reach out when deposit address provisioning and management is available.
  </Card>
</Note>

The flow below shows the intended pattern end to end. The create and manage steps (Step 1 and the Managing Deposit Addresses section) are not yet available: there are no endpoints to create, update, list, or delete a deposit address today. The transaction reads referenced in Step 3 (`GET /transactions/{id}` and `GET /customers/{id}/transactions`) are available now.

<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"}}>Deposit address 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 /customers/\{id}/deposit-addresses</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: \{address: "0x..."}}</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"}}>Sender</span>
    <span style={{fontSize:"13px",color:"#141635"}}>Share onchain address</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"}}>Sender</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"}}>Polygon</span>
    <span style={{fontSize:"13px",color:"#141635"}}>Send USDC to address</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"}}>Polygon</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"}}>Deposit detected</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 and execute 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"}}>Webhook: transaction.completed</span>
  </div>
</div>

## Prerequisites

Before creating a Deposit Address, you need:

1. **A customer** with a `cst_` ID and the `cryptoCustody` endorsement active.
2. **A crypto destination**: a `WalletTarget` object with one of `wallet` (OMS custodial wallet, `wlt_`), `blockchainAddress` (external on-chain address), or `externalAccount` (saved on-chain address, `cpBcAddr_`).
3. **Webhook subscriptions** configured in the OMS Dashboard for `transaction.cryptoToCrypto.*` events.

## Step 1: Create the Deposit Address

<Note>
  Creating a deposit address is not yet available in the OMS API. The request and response below describe the intended shape so you can plan your integration.
</Note>

A Deposit Address is a persistent, reusable configuration that tells OMS: "When crypto arrives at this address, convert and deliver it to a destination." There is no amount specified upfront, the amount is determined when funds actually arrive.

Both sides are crypto: sources accept `usdc` or `usdt` on `polygon` or `ethereum`, and destinations are specified via a `WalletTarget` object (the same shape used elsewhere for crypto delivery).

### Request

```
POST /v0.9/customers/cst_01H9Xa.../deposit-addresses
Authorization: Bearer {token}
Idempotency-Key: da-alice-usdc-polygon-001
Content-Type: application/json
```

```json theme={null}
{
  "source": {
    "asset": "usdc",
    "network": "polygon"
  },
  "destination": {
    "wallet": {
      "wallet": "wlt_01H9Xb..."
    },
    "asset": "usdc",
    "network": "polygon"
  },
  "developerFees": [
    { "type": "percentage", "rate": "0.015", "wallet": "wlt_01H9Xf..." }
  ],
  "label": "Alice deposit address",
  "metadata": {
    "purpose": "user_deposit"
  }
}
```

**Required fields:**

* `source.asset`: The crypto asset to accept (`usdc` or `usdt`).
* `source.network`: The blockchain to monitor (`polygon` or `ethereum`).
* `destination.asset`: The crypto asset to deliver (`usdc` or `usdt`).
* `destination.network`: The destination rail (`polygon` or `ethereum`).
* A `destination.wallet` object with one of: `wallet`, `blockchainAddress`, or `externalAccount`.

**Optional fields:**

* `developerFees`: Array of fee entries. Each entry has `type` (`percentage`), `rate` (as a string, e.g., `"0.015"`), and optional `wallet` (OMS wallet receiving the fee). Percentage-only because the deposit amount is unknown until funds arrive. If omitted, no developer fees are collected.
* `label`: A human-readable name for this address.
* `metadata`: Up to 20 arbitrary key-value pairs.

### Response, `201 Created`

```json theme={null}
{
  "id": "da_01H9Xy...",
  "object": "depositAddress",
  "customerId": "cst_01H9Xa...",
  "status": "active",
  "transactionType": "cryptoToCrypto",
  "source": {
    "asset": "usdc",
    "network": "polygon",
    "depositInstructions": {
      "address": "0xABC123...",
      "asset": "usdc",
      "network": "polygon"
    }
  },
  "destination": {
    "wallet": {
      "wallet": "wlt_01H9Xb..."
    },
    "asset": "usdc",
    "network": "polygon"
  },
  "developerFees": [
    { "type": "percentage", "rate": "0.015", "wallet": "wlt_01H9Xf..." }
  ],
  "omsFeeSchedule": {
    "feeCurrency": "usd",
    "entries": [
      { "type": "percentage", "rate": "0.02" },
      { "type": "fixed", "amount": "3.00" }
    ]
  },
  "label": "Alice deposit address",
  "metadata": {
    "purpose": "user_deposit"
  },
  "createdAt": "2024-01-15T10:00:00Z",
  "updatedAt": "2024-01-15T10:00:00Z"
}
```

**Key fields in the response:**

* `id`: The Deposit Address ID (prefix `da_`). Use this for GET, PATCH, and DELETE operations.
* `status`: Starts as `active`. Can be changed to `paused` or `deleted` later.
* `transactionType`: Always `cryptoToCrypto` for the destinations defined in the request schema.
* `source.depositInstructions`: The blockchain address your customer should send funds to. This is server-generated and unique to this Deposit Address.
* `omsFeeSchedule`: Shows how OMS fees will be calculated on auto-created transactions. Since there is no Quote step for Deposit Addresses, this gives you visibility into the fee structure upfront.

**What to do with the response:** Surface `source.depositInstructions.address` to your customer as the address they should send crypto to. Store `da_01H9Xy...` in your system for tracking.

## Test in sandbox

Once a deposit address is provisioned for you, you can simulate an inbound deposit in sandbox instead of sending real crypto. Call `POST /deposit-addresses/{depositAddressId}/simulate` with an `amount` in cents. OMS returns a synthetic `transactionHash` and fires the same `transaction.cryptoToCrypto.*` webhooks as a real deposit. This endpoint returns `404` in production.

```bash theme={null}
curl -X POST https://sandbox-api.polygon.technology/v0.9/deposit-addresses/da_01H9Xy.../simulate \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{ "amount": { "value": "25000" } }'
```

## Step 2: Customer Sends Funds

The customer sends crypto to the `depositInstructions.address` from any external wallet. There is nothing to do on the API side at this point, OMS monitors the blockchain for incoming deposits.

For this example, the customer sends **250.00 USDC** on Polygon to `0xABC123...`.

## Step 3: OMS Detects the Deposit and Auto-Creates a Transaction

When OMS detects the onchain deposit, it automatically creates a Transaction in `processing` status. This transaction skips the Quote step entirely, there is no Quote object, and `quote` is `null`.

### Webhook, `transaction.cryptoToCrypto.processing`

OMS fires this webhook as soon as the transaction is created:

```json theme={null}
{
  "id": "whk_evt_01H9Xw...",
  "event": "transaction.cryptoToCrypto.processing",
  "createdAt": "2024-01-15T14:30:00Z",
  "data": {
    "id": "txn_01H9Xd...",
    "object": "transaction",
    "type": "cryptoToCrypto",
    "status": "processing",
    "subStatus": "processing.fundsDetected",
    "customerId": "cst_01H9Xa...",
    "quoteId": null,
    "depositAddress": "da_01H9Xy...",
    "virtualAccount": null,
    "cashIn": null,
    "source": {
      "asset": "usdc",
      "network": "polygon",
      "amountGross": "250.00",
      "amountNet": "246.25",
      "feesDeducted": {
        "total": "3.75",
        "developer": "3.75",
        "oms": "0.00",
        "gas": "0.00"
      },
      "txHash": "0x8a3b7c...d4e5f6"
    },
    "destination": {
      "wallet": {
        "wallet": "wlt_01H9Xb..."
      },
      "asset": "usdc",
      "network": "polygon",
      "amountGross": "246.25",
      "amountNet": "246.25",
      "feesDeducted": {
        "total": "0.00",
        "developer": "0.00",
        "oms": "0.00",
        "gas": "0.00"
      }
    },
    "fixedAmountSide": "source",
    "sponsorGasCost": "0.00",
    "sponsorGas": false,
    "rates": {
      "exchangeRate": "1.0000",
      "effectiveRate": "0.9850"
    },
    "estimatedArrival": null,
    "error": null,
    "metadata": {
      "purpose": "user_deposit"
    },
    "createdAt": "2024-01-15T14:30:00Z",
    "updatedAt": "2024-01-15T14:30:00Z"
  }
}
```

**What to notice:**

* `quote: null`: Auto-created transactions skip the Quote step.
* `depositAddress: "da_01H9Xy..."`: Links this transaction back to the originating Deposit Address.
* `source.txHash`: The onchain transaction hash of the incoming deposit.
* `source.amountGross: "250.00"`: The actual amount deposited, now known.
* `source.amountNet: "246.25"`: After deducting the 3.75 developer fee.
* `destination.amountGross: "246.25"`: Amount to be delivered.
* `destination.amountNet: "246.25"`: Same as gross (no additional fees on destination).
* `source.feesDeducted.developer: "3.75"`: Your 1.5% fee on the 250.00 USDC deposit.
* `fixedAmountSide: "source"`: The source amount is fixed; destination is calculated from it.
* The `metadata` from the Deposit Address is carried over to the transaction.

### Polling Alternative

If you prefer polling over webhooks, you can retrieve the transaction directly:

```
GET /v0.9/transactions/txn_01H9Xd...
Authorization: Bearer {token}
```

Or list all transactions for the customer:

```
GET /v0.9/customers/cst_01H9Xa.../transactions
Authorization: Bearer {token}
```

## Step 4: Transaction Completes

OMS processes the conversion (in this crypto-to-crypto example, no exchange is needed since source and destination are both USDC on Polygon) and delivers funds to the destination wallet.

### Webhook, `transaction.cryptoToCrypto.completed`

```json theme={null}
{
  "id": "whk_evt_01H9Xw2...",
  "event": "transaction.cryptoToCrypto.completed",
  "createdAt": "2024-01-15T14:30:45Z",
  "data": {
    "id": "txn_01H9Xd...",
    "object": "transaction",
    "type": "cryptoToCrypto",
    "status": "completed",
    "subStatus": null,
    "customerId": "cst_01H9Xa...",
    "quoteId": null,
    "depositAddress": "da_01H9Xy...",
    "virtualAccount": null,
    "cashIn": null,
    "source": {
      "asset": "usdc",
      "network": "polygon",
      "amountGross": "250.00",
      "amountNet": "246.25",
      "feesDeducted": {
        "total": "3.75",
        "developer": "3.75",
        "oms": "0.00",
        "gas": "0.00"
      },
      "txHash": "0x8a3b7c...d4e5f6"
    },
    "destination": {
      "wallet": {
        "wallet": "wlt_01H9Xb..."
      },
      "asset": "usdc",
      "network": "polygon",
      "amountGross": "246.25",
      "amountNet": "246.25",
      "feesDeducted": {
        "total": "0.00",
        "developer": "0.00",
        "oms": "0.00",
        "gas": "0.00"
      }
    },
    "fixedAmountSide": "source",
    "sponsorGasCost": "0.00",
    "sponsorGas": false,
    "rates": {
      "exchangeRate": "1.0000",
      "effectiveRate": "0.9850"
    },
    "estimatedArrival": null,
    "error": null,
    "metadata": {
      "purpose": "user_deposit"
    },
    "createdAt": "2024-01-15T14:30:00Z",
    "updatedAt": "2024-01-15T14:30:45Z"
  }
}
```

**What changed from the `processing` webhook:**

* `status` is now `completed` and `subStatus` is `null` (sub-statuses only apply to the cash pickup flow).
* `updatedAt` reflects the completion time.

At this point the flow is done. The customer's 250 USDC has been received, your 3.75 USDC developer fee has been collected to `wlt_01H9Xf...`, and 246.25 USDC has been delivered to the destination wallet `wlt_01H9Xb...`.

## Step 5 (Reuse): More Deposits

The Deposit Address remains `active` and continues monitoring `0xABC123...`. Every subsequent deposit to that address triggers the same flow, a new auto-created transaction with a new `txn_` ID, the same `depositAddress`, and fees calculated from the same configuration.

There is no limit on the number of transactions a single Deposit Address can produce.

## Managing Deposit Addresses

<Note>
  The management operations below (pause, resume, change destination, delete, and list) are not yet available in the OMS API. They describe the intended pattern.
</Note>

### Pause a Deposit Address

Pausing stops OMS from processing new deposits. Any in-flight transactions continue to completion.

```
PATCH /v0.9/deposit-addresses/da_01H9Xy...
Authorization: Bearer {token}
Content-Type: application/json
```

```json theme={null}
{
  "status": "paused"
}
```

Response returns the updated Deposit Address with `"status": "paused"`.

### Resume a Deposit Address

```json theme={null}
{
  "status": "active"
}
```

### Change the Destination

You can redirect future deposits to a different wallet or external account without creating a new Deposit Address. The source (and its deposit instructions) remain the same.

```
PATCH /v0.9/deposit-addresses/da_01H9Xy...
Authorization: Bearer {token}
Content-Type: application/json
```

```json theme={null}
{
  "destination": {
    "wallet": {
      "wallet": "wlt_01H9Xc..."
    }
  }
}
```

Note: You cannot change the source. If you need a different source asset or network, create a new Deposit Address.

### Delete a Deposit Address

Soft-deletes the address. OMS stops monitoring for deposits.

```
DELETE /v0.9/deposit-addresses/da_01H9Xy...
Authorization: Bearer {token}
```

Response: `204 No Content`.

### List Deposit Addresses

```
GET /v0.9/customers/cst_01H9Xa.../deposit-addresses?status=active
Authorization: Bearer {token}
```

```json theme={null}
{
  "data": [
    {
      "id": "da_01H9Xy...",
      "status": "active",
      "transactionType": "cryptoToCrypto",
      "...": "..."
    },
  ],
  "hasMore": false,
  "cursor": null
}
```

## Failure Handling

If a transaction fails after the deposit is detected, OMS fires a `transaction.cryptoToCrypto.failed` webhook with an `error` object:

```json theme={null}
{
  "id": "whk_evt_01H9Xw3...",
  "event": "transaction.cryptoToCrypto.failed",
  "createdAt": "2024-01-15T14:31:00Z",
  "data": {
    "id": "txn_01H9Xd...",
    "type": "cryptoToCrypto",
    "status": "failed",
    "subStatus": "failed.onChainRevert",
    "error": {
      "code": "onChainRevert",
      "message": "Unable to deliver funds to destination wallet"
    },
    "...rest of transaction object..."
  }
}
```

If OMS successfully refunds the crypto back to the sender, you'll receive a `transaction.cryptoToCrypto.refundCompleted` webhook. If the refund itself fails, you'll receive `transaction.cryptoToCrypto.refundFailed`.

## Compliance Review

In some cases, a transaction may be held for compliance review. This fires a developer-only webhook (not forwarded to customers):

```json theme={null}
{
  "id": "whk_evt_01H9Xw4...",
  "event": "transaction.cryptoToCrypto.underReview",
  "createdAt": "2024-01-15T14:30:10Z",
  "data": {
    "id": "txn_01H9Xd...",
    "type": "cryptoToCrypto",
    "status": "processing",
    "subStatus": "processing.underReview",
    "...rest of transaction object..."
  }
}
```

The transaction remains in `processing` status during review. Once resolved, it proceeds to `completed` or `failed` with the corresponding webhook.

## Summary: Webhook Events for Deposit Address Transactions

| Event                                        | When                                     |
| -------------------------------------------- | ---------------------------------------- |
| `transaction.cryptoToCrypto.processing`      | Deposit detected, transaction created    |
| `transaction.cryptoToCrypto.completed`       | Funds delivered to destination           |
| `transaction.cryptoToCrypto.failed`          | Delivery failed                          |
| `transaction.cryptoToCrypto.refundCompleted` | Refund sent back to sender               |
| `transaction.cryptoToCrypto.refundFailed`    | Refund attempt failed                    |
| `transaction.cryptoToCrypto.underReview`     | Under compliance review (developer-only) |

## Key Differences from Quote → Transaction Flow

Deposit Addresses differ from the standard Quote → Transaction flow in several ways:

* **No amount upfront.** The Quote flow requires a known amount to generate pricing. Deposit Addresses handle "send any amount" scenarios.
* **No Quote object.** Auto-created transactions have `quote: null`. Pricing is calculated when the deposit arrives.
* **Fee visibility via `omsFeeSchedule`.** Since there's no Quote with exact pricing, the Deposit Address response includes `omsFeeSchedule` so developers know the fee structure in advance.
* **Percentage-only developer fees.** Fixed USD fees aren't supported because the deposit amount is unknown until arrival.
* **Reusable.** A single Deposit Address produces unlimited transactions over its lifetime. Quotes are one-time-use.
* **Transactions start at `processing`.** There's no `open` → `accepted` step. The transaction goes straight to `processing` when the deposit is detected.
