cryptoToFiatAccount), or forwarded as crypto to a registered external wallet (cryptoToCrypto). No developer action is required after the address is provisioned, unless the address only accepts deposits from registered sender wallets (see Sender wallet registration).
Deposit addresses are persistent. OMS keeps them active until they are frozen or closed.
How it works
Once a deposit address is provisioned, you display its onchain address to the customer. When a supported stablecoin arrives at that address, OMS:- Detects the inbound transfer on the source chain.
- Creates a transaction whose
precursoris{ "type": "depositAddress", "id": "da_..." }. Dereference the deposit address by thatidfor its inlet address and instructions. - Moves the transaction directly to
processing(there is no quote step, because pricing cannot be locked before the funds arrive). - Delivers the funds to the configured destination, converting them to fiat first when the destination is a bank account or fiat wallet.
Creating a deposit address
Create a deposit address withPOST /deposit-addresses:
The
201 response returns the deposit address with depositInstructions carrying the accepted asset and network. The onchain address is left out until the provider issues it; a provider that issues it during the create call returns it in the 201 response, and otherwise the deposit address moves from pending to active once the address is issued.
Deposit instructions
ThedepositInstructions field carries the details to display in your UI. asset and network are present from creation, and address is present once the provider issues it:
Crypto sent to
address is delivered to the configured destination.
The OMS-managed wallet that backs a deposit address is reserved for that address’s auto-conversion flow. Referencing the same custodial wallet on a quote, a transaction, or a cash-in is refused with
422 WalletBoundToCustodialFlow. The wallet is also filtered out of a project-wide wallet listing so it does not appear as an independent balance. Use a different wallet for those flows.Sender wallet registration
Some deposit addresses accept a deposit only from a sender wallet you have registered in advance. The deposit address response tells you which kind you have:requiresCounterpartyWalletRegistration is present and true when each sender’s wallet must be registered as a walletExternal external account under the deposit address’s customer before it deposits.
provider is absent too. Read it from each deposit address rather than caching one value for your project.
When the field is true, register each sender’s wallet with POST /external-accounts as a walletExternal account owned by the customer, or by one of the customer’s counterparties when someone else is sending, before you share depositInstructions.address. An EVM address registered once covers every EVM chain. The deposit addresses guide walks through this.
A deposit from an unregistered wallet still arrives, but OMS cannot attribute it. Its transaction moves to awaitingAction with subStatus: awaitingAction.awaitingSenderAttribution and a hold naming the wallet to register:
walletExternal account for hold.match.address on hold.match.network releases the deposit, and the transaction continues to processing. Release is asynchronous; see Released sender-attribution holds. If no matching account is registered by hold.deadline, the transaction fails with failed.attributionTimeout.
Forward deposits to a wallet
A deposit address can forward inbound crypto to a wallet instead of a bank account. Set thedestination to a registered walletExternal external account, referenced by its ext_ ID. Raw blockchain addresses are not accepted, and a walletCrypto destination is rejected with 422 DestinationWalletCryptoNotSupported.
cryptoToCrypto transaction that delivers the funds to the wallet. The destination network must be one the deposit address’s provider serves, or the create is rejected with 422 DestinationNetworkUnsupported.
To forward deposits to a custodial wallet owned by another customer in your project, such as an omnibus account, register that wallet’s address as a walletExternal external account under the depositing customer and use its ext_ ID. OMS settles the delivery as an internal ledger movement, with no onchain transfer and no network fee.
Payout memo
A deposit address destination can carry an optional payment memo that OMS delivers to the beneficiary’s bank with each payout. Setdestination.details.memo on create or on a PATCH that replaces destination.
The published schema’s
paymentMemo pattern is the union of the ACH addenda and ISO 20022 character sets. The published pattern is deliberately permissive so a client validating locally will not reject a memo the server would have accepted; the narrower per-rail rules above are still enforced server-side on write, with a 422 on violation.
OMS reads the memo when it builds each payout, so an edit applies only to payouts built after it. A payout already sent keeps the memo it was built with. Set memo to null, omit it, or send only whitespace to use no memo of your own; the payout then carries the memo OMS composes for the rail, if any.
A memo outside its rail’s character set or length is rejected server-side with 422. The CAD local leg of bankCanada has no remittance field, so a non-empty memo there is rejected with 422 MemoNotSupported.
pattern and maxLength describe the normalized memo: the server trims leading and trailing whitespace before validating. A whitespace-only memo, or a 140-character memo wrapped in spaces, is accepted after trimming even though a strict local check against the raw string would reject it.memo field is available on virtual account bank destinations, which offer no rtp rail, and on quotes with a walletFiat source or with a walletCrypto source paying a bankUs destination. Any other quote corridor rejects a non-empty memo with 422 MemoNotSupported.
ACH company discretionary data
For abankUs destination with network: "ach" or network: "achSameDay", set an optional destination.details.companyDiscretionaryData. OMS carries the value in the NACHA batch header on every outbound ACH payout from the deposit address. This is the originator’s internal metadata and never reaches the beneficiary; it is distinct from memo, which does. Responses report the value as payout.companyDiscretionaryData.
Destination and payout rail
In responses,destination is the typed instrument deposits are paid out to, with type, id, asset, and a details block. A bank account destination carries no rail; the rail and ACH options are reported next to it in payout:
payout.rail is the rail payouts move on. On ach and achSameDay, payout also carries secCode, derived from the destination owner’s and the customer’s entity type and left out while either is unknown, and companyDiscretionaryData when you set it. A crypto destination has no payout.
Payout origin
Deposit address responses and webhook payloads carry a top-levelpayoutOrigin. It describes whose name a payout from the address is sent under: the holder stored when the deposit address was created, with the customer’s legal name resolved onto accountHolderName where applicable. A walletFiat destination or an address with no payout destination carries no payoutOrigin. See the shared payout origin shape.
Customer reference
Deposit addresses carry acustomer reference resolving the owning customer in one hop:
destination from its details block; see Rendering an instrument and the shared customer reference.
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 (default 50, maximum 100), startingAfter, and endingBefore. Pass a page’s nextCursor as startingAfter for the next page, or its previousCursor as endingBefore for the previous one. Cursors are opaque; do not parse them.
GET /deposit-addresses/{depositAddressId} fetches a single deposit address by ID.
Updating
PATCH /deposit-addresses/{depositAddressId} accepts destination (re-point to a different destination), returnDestination, label, metadata, and sponsorGas; any other key in the body is rejected with 400.
Re-pointing destination to a healthy 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.
Deposit address responses also carry a read-only returnDestinationTypes array that lists the walletCrypto and walletExternal return targets this address accepts, derived from the issuing provider and depositInstructions.network. An empty array means no return destination can be configured.
A deposit address is permanent: there is no delete endpoint. The onchain address is published to senders and can receive a deposit at any time, so removing the record would strand any funds that arrive afterwards with nothing to route them to. The terminal closed status is reached through the provider’s own lifecycle or an operator action, and a closed address stays retrievable by ID. To stop using one, stop handing its address to senders.
Statuses
Simulating inbound deposits
Sandbox deposit addresses accept testnet transfers. Send testnet stablecoins to the address from a public testnet faucet or wallet, and OMS reacts to the onchain confirmation as it would to a mainnet deposit: the transaction is auto-created and moves through the transaction lifecycle, firing the same webhook events. There is no simulation endpoint for deposit addresses. Virtual accounts have one (see Simulating inbound deposits) because bank rails have no public testnet.Webhook events
Each deposit also creates a transaction that fires its own
transaction.* and transfer.* events. See the webhook events catalog.
Deposit address vs. virtual account
Both are persistent auto-route configurations. The difference is which side is fiat:Related
- Deposit addresses guide: walkthrough of the inbound flow and webhook handling
- Virtual accounts: the fiat equivalent, a bank account number that auto-converts to crypto
- External accounts: registering the bank account or wallet a deposit address delivers to
- Transaction lifecycle: statuses, sub-statuses, and webhook events for the auto-created transaction
- Failed transactions and returns: where inbound crypto goes when the payout cannot complete, and how to configure it