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

# Customer onboarding

> How to register a customer, collect identity verification, and provision their first wallet.

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

This guide walks through registering a new end user in OMS, acquiring the endorsements required to unlock money movement, and provisioning a custodial wallet. Every transaction, deposit address, and virtual account in OMS belongs to a customer record, so this is the starting point for any integration.

## Architecture

<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"}}>Customer onboarding 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</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"}}>\{id: "cst\_...", endorsements: \[]}</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"}}>User</span>
    <span style={{fontSize:"13px",color:"#141635"}}>Collect identity documents</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"}}>User</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={{fontSize:"13px",color:"#141635"}}>KYC/KYB data</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"}}>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={{fontSize:"13px",color:"#141635"}}>Submit verification (KYC flow)</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={{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: customer.endorsement.granted</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"}}>7</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}/wallets</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"}}>8</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"}}>Polygon</span>
    <span style={{fontSize:"13px",color:"#141635"}}>Derive wallet 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"}}>9</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"}}>\{id: "wlt\_...", 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"}}>10</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}/external-accounts (optional)</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"}}>11</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"}}>\{id: "cpUsBank\_..."}</span>
  </div>
</div>

***

## Prerequisites

* An OMS API key.
* Webhook subscriptions configured for `customer.endorsement.*` events in the OMS Dashboard.

***

## Step 1: Create a customer

Register the end user with a `POST /customers` call. OMS creates the record and returns an ID.

### Request

```text theme={null}
POST /v0.9/customers
Authorization: Bearer {token}
Idempotency-Key: cst-alice-001
Content-Type: application/json
```

```json theme={null}
{
  "type": "individual",
  "firstName": "Alice",
  "lastName": "Martin",
  "email": "alice@example.com",
  "phone": "+12125551234",
  "birthDate": "1990-05-15",
  "nationality": "US",
  "externalId": "usr_7890",
  "signedAgreement": true
}
```

**Required fields:** `type` must be `individual`. Only the individual customer type is supported in the v0.9 API. All other fields are optional but needed before endorsements can be granted.

**`externalId`** is the recommended way to link the OMS customer record to your internal user ID. Pass it at creation to avoid a separate update call later.

### Response, `201 Created`

```json theme={null}
{
  "id": "cst_01H9Xa...",
  "object": "customer",
  "type": "individual",
  "firstName": "Alice",
  "lastName": "Martin",
  "email": "alice@example.com",
  "externalId": "usr_7890",
  "status": "active",
  "endorsements": [],
  "createdAt": "2024-01-15T10:00:00Z"
}
```

The `endorsements` array is empty at creation. No money movement is possible until endorsements are granted.

***

## Step 2: Collect identity and get endorsements

OMS uses an endorsement model to gate access to financial operations. The three endorsements are:

| Endorsement     | Unlocks                                                |
| --------------- | ------------------------------------------------------ |
| `basic`         | Standard operations. Required for all transactions.    |
| `cryptoCustody` | Crypto custody and advanced wallet features.           |
| `usd`           | USD stablecoin operations, including virtual accounts. |

Your KYC/KYB flow submits identity documents to OMS for review. When verification completes, OMS grants the appropriate endorsements and fires a webhook.

### Webhook: `customer.endorsement.granted`

```json theme={null}
{
  "event": "customer.endorsement.granted",
  "data": {
    "id": "cst_01H9Xa...",
    "object": "customer",
    "endorsements": ["basic", "cryptoCustody", "usd"]
  }
}
```

Check `endorsements` in this payload to confirm which operations are now available for the customer.

***

## Step 3: Provision a wallet

Once the customer has at least the `cryptoCustody` endorsement, create a custodial wallet. OMS derives the onchain address and manages the keys.

### Request

```text theme={null}
POST /v0.9/customers/cst_01H9Xa.../wallets
Authorization: Bearer {token}
Idempotency-Key: wlt-alice-polygon-001
Content-Type: application/json
```

```json theme={null}
{
  "asset": "usdc",
  "chain": "polygon"
}
```

The customer is identified in the path. The request body declares the `asset` and `chain` the wallet will hold.

### Response, `201 Created`

```json theme={null}
{
  "id": "wlt_01H9Xb...",
  "object": "wallet",
  "customerId": "cst_01H9Xa...",
  "address": "0xBEEF4a2c891D56e72b67a3f21d0cf94F1D7c5911",
  "asset": "usdc",
  "chain": "polygon",
  "status": "active",
  "createdAt": "2024-01-15T10:01:00Z"
}
```

The `address` is the onchain address where deposits for this customer will be received. Store the `wlt_` ID, you will use it as the source or destination in quotes.

***

## Step 4: Add an external bank account (optional)

<Note>
  External bank account and card registration 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 external bank account and card registration is available.
  </Card>
</Note>

The pattern below describes the intended shape so you can plan your integration. The schema lookup (`GET /external-accounts/schemas`) and the registration call (`POST /customers/{id}/external-accounts`) are not yet available in the OMS API.

If the customer will receive fiat payouts, register their bank account as an external account. Use `GET /external-accounts/schemas` to get the required fields for the target country and currency.

### Get the schema

```text theme={null}
GET /v0.9/external-accounts/schemas?country=US&currency=usd
Authorization: Bearer {token}
```

The schemas endpoint accepts `country` and `currency` as optional query params. The response describes which fields each supported rail requires. Render those fields as a form and collect the data from the customer.

### Register the account

```text theme={null}
POST /v0.9/customers/cst_01H9Xa.../external-accounts
Authorization: Bearer {token}
Content-Type: application/json
```

```json theme={null}
{
  "type": "usBank",
  "network": "ach",
  "owner": {
    "name": "Alice Martin",
    "type": "individual"
  },
  "bankDetails": {
    "accountNumber": "000123456789",
    "routingNumber": "021000021",
    "accountType": "checking",
    "bankName": "Chase"
  }
}
```

Per-rail bank fields live inside `bankDetails` and are validated against the response from `GET /external-accounts/schemas`. The `network` value (`ach`, `wire`, `swift`, etc.) declares the rail.

```json theme={null}
{
  "id": "cpUsBank_01H9Xs...",
  "object": "counterparty.usBank",
  "customerId": "cst_01H9Xa...",
  "type": "usBank",
  "network": "ach",
  "status": "verified",
  "owner": { "name": "Alice Martin", "type": "individual" },
  "bankDetails": {
    "accountNumber": "****6789",
    "routingNumber": "021000021",
    "accountType": "checking",
    "bankName": "Chase"
  },
  "createdAt": "2024-01-15T10:02:00Z"
}
```

The `cpUsBank_` ID identifies the bank account for use elsewhere in OMS.

***

## What's next

With a customer, wallet, and optional external account in place, you can:

* Fund the wallet with a [cash-in](/api-reference/guide-cash-in) at a retail location.
* Set up a [virtual account](/payments/guides/virtual-accounts) to accept recurring ACH deposits (early access).
* Create a [deposit address](/payments/guides/deposit-addresses) to receive crypto from external wallets (early access).
* Send funds out of the wallet with the [send guide](/payments/guides/crypto-to-fiat): crypto destinations today, bank payouts in early access.
