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

# Custodial wallet quickstart

> Authenticate, create a customer, and provision an OMS custodial wallet with the API.

This quickstart provisions your first OMS custodial wallet through the API. You authenticate, create a customer to own the wallet, provision the wallet, and read its balance. OMS holds the keys, so there is no wallet SDK and no user signing.

<Note>
  Custodial wallets are in early access and require an OMS API key. [Request access](https://info.polygon.technology/get-early-access?utm_source=docs\&utm_medium=card\&utm_campaign=oms_access) if you do not have one yet.
</Note>

<Steps>
  <Step title="Get a bearer token">
    You do not send the API key directly on requests. Exchange the key and secret for a short-lived bearer token at `POST /auth/token`, then send that token as `Authorization: Bearer {accessToken}` on every other call.

    <CodeGroup>
      ```bash Sandbox theme={null}
      curl -X POST https://sandbox-api.polygon.technology/v0.10/auth/token \
        -H "Content-Type: application/json" \
        -d '{
          "apiKey": "{api_key}",
          "apiSecret": "{api_secret}"
        }'
      ```

      ```bash Production theme={null}
      curl -X POST https://api.polygon.technology/v0.10/auth/token \
        -H "Content-Type: application/json" \
        -d '{
          "apiKey": "{api_key}",
          "apiSecret": "{api_secret}"
        }'
      ```
    </CodeGroup>

    ```json theme={null}
    {
      "accessToken": "eyJhbGc...",
      "tokenType": "bearer",
      "expiresIn": 3600,
      "expiresAt": "2026-01-15T11:00:00Z"
    }
    ```

    The token is valid for 60 minutes. When a request returns `401`, exchange your key for a fresh token and retry. If `POST /auth/token` returns `429`, the endpoint is rate-limited: back off before retrying.
  </Step>

  <Step title="Create a customer">
    Every custodial wallet belongs to a customer record. Create one before provisioning a wallet. Only `type` is required; when you omit `endorsements`, OMS defaults to `cryptoCustody` and `usd` (which auto-includes `basic`). If you also plan to fund the wallet with fiat (the next-step cash or card flows), include the full set of identifying fields so the customer can be provisioned to move money, not just a name.

    <CodeGroup>
      ```bash Sandbox theme={null}
      curl -X POST https://sandbox-api.polygon.technology/v0.10/customers \
        -H "Authorization: Bearer {accessToken}" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: cst-wallet-quickstart-001" \
        -d '{
          "type": "individual",
          "firstName": "Jane",
          "lastName": "Smith",
          "email": "jane@example.com",
          "phone": "+12125551234",
          "birthDate": "1990-05-15",
          "nationality": "US",
          "residentialAddress": {
            "line1": "123 Main St",
            "city": "New York",
            "state": "NY",
            "country": "US",
            "zipCode": "10001"
          },
          "identifyingInformation": [
            { "type": "ssn", "issuingCountry": "US", "number": "123-45-6789" }
          ],
          "endorsements": ["cryptoCustody", "usd"]
        }'
      ```

      ```bash Production theme={null}
      curl -X POST https://api.polygon.technology/v0.10/customers \
        -H "Authorization: Bearer {accessToken}" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: cst-wallet-quickstart-001" \
        -d '{
          "type": "individual",
          "firstName": "Jane",
          "lastName": "Smith",
          "email": "jane@example.com",
          "phone": "+12125551234",
          "birthDate": "1990-05-15",
          "nationality": "US",
          "residentialAddress": {
            "line1": "123 Main St",
            "city": "New York",
            "state": "NY",
            "country": "US",
            "zipCode": "10001"
          },
          "identifyingInformation": [
            { "type": "ssn", "issuingCountry": "US", "number": "123-45-6789" }
          ],
          "endorsements": ["cryptoCustody", "usd"]
        }'
      ```
    </CodeGroup>

    ```json theme={null}
    {
      "id": "cst_01H9Xa...",
      "object": "customer",
      "type": "individual",
      "status": "active",
      "endorsements": [
        { "name": "basic", "status": "ACTIVE" },
        { "name": "cryptoCustody", "status": "ACTIVE" },
        { "name": "usd", "status": "ACTIVE" }
      ],
      "wallets": [],
      "createdAt": "2026-01-15T10:00:00Z"
    }
    ```

    Store the `cst_` ID. You pass it in the path when provisioning the wallet. PII fields (`birthDate`, `residentialAddress`, `ipAddress`, `identifyingInformation`) are write-only: OMS accepts them but never returns them. Only `individual` is supported for `type` today. Endorsement statuses use SCREAMING\_CASE (`INACTIVE`, `PENDING`, `ISSUES`, `ACTIVE`, `REJECTED`, `REVOKED_ISSUES`, `OFFBOARDED`).

    <Warning>
      A custodial wallet can be created for a name-only customer, but that customer cannot be provisioned to move fiat. If you later fund the wallet with a fiat-to-crypto flow, those calls fail because the customer is not provisioned for fiat. For USD and cash flows, provide a structured `residentialAddress`, `phone` (E.164), `birthDate`, and a government ID in `identifyingInformation` (for US customers, an `ssn` or `itin`) at creation, or add them later with `PATCH /customers/{customerId}`.
    </Warning>

    <Note>
      In sandbox, endorsements are auto-approved so you can provision and use wallets without a live KYC integration. Provisioning still reads the identifying fields above, so include them in sandbox too.
    </Note>
  </Step>

  <Step title="Provision a custodial wallet">
    Create the wallet with `POST /customers/{customerId}/wallets`. The customer ID goes in the path, and the body names the `asset` the wallet holds and the `chain` it lives on. OMS derives the on-chain address and manages the keys.

    <CodeGroup>
      ```bash Sandbox theme={null}
      curl -X POST https://sandbox-api.polygon.technology/v0.10/customers/cst_01H9Xa.../wallets \
        -H "Authorization: Bearer {accessToken}" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: wlt-quickstart-001" \
        -d '{
          "asset": "usdc",
          "chain": "polygon"
        }'
      ```

      ```bash Production theme={null}
      curl -X POST https://api.polygon.technology/v0.10/customers/cst_01H9Xa.../wallets \
        -H "Authorization: Bearer {accessToken}" \
        -H "Content-Type: application/json" \
        -H "Idempotency-Key: wlt-quickstart-001" \
        -d '{
          "asset": "usdc",
          "chain": "polygon"
        }'
      ```
    </CodeGroup>

    ```json theme={null}
    {
      "id": "wlt_01H9Xb...",
      "object": "wallet",
      "customerId": "cst_01H9Xa...",
      "type": "internal",
      "status": "active",
      "asset": "usdc",
      "chain": "polygon",
      "address": "0xBEEF4a2c891D56e72b67a3f21d0cf94F1D7c5911",
      "blockchainAsset": {
        "protocol": "evm",
        "chainId": "137",
        "tokenId": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
      },
      "createdAt": "2026-01-15T10:01:00Z"
    }
    ```

    The `address` is the wallet's on-chain Polygon address. The `wlt_` ID is what you reference as a source or destination in quotes and transactions. A custodial wallet is `internal` (OMS-managed) with a `status` of `active`. List a customer's wallets any time with `GET /customers/{customerId}/wallets`.
  </Step>

  <Step title="Read the wallet balance">
    Read a wallet's current balance any time with `GET /wallets/{walletId}/balance`.

    <CodeGroup>
      ```bash Sandbox theme={null}
      curl https://sandbox-api.polygon.technology/v0.10/wallets/wlt_01H9Xb.../balance \
        -H "Authorization: Bearer {accessToken}"
      ```

      ```bash Production theme={null}
      curl https://api.polygon.technology/v0.10/wallets/wlt_01H9Xb.../balance \
        -H "Authorization: Bearer {accessToken}"
      ```
    </CodeGroup>

    ```json theme={null}
    {
      "data": {
        "id": "wlt_01H9Xb...",
        "customerId": "cst_01H9Xa...",
        "address": "0xBEEF4a2c891D56e72b67a3f21d0cf94F1D7c5911",
        "asset": "usdc",
        "chain": "polygon",
        "currencyName": "USD Coin",
        "balance": "0.00",
        "estimatedBalanceValue": "0.00",
        "updatedAt": "2026-01-15T10:01:00Z"
      }
    }
    ```

    A freshly provisioned wallet starts at zero. Fund it with a fiat-to-crypto flow, then poll this endpoint or subscribe to transaction webhooks to track the balance.
  </Step>
</Steps>

## What's next

<CardGroup cols={2}>
  <Card title="Custodial wallets overview" icon="wallet" href="/wallets/custodial-wallets">
    When to use custodial wallets and how OMS secures keys.
  </Card>

  <Card title="Create a wallet (API reference)" icon="code" href="/api-reference/overview">
    Full request and response reference for `POST /customers/{customerId}/wallets`.
  </Card>

  <Card title="Fund a wallet" icon="coins" href="/payments/guides/fiat-to-crypto">
    Bring fiat into the wallet with the cash-in or virtual account flows.
  </Card>

  <Card title="Get started with OMS" icon="rocket" href="/payments/get-started">
    The end-to-end payments walkthrough, from customer to first transaction.
  </Card>
</CardGroup>
