Skip to main content
Custodial wallets are managed wallets where OMS holds and secures private keys on behalf of your customers. Your application makes server-to-server API calls with no user signing and no blockchain interaction. This model suits regulated financial products, enterprise deployments, and products where users should not be responsible for their own keys. There are two kinds. A crypto wallet (walletCrypto) holds one stablecoin on one network; to hold more than one asset or network, create one wallet each under the same customer. A fiat wallet (walletFiat) holds a USD balance at a partner bank. Both belong to a customer and act as sources and destinations in quotes and transactions.

When to use custodial wallets

The two models can be combined in a single product: see Link a non-custodial wallet. To create your first wallet step by step, follow the custodial wallets quickstart.

Object

type is walletCrypto for a crypto wallet or walletFiat for a fiat wallet. A crypto wallet carries its network and its onchain address, which is omitted until the custody provider reports one. A fiat wallet has no network or address, and its balances entries carry no network. provider is the legal entity holding the wallet’s assets; treat it as a free-form string. routing reports whether a deposit address or virtual account has claimed the wallet; see Claimed wallets. balances lists the wallet’s balance per asset with a USD estimate. Each balance is a decimal string at the asset’s precision. A fiat wallet balance can be negative, for example after an ACH clawback, so render the sign as received.

Create a wallet

POST /wallets creates a wallet for a customer. Set type to custodial for a crypto wallet or fiat for a fiat wallet; the response reports the matching walletCrypto or walletFiat type.
A custodial create returns 201 with the wallet when it exists or is confirmed right away. When confirmation arrives later, it returns 202 with a Location header; poll GET /wallets/operations/{operationId} until its status is complete, then read the wallet by the operation’s walletId. A fiat wallet starts pending and moves to active once the bank opens the account. POST /wallets requires an Idempotency-Key header; a replay returns the same response, including the same operation Location.

Read, list, and update

  • GET /wallets/{id} returns one wallet, including its current balances.
  • GET /wallets lists wallets in the project, most recent first. Filter by customerId and by type (custodial, fiat, or noncustodial), or search with search. Page with limit and cursor. Claimed wallets are hidden unless you pass includeHidden=claimed.
  • GET /wallets?orderBy=balance ranks wallets by the USD estimate of their available balance, highest first; pass order=asc to reverse it. Wallets without a USD estimate sort last. The order uses live balances, so a balance that changes while you page can skip or repeat a wallet.
  • PATCH /wallets/{id} updates label only. An empty string clears it.
For a customer’s total across every wallet, use GET /customers/{id}/balance. See Customers. POST /customers/{customerId}/wallets/associate links an existing OMS Wallet non-custodial wallet to a customer. The request body carries an idToken issued for the wallet: the token’s subject identifies the wallet, so you never pass a wallet ID directly, and its audience must be your project.

Funding a wallet

Transaction history

List a wallet’s transactions with GET /transactions?walletId={id}. It returns every transaction where the wallet is the source or destination, crypto or fiat alike. See Transactions.

Claimed wallets

A wallet that a live deposit address or virtual account receives into is claimed by that resource. Every wallet carries a read-only routing object that reports this state:
A claimed wallet stays readable by ID, keeps its balance, and can still be updated. It cannot fund a withdrawal while the claim stands: POST /quotes and POST /transactions return 422 WalletClaimed (code 10357). GET /wallets omits claimed wallets unless you pass includeHidden=claimed. The customer’s aggregate balance still includes it. Deleting or closing the claiming virtual account or deposit address releases the wallet: claimStatus moves to released, the wallet reappears in the default listing, and it can fund withdrawals again. A deposit address’s or virtual account’s destination wallet is a payout target, not a claim. It stays listed and can fund a withdrawal. A custodial wallet that is a live virtual account’s walletCrypto destination still cannot be the destination of a second virtual account (409 VirtualAccountWalletInUse).

Webhook events

Routing claims and releases do not send an event.

Key operations

  • Virtual accounts: assign a bank account number that funds a destination
  • Deposit addresses: set up a monitored crypto address that routes to a destination
  • Transactions: move funds out of a wallet via crypto, bank transfer, or cash

Get access

Request custodial wallet access

Request access to OMS custodial wallet infrastructure.