Skip to main content
A deposit address is a reusable on-chain address assigned to a customer. When crypto arrives at the address, OMS automatically creates and executes a transaction that converts it and pays out to a configured fiat destination (cryptoToFiatAccount). No developer action is required after the address is provisioned. Deposit addresses are persistent. OMS keeps them active until they are frozen or closed.
Deposit addresses must be enabled for your project before you can create them, and the customer must be provisioned for them. To get set up, share your use case below.

Contact us

Tell us about your on-ramp flow and we’ll enable deposit addresses for your project.

How it works

Once a deposit address is provisioned, you display its on-chain address to the customer. When a supported stablecoin arrives at that address, OMS:
  1. Detects the inbound transfer on the source chain.
  2. Creates a transaction with a typed precursor of depositAddress, carrying the depositAddressId and its deposit instructions.
  3. Moves the transaction directly to processing (there is no quote step, because pricing cannot be locked before the funds arrive).
  4. Converts the incoming crypto and delivers it to the configured fiat destination.
The resulting transaction carries sourceToDestination: "cryptoToFiatAccount" and follows the standard transaction lifecycle, including webhook events.

Creating a deposit address

Create a deposit address with POST /deposit-addresses:
{
  "customerId": "cst_...",
  "expectedSourceAsset": "usdc",
  "expectedSourceNetwork": "ethereum",
  "destination": {
    "type": "bankUs",
    "details": {
      "id": "ext_bankUs_...",
      "asset": "usd",
      "network": "ach",
      "accountHolder": "customer"
    }
  },
  "label": "Inbound USDC deposits"
}
FieldRequiredMeaning
customerIdYesThe customer the address belongs to.
expectedSourceAssetYesThe inbound stablecoin the address expects: usdc or usdt (lowercase).
expectedSourceNetworkYesThe chain the address accepts funds on (for example, ethereum or base).
destinationYesA registered bank-type external account (bankUs, bankIban, or bankCanada) on the standard side shape. OMS validates the details (asset, network, and accountHolder) against the resolved external account.
sponsorGasNoWhen true (the default), OMS absorbs the on-chain gas cost for the destination delivery. Only true is currently supported.
label, metadataNoA display label and free-form string metadata.
The 201 response returns the deposit address with depositInstructions: null. Provisioning populates the OMS-owned inlet address asynchronously, and the address moves from pending to active once the instructions are ready.

Deposit instructions

The depositInstructions field carries the details to display in your UI. It is null until provisioning completes:
{
  "address": "0xabc123...",
  "asset": "usdc",
  "network": "ethereum",
  "expiresAt": null
}
FieldMeaning
addressThe OMS-owned on-chain inlet address for this deposit address. Give this to your customer.
assetThe stablecoin the address accepts (matches expectedSourceAsset).
networkThe chain the address accepts funds on (matches expectedSourceNetwork).
expiresAtReserved for a future provider-imposed inlet expiry. Null today.
Crypto sent to address is converted and paid out to the configured fiat destination.

Listing and retrieving

GET /deposit-addresses lists deposit addresses across every customer in your organization. Both filters are optional: customerId scopes the list to one customer, and status to one lifecycle state. Paginate with limit, startingAfter, and endingBefore; each page returns nextCursor, previousCursor, and hasMore. GET /deposit-addresses/{depositAddressId} fetches a single deposit address by ID.

Updating

PATCH /deposit-addresses/{depositAddressId} accepts destination (re-point to a different bank-type external account), label, metadata, and sponsorGas; any other key in the body is rejected with 400. Re-pointing destination to a healthy bank external account recovers a deposit address from inactiveActionRequired back to active. A re-point on an already active address updates the target without a status transition. There is no delete endpoint for deposit addresses.

Statuses

StatusMeaning
pendingCreated; OMS is provisioning the on-chain inlet address. depositInstructions is null.
activeProvisioned and accepting deposits.
frozenTemporarily suspended; inbound deposits are not processed.
closedPermanently closed.
failedProvisioning failed; failureReason identifies the cause.
inactiveActionRequiredThe destination external account is no longer usable. Re-point destination to a healthy account to recover to active.

Simulating inbound deposits

In sandbox, you can simulate an inbound transfer to test your webhook and reconciliation flows without moving real funds. This endpoint is available in non-production environments only and returns 404 in production. POST /deposit-addresses/{depositAddressId}/simulate with the amount to simulate:
{
  "amount": { "value": "5000" }
}
The value is the stablecoin amount in cents (greater than 0 and at most 100000). The currency and network are resolved server-side from the deposit address. The response echoes the simulated deposit and returns a synthetic transactionHash you can correlate against the webhook:
{
  "depositAddressId": "da_...",
  "amount": { "value": "5000", "currency": "usdc" },
  "network": { "...": "..." },
  "transactionHash": "0x...",
  "status": "submitted",
  "submittedAt": "2026-01-15T10:32:00Z"
}
Use the simulate endpoint to exercise the full auto-created transaction path in sandbox: the simulated inbound funds create a cryptoToFiatAccount transaction just as a real deposit would.

Deposit address vs. virtual account

Both are persistent auto-route configurations. The difference is which side is fiat:
Deposit addressVirtual account
Incoming fundsCrypto (on-chain)Fiat (bank rail)
Deposit detailsOn-chain inlet addressBank account number and routing
DirectioncryptoToFiatAccountfiatAccountToCrypto
DestinationFiat accountCrypto wallet