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

# Account model

> OMS supports custodial, non-custodial, and agentic custody models. This page covers the account types used by the custodial model.

OMS supports flexible custody models. Pick the model that fits your product; the rest of the OMS API (transactions, quotes, compliance, on-ramps and off-ramps) works the same across all three.

| Model                                           | Key custody                 | Built for                                            |
| ----------------------------------------------- | --------------------------- | ---------------------------------------------------- |
| [Custodial](/wallets/custodial-wallets)         | OMS holds the keys          | Regulated fintech, neobanks, and remittance products |
| [Non-custodial](/wallets/non-custodial-wallets) | The user holds the keys     | Consumer apps where users control their own funds    |
| [Agentic](/wallets/agentic-wallets)             | The agent holds scoped keys | Autonomous agents with policy-based spending limits  |

A single product can combine them: custodial for fiat flows and compliance, non-custodial for user-controlled on-chain assets, agentic for autonomous payments.

The remainder of this page covers the account types used by the **custodial** model. For non-custodial and agentic wallets, see [OMS wallets](/wallets/overview).

## Custodial wallets

The primary balance store. OMS manages private keys, with no end-user signing and no wallet SDKs required. All operations are server-to-server API calls.

```
Wallet
├── id: "wlt_..."
├── object: "wallet"
├── customerId: "cst_..."
├── asset: "usdc"
├── chain: "polygon"
├── address: "0x..."              (on-chain address)
├── blockchainAsset: { ... }      (protocol / chainId / tokenId)
├── type: "internal"              (internal = OMS-managed)
└── status: "active"              (active → suspended → closed)
```

Each custodial wallet holds a single asset on one chain and has an on-chain `address`. The `type` field is `internal` for OMS-managed wallets. `blockchainAsset` resolves the on-chain identity of the asset (protocol, chain ID, and token ID).

**Creating a wallet:** `POST /customers/{customerId}/wallets` with `asset` and `chain`. Returns the created wallet record.

**Listing wallets:** `GET /customers/{customerId}/wallets` returns the customer's wallets, one per asset and chain.

**Reading a balance:** `GET /wallets/{walletId}/balance` returns the wallet's current `balance` for its asset and chain, along with an estimated value in the requested currency.

**Funding a wallet:** Send crypto directly to the wallet's `address`, or use the on-ramp flows (cash-in, virtual accounts, deposit addresses) to convert fiat.

**Multiple wallets:** A customer can have more than one wallet, for different currencies, use cases, or segregation needs.

<Note>
  At launch, OMS custodial wallets are `internal` (OMS-managed). Embedded wallets, provisioned through the same customer endpoint, are planned for a later release.
</Note>

## Virtual accounts

A bank account number wired to a customer's wallet. Fiat deposits auto-convert to crypto.

```
Virtual Account
├── id: "va_..."
├── customerId: "cst_..."
├── destination: { ... }          (the wallet that receives the converted crypto)
└── bankDetails: {
     domestic: { accountNumber, routingNumber, ... },
     swift: { accountNumber, bic, memo, ... }
   }
```

Give your customers the `bankDetails` to display in your UI (null until the underlying deposit account is provisioned). A transfer to that account number delivers crypto to the configured wallet. When funds arrive, OMS creates a `fiatAccountToCrypto` transaction directly in `processing`.

Virtual accounts are managed through the API: create with `POST /virtual-accounts`, list with `GET /virtual-accounts`, read and update with `GET`/`PATCH /virtual-accounts/{id}`. Deletion is asynchronous: `DELETE /virtual-accounts/{id}` returns `202` and initiates closure of the underlying deposit account, and the status finalizes to `deleted` once it closes. A sandbox `POST /virtual-accounts/{id}/simulate` endpoint exercises the inbound flow. See [Virtual accounts](/payments/virtual-accounts).

## Deposit addresses

A reusable on-chain address wired to a fiat destination. On-chain deposits auto-create a transaction.

```
Deposit Address
├── id: "da_..."
├── customerId: "cst_..."
├── destination: { ... }
└── depositInstructions: {
     address: "0x...",
     asset: "usdc",
     network: "polygon"
   }
```

Deposit addresses carry routing configuration, so any deposit to the inlet address is converted and delivered to the configured fiat destination. They are the pattern for "accept any amount from any sender" on-ramp flows. When funds arrive, OMS creates a `cryptoToFiatAccount` transaction directly in `processing`.

Deposit addresses are managed through the API: create with `POST /deposit-addresses` (the `destination` is a registered bank external account), list with `GET /deposit-addresses`, read and update with `GET`/`PATCH /deposit-addresses/{id}`. There is no delete. `depositInstructions` is null until provisioning populates the OMS-owned inlet address, and re-pointing the `destination` to a healthy external account recovers an `inactiveActionRequired` address to `active`. Deposit addresses must be enabled for your project: contact us to enable them. A sandbox `POST /deposit-addresses/{id}/simulate` endpoint exercises the inbound flow. See [Deposit addresses](/payments/deposit-addresses).

## External accounts

Off-platform bank accounts, external wallets, and debit cards, referenced on a quote by their ID. A quote's source is always an OMS wallet or a card, so banks are destinations. Each external account is referenced by an ID whose prefix identifies the account type:

| Prefix          | Type                                           |
| --------------- | ---------------------------------------------- |
| `ext_card_`     | Debit card                                     |
| `ext_bankUs_`   | US bank account (ACH, same-day ACH, wire, RTP) |
| `ext_bankIban_` | IBAN bank account (international, SWIFT)       |
| `ext_bankCa_`   | Canadian bank account                          |
| `ext_wlt_`      | External wallet                                |

Register external accounts with `POST /external-accounts`. The body specifies an `owner` (a customer, or one of the customer's counterparties), a `type` (`bankUs`, `bankIban`, `bankCanada`, `card`, or `walletExternal`), and exactly one per-type details object matching the `type`; debit cards register through this same endpoint. List with `GET /external-accounts` (requires `customerId`, with an optional `counterpartyId` filter), update `label` and `metadata` with `PATCH`, and remove with `DELETE`. When delivering to a raw on-chain wallet, a quote can also pass a `blockchainAddress` directly instead of an `ext_wlt_` ID.

<Note>
  External accounts are not OMS-managed balances. OMS never holds funds in an external account; it is only a source or destination reference on a transaction.
</Note>

## Forward-looking

Embedded custodial wallets, provisioned alongside the internal wallets available today, are planned for an upcoming release.
