Skip to main content
Fiat deposit destinations are currently in private beta and require account enablement. Contact your Coinbase representative for access. Fields and behavior may change before general availability.
This guide walks through the full journey for issuing a fiat deposit destination in Sandbox: onboard a customer, create the account that receives funds, issue the fiat deposit destination, then simulate an inbound deposit and watch it settle as USDC. Every step is a real API call so you can see exactly which endpoints your integration needs to hit. Fiat deposit destinations are currently created and managed entirely via API. They are not accessible in the Portal UI yet.

Prerequisites

Install the CDP CLI (requires Node.js 22+):
Configure a Sandbox environment using your CDP Secret API Key JSON file from the CDP Portal. Point it at the Sandbox host so both the /platform/v2 APIs and the Sandbox-only simulation helper resolve:
Keep the API key secret. Never commit it to source control.
Sandbox does not connect to any bank. Deposit instructions returned here are placeholders for API testing, and deposits are triggered with a simulation helper, not real money movement. Do not send real funds to a Sandbox fiat deposit destination.

1. Onboard a KYC’d customer

Create a customer with type individual, requesting the capabilities this flow needs: See the full capability set for every capability CDP supports. In Sandbox, the fullSsn value 000-00-0000 is a magic value that forces a deterministic approval, so the requested capabilities verify and become active without real PII.
For the full customer lifecycle (identity fields, Terms of Service, tax attestations, and the requirements each capability needs), see the Customers Quickstart.

2. Confirm the custodyFiat capability is active

Creating a fiat deposit destination requires the customer’s custodyFiat capability to be active. Verification is asynchronous; with the approval magic value it settles quickly. Poll with Get a customer:
In production, subscribe to the customers.capability.changed webhook rather than polling. If custodyFiat is not active, the create call in Step 4 returns 403 customer_not_authorized.

3. Create the customer’s account

Create account with the customer as owner. This is where deposited funds will land as USDC. Passing the customer ID as owner makes it customer-owned; customer-facing operations require the end-user’s IP on compliance.requesterIpAddress.

4. Issue the fiat deposit destination

Create deposit destination with type fiat for the account. This is a customer-facing operation, so it also requires the end-user’s IP on compliance.requesterIpAddress. Choose a target for the incoming funds: credit a CDP account, or route straight out on-chain to an external address as each deposit settles (useful for automated sweeps to a non-custodial address):
Set target.asset to usdc so incoming USD is converted and credited as USDC:
The rest of this guide continues with a deposit destination that credits an account. If you used the onchain address target instead, deposits forward automatically once the destination is active - there’s nothing to transfer out manually in Step 10.
If custodyFiat is not active, this returns 403 with errorType: customer_not_authorized and the missing capability under unauthorizedCapabilities. Resolve it (Step 2) and retry.
The response status is pending: the banking partner is still provisioning the account.

5. Wait for activation

Poll Get deposit destination until the fiat deposit destination is active. Only then can it receive deposits.
No webhook fires for fiat deposit destination creation or the pending → active transition. You must poll GET /v2/deposit-destinations/{depositDestinationId} to confirm status is active before sharing deposit instructions or simulating a deposit.

6. Share the deposit instructions

Once active, the fiat object holds the bank coordinates the depositor uses to send USD: ACH is currently the only publicly supported rail.
A fiat deposit destination can be funded by the customer themselves (the sender name must match the KYC’d customer).

7. Simulate a deposit

Because Sandbox is not connected to a bank, use the simulation endpoint to trigger an inbound deposit. It works for both crypto and fiat destinations (the type is derived from the destination), so no rail details are needed. For a fiat destination, asset defaults to the destination’s currency (usd).
After simulation:
  • Webhook events fire: payments.transfers.processing then payments.transfers.completed
  • Transfer record is created: visible via List transfers
  • Balance is credited: the account receives USDC (converted 1:1 from USD)

8. Inspect the webhook payload

When the deposit settles, CDP fires a payments.transfers.completed webhook to your subscribed endpoint. The payload includes the transfer record, a reference back to the fiat deposit destination, and any metadata set on it.
This requires a webhook subscription; CDP has nowhere to deliver the event otherwise. See Create webhook subscription and Transfer Webhooks to set one up.
A payments.transfers.processing event fires earlier when the deposit is first detected. For most integrations, listening for completed is sufficient. If a deposit is returned, a payments.transfers.failed event fires with the reason.

9. Verify the balance update

Confirm the deposit credited to the account as USDC with List balances for account:

10. Transfer funds out to a wallet address

Once the deposit settles as USDC, use Create transfer to send it out to an external wallet address (target.address), or back to a bank rail via a payment method (target.paymentMethodId). This is also a customer-facing operation, so it requires both the transferStablecoin capability from Step 1 and the end-user’s IP on compliance.requesterIpAddress:
This is a manual, per-transfer call. For automated sweeps to a non-custodial address, no manual transfer needed, set the deposit destination’s target to an onchain address at creation time (Step 4) instead of an account. Deposits are then routed to that address automatically as they settle.
In Sandbox, 0x1111111111111111111111111111111111111111 is the reserved success address. See the Transfers Quickstart for the full set of reserved addresses and failure cases (including the payment method withdrawal example), and the Transfers overview for fee quotes and travel rule requirements.

Move to production

To run this flow for real, switch the Sandbox base URL to the production base URL and use a production API key. In production there are no magic values (customers complete real KYC), and fiat deposit destinations are provisioned at a real banking partner. Fiat deposit destinations are currently API-only; they are not accessible in the Portal UI yet.

Deposit Destinations overview

Crypto and fiat deposit destinations: concepts, rails, lifecycle, and who can send funds

Customers & KYC

Onboard and verify the customer that owns the fiat deposit destination

Transfers

Move funds out of an account to a wallet address, email, or payment method

Webhooks

Subscribe to real-time deposit event notifications

REST API reference

Full Deposit Destinations API reference