Skip to main content
In this tutorial you will use the OMS sandbox to take one customer from nothing to a funded wallet. You will authenticate, create a customer, give them a USDC wallet on Polygon, fund it with a simulated cash deposit, and watch the resulting transaction complete. Every request runs against https://sandbox-api.polygon.technology/v0.13, so no real money moves. You need curl and sandbox API credentials. The same requests work in production against https://api.polygon.technology/v0.13 with production credentials.
1

Get sandbox credentials

OMS is in early access. Request access to receive sandbox credentials.

Request OMS access

Submit your details to get sandbox credentials.
Once approved, open the OMS Dashboard and go to API Keys. Generate a secret key and copy both the key (it starts with sk_sdbx_) and its secret. The secret is shown only once.
Treat your API secret like a password and keep it on your server. If it is ever exposed, revoke the key in the dashboard and generate a new one.
2

Exchange your key for a bearer token

You never send the API key on ordinary requests. Exchange the key and secret for a bearer token:
Notice that projectMode is sandbox. The token is valid for 60 minutes. Send it on every other request in this tutorial:
Every other POST in this tutorial also needs an Idempotency-Key header. Use a new UUID for each new request, and send the same key again only to retry that exact request.
If a later request returns 401, your token has expired. Run this step again and continue. If POST /auth/token returns 429, wait for the number of seconds in the Retry-After header.
3

Create a customer

Every wallet, quote, and transaction belongs to a customer. Create an individual customer with the identifying details OMS needs to provision a wallet and accept cash:
You get back the customer with 201:
Copy the cst_ ID; you use it in every remaining step. The birthDate, residentialAddress, and identifyingInformation you sent are write-only, so they never appear in responses. Sandbox runs the same onboarding checks as production, so wait until the customer’s status is active before you continue (poll GET /customers/{customerId} or listen for the customer.* webhooks). See Sandbox and testing if a check rejects your data.If the response is 202 with "status": "processing" instead, onboarding is still running. Wait a few seconds, then send the identical request with the same Idempotency-Key. You get 202 again while it runs and 201 with the customer once it is done.
Use these fields exactly as shown. Projects that require identity verification for custodial wallets need email, birthDate as YYYY-MM-DD, a US phone in E.164 format (+1 and 10 digits), an ssn entry in identifyingInformation, and a US residentialAddress with a two-letter state. Addresses in New York, Texas, and Vermont are not supported on these projects. Avoid the word “test” in names and emails, which can trip fraud checks.
If the request fails with 400, read the cause field in the error body for the specific reason, and quote the response’s Request-Id header if you contact support. Fields the API does not recognize are ignored rather than rejected, so check spelling carefully. For business customers and the full onboarding lifecycle, see Customer onboarding.
4

Create a USDC wallet

Give the customer a custodial wallet that holds USDC on Polygon. OMS manages the keys, so there is nothing for the customer to sign.
Copy the wlt_ ID. In sandbox the address lives on Polygon Amoy, the Polygon testnet.If the response is 202 instead, the wallet is still being provisioned. Poll the URL in the Location header (GET /wallets/operations/{operationId}) until its status is complete, then take the wallet ID from walletId.
5

Create a cash-in

Now fund the wallet with cash. First find a retail location that accepts cash deposits:
Use the cash provider value enabled for your project. From the results, pick a location with buyAllowed: true and copy its id (loc_...) and cashLocationReference.Create the cash-in. The customer will deposit about $100.00, and the USDC goes to the wallet you just created:
The cashInCode is what a real customer would show at the counter before expiresAt. The pricing amounts are estimates until cash is actually deposited. Copy the ci_ ID and the cashInCode.
6

Simulate the cash deposit

In sandbox, two calls stand in for the customer at the counter. First, present the code:
The response carries a confirmationId. Pass it to hand over the cash:
OMS now treats the cash as received and creates a transaction that converts it to USDC and delivers it to the wallet.
7

Watch the transaction complete

Read the cash-in again:
Notice that it now has a transactionId (txn_...) and a status of processing or completed. Read that transaction:
The transaction’s precursor is { "type": "cashIn", "id": "ci_01H9Xc..." }. Its status moves from processing to completed, and subStatus shows the step it is on, such as processing.initiated or completed.settled. Repeat the read every few seconds until it reaches completed.Finally, read the wallet with GET /wallets/wlt_01H9Xb.... The balances entry for usdc now shows the deposit.You have authenticated, onboarded a customer, provisioned a wallet, and completed a cash-to-crypto transaction.
8

Receive webhooks instead of polling

Polling works for a first run. In your application, let OMS tell you when things change. Register a public HTTPS endpoint:
The response contains webhook and a signingKey. Store the signingKey now. Later reads do not return it. ["*"] subscribes to every event. Run another cash-in and your endpoint receives events such as these:Each event’s data.resource is the full resource as a GET returns it, so you rarely need to read it again. Before acting on an event, verify its Webhook-Signature header (t=<timestamp>,v1=<signature>): compute HMAC-SHA256 with your signingKey over <t>.<raw body>, compare in constant time, and reject events whose timestamp is more than five minutes old. See Receiving webhooks for a full handler and Webhook events for the catalog.

What’s next

Crypto to fiat

Register a bank account, quote, and pay out from the wallet to the customer’s bank.

Cash-in

Location search, code refresh, expiry, and the rest of the cash deposit flow.

Fiat to crypto

Fund wallets from bank transfers and virtual accounts.

API reference

Core concepts and the full endpoint reference.