Custodial Wallets require a business account. This recipe assumes your platform is already onboarded with Custodial Wallets enabled. If you’re interested or want to check whether this fits your use case, get in touch and our team will follow up.
https://api.cdp.coinbase.com/platform for the SDK, or cdp env production for the CLI) and use a production API key.
Flow of funds

Prerequisites
- Your entity is onboarded (KYB’d) with Custodial Wallets enabled. See the Custodial Wallets overview.
- The CDP CLI or TypeScript SDK installed and pointed at Sandbox. Both require Node.js 22 or later.
Account structure
Install and configure
- CDP CLI
- TypeScript SDK
Pick one path, the CDP CLI or the TypeScript SDK, and follow that tab in every step. Each CLI command runs on its own. The SDK snippets build up a single
main.ts file, so the complete runnable script is at the end under Run the SDK flow as scripts.Copying these commands: anything shown as a placeholder — values ending in
... (like account_...) or wrapped in <ANGLE_BRACKETS> — must be replaced with your real value before running. Use each code block’s copy button; if you paste through a rich-text editor (Google Docs, Notes), straight quotes " can turn into curly " and the shell will hang on a dquote> prompt.1. Create your treasury account
Your entity-owned USD account. Omitting an owner makes the account entity-owned.- CDP CLI
- TypeScript SDK
entity_:2. Fund the treasury with USD
In Sandbox, there are no real wires, so add a USD test balance in the Portal: Accounts → your treasury account → Edit test assets → set USD, then Save changes.
Edit test assets: set the treasury's USD balance (here, 100).

The treasury account funded with $100 USD (entity-owned).
3. Pay out USDC to a beneficiary’s wallet
The source is your USD balance, and the target is an onchain address receivingusdc. Because the source and target assets differ, Coinbase converts the USD to USDC and sends it onchain for you.
In Sandbox there’s no real recipient wallet, so use a reserved test address like
0x1111111111111111111111111111111111111111 (it settles as a success). In production, use the beneficiary’s real wallet address.For payouts of $3,000 or more (US), include a
travelRule object with originator and beneficiary details. See Transfers overview for the full field list.- CDP CLI
- TypeScript SDK
amount and asset are in usd (what you spend); the target asset is usdc (what the beneficiary receives). Coinbase handles the conversion. The CLI passes the JSON body to cdp transfers create on stdin (-) so the nested source/target objects are easy to write.4. Confirm the payout
The payout settles asynchronously; you get apayments.transfers.completed webhook when the USDC lands onchain. You can also poll it:
- CDP CLI
- TypeScript SDK
In Sandbox the payout settles immediately, so this check returns
completed. In production the first check usually shows quoted or processing; rely on the payments.transfers.completed webhook, or poll until the status reaches completed.
After the payout, the treasury's USD balance drops from $100 to $50.
Run the SDK flow as scripts
Run the SDK flow as scripts
The SDK snippets above build on one client and belong in a single file. Because funding the treasury (Step 2) happens in the Portal, run it as two scripts: create the account, fund it, then pay out. Save each as a Fund that account in the Portal (Step 2), then run Part 2.Part 2 — pay out and confirm (Steps 3 to 4). Paste the treasury account ID Part 1 printed.
.ts file and run it with npx tsx <file>.ts (Node 22 or later; tsx runs TypeScript directly, no build step).Part 1 — create the treasury (Step 1). Prints the account ID to fund.main.ts
main.ts
Good to know
- Automatic conversion: because the source (USD) and target (USDC) assets differ, Coinbase debits your USD, converts it to USDC, and sends it onchain. You fund only in USD and never custody stablecoins.
- Travel rule: for payouts of $3,000 or more (US), include a
travelRuleobject withoriginatorandbeneficiarydetails. See the Transfers overview for the full field list. - Reconciliation: attach
metadata(a reference or customer ID) to each payout, and query history withcdp transfers listor the Transfers API. - Idempotency: every SDK call passes an
idempotencyKey, so a retried request returns the same result instead of creating a duplicate payout. Thecdp transfers createCLI command has no idempotency option, so for production prefer the SDK (or the REST API, which accepts an idempotency key) for safe retries.
What to read next
Customers / KYC
Onboard the entity and customers behind these payouts
Transfers
All transfer types, rails, and lifecycle
Deposit Destinations
Fiat and crypto deposit destinations
Webhooks
React to payout status in production