Skip to main content
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.
Use case: Your business holds USD, but you need to pay recipients (workers, sellers, partners) in stablecoins, sent straight to their wallets onchain. What you’ll build: Fund a USD treasury, then pay out USDC onchain to any wallet address. Coinbase handles the USD-to-USDC conversion and the onchain send for you, so you never hold stablecoins yourself. These steps run in Sandbox, Coinbase’s test environment. To go live, point at production (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

Flow of funds: a USD treasury account funds a payout, where Coinbase converts USD to USDC and sends it onchain to the beneficiary's wallet.

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

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.
Confirm it is entity-owned. The owner should start with 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.
The Edit test assets modal in the CDP Portal, with the USD amount set to 100.

Edit test assets: set the treasury's USD balance (here, 100).

The treasury account overview in the CDP Portal showing a $100 USD balance.

The treasury account funded with $100 USD (entity-owned).

In production, you fund by wire: provision a fiat deposit destination to get a virtual bank account, then wire USD to it. This is a gated feature enabled per entity, so get in touch to turn it on. See Fiat deposit destinations for the setup.

3. Pay out USDC to a beneficiary’s wallet

The source is your USD balance, and the target is an onchain address receiving usdc. 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.
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 a payments.transfers.completed webhook when the USDC lands onchain. You can also poll it:
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.
The treasury account overview in the CDP Portal showing a $50 USD balance after a $50 payout.

After the payout, the treasury's USD balance drops from $100 to $50.

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 .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
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.
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 travelRule object with originator and beneficiary details. See the Transfers overview for the full field list.
  • Reconciliation: attach metadata (a reference or customer ID) to each payout, and query history with cdp transfers list or the Transfers API.
  • Idempotency: every SDK call passes an idempotencyKey, so a retried request returns the same result instead of creating a duplicate payout. The cdp transfers create CLI command has no idempotency option, so for production prefer the SDK (or the REST API, which accepts an idempotency key) for safe retries.

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