Digital assets (sandbox)
A business can hold digital-asset accounts — USDC, EURC and other
stablecoins — next to its bank accounts, on the same API: /v1/banking/*.
Each account holds one asset. Money arrives on chain (and, for USDC, by SEPA
to an IBAN), and leaves on chain, to a bank account, to another CashXChain
customer, or into your other accounts.
Everything in this section runs in the sandbox, at
https://api.sandbox.cashxchain.com and
app.sandbox.cashxchain.com. Production
does not offer digital-asset accounts, wallets or sends yet: there, onboarding
answers 503 digital_assets_unavailable, opening a USDC account
422 currency_unavailable, a send 422 corridor_unsupported, and the sandbox
routes 404. GET /v1/banking/capabilities says what the deployment you call
offers — see Capabilities.
The accounts and wallets are held at our crypto-asset service provider. CashXChain holds no private keys: it sends instructions and records what happens. The provider is never named — not in a path, a field, an error or a route — and no provider id appears in a response.
Accounts per asset, wallets per chain
- An account per asset. USDC, EURC, USDT, USDB, PYUSD and PATHUSD can each be opened once. An account spans every chain where you hold a wallet that carries its asset.
- A wallet per chain. You open one wallet on each chain you want. The asset accounts share the wallets: a Solana wallet carries your USDC, EURC and USDT on Solana alike.
- Each asset is its own currency. An asset is never converted for display, never shown as fiat, and never added to another asset. A balance sums one asset over its wallets, and nothing else.
- All digital assets together count as one currency of your plan's
max_currencies, however many you open.
What the sandbox offers, per chain:
| Chain | Assets |
|---|---|
solana | USDC, EURC, USDT, USDB, PYUSD |
base | USDC, EURC, USDB |
ethereum | USDC, USDT, USDB |
tron | USDT |
tempo | USDC, USDT, EURC, PATHUSD |
A new account's first wallet is opened on Solana — on Tempo for PATHUSD. The USDC account also has an EUR IBAN: EUR sent to it by SEPA arrives as USDC. See Accounts and wallets.
What you can do
| Flow | How | Page |
|---|---|---|
| Get verified with the provider | GET/POST /v1/banking/kyb/digital-assets; in the sandbox, one call approves you | Accounts and wallets |
| Open an account | POST /v1/banking/accounts with {"currency": "USDC"} (or EURC, …) | Accounts and wallets |
| Open a wallet on another chain | POST /v1/banking/digital-assets/wallets | Accounts and wallets |
| Add test funds | POST /v1/sandbox/banking/accounts/{account_id}/simulate-deposit | Accounts and wallets |
| Settle a send the provider's sandbox leaves in flight | POST /v1/sandbox/banking/payouts/{payout_id}/simulate-completion | Sandbox behaviour |
| Send on chain, to the same chain or across chains | POST /v1/banking/payouts with destination.type onchain | Sending |
| Send to an IBAN (EUR over SEPA) | destination.type iban | Sending |
| Send to a US, UK, Mexican or Brazilian bank account | destination.type us_bank, gb_bank, clabe, pix | Sending |
| Send to another CashXChain customer by @handle | destination.type cxc_handle | Sending |
| Swap USDC and EURC | destination_account_id: your account in the other asset | Sending |
| Send USDC back to your own EUR account | destination_account_id: your EUR account | Sending |
| Convert EUR into your USDC account | a payout from your EUR account to the USDC account | Sending |
| See the route and lock it | POST /v1/banking/payouts/quote, then quote_id | Quotes and the route lock |
| Send with an API key | to a trusted beneficiary a person approved | API keys and trusted beneficiaries |
| Build it end to end with a key: wallet to wallet, bank to wallet | every call in order, with timings and errors | API transfer guide |
What the sandbox simulates
The sandbox talks to the provider's own sandbox. Four things are simulated so you can test without a real business, real money or a bank behind the account:
- Approval.
POST /v1/sandbox/banking/kyb/digital-assets/approveapproves you at the provider without its hosted verification form. - Test funds.
simulate-depositasks the provider's sandbox to deposit the asset into your wallet; it is then read and booked like any real deposit — balance, transaction,payin.received. - A send-back's arrival. No bank sits behind a sandbox EUR account, so
simulate-arrivalbooks the EUR of a send-back on it (a background pass does the same within about two minutes). - Completion. The provider's sandbox accepts sends to an IBAN or a bank
account, send-backs and swaps, and leaves them in flight; it was seen to
complete a send over ACH to a US account itself. The sandbox settles each
one still in flight once the money has been seen leaving the wallet: from a
minute after the provider accepts it (five minutes for a
us_banksend), or without that wait withsimulate-completion. It marks each onesimulated: true.
Everything else is the provider's sandbox answering for real. Read Sandbox behaviour before you test.
Who may do what
Every route takes a person's dashboard session or an API key. A restricted
key (cxc_rk_) needs the scope shown; a secret key (cxc_sk_) and a master
key hold every scope. Publishable keys reach none of these.
| Action | Route | Session | API key |
|---|---|---|---|
| Onboarding: status, start | GET / POST /v1/banking/kyb/digital-assets | ✓ | accounts:read / accounts:write |
| Sandbox approval | POST /v1/sandbox/banking/kyb/digital-assets/approve | ✓ | accounts:write |
| Open an account | POST /v1/banking/accounts | ✓ | accounts:write |
| Accounts, balances, pay-in details | GET /v1/banking/accounts, …/{id}/balance, …/{id}/payin-instructions | ✓ | accounts:read |
| Wallets: list, open | GET / POST /v1/banking/digital-assets/wallets | ✓ | accounts:read / accounts:write |
| Credits | GET /v1/transactions | ✓ | payments:read |
| Payouts | GET /v1/banking/payouts, …/{id} | ✓ | payments:read |
| Quotes and route locks | POST /v1/banking/payouts/quote | ✓ | payments:read |
| Capabilities | GET /v1/banking/capabilities | ✓ | accounts:read |
| Swap | POST /v1/banking/payouts with destination_account_id | step-up | payments:write, no step-up |
| Convert EUR into USDC | POST /v1/banking/payouts from the EUR account | step-up | payments:write, no step-up |
| Send back to your own EUR account | POST /v1/banking/payouts from the USDC account | step-up | payments:write, no step-up |
| Send on chain, to an IBAN or a bank account, by @handle | POST /v1/banking/payouts with destination | step-up; inline or a trusted beneficiary | payments:write, a trusted beneficiary only, no step-up |
| Trusted beneficiaries: list | GET /v1/banking/digital-assets/trusted-beneficiaries | ✓ | accounts:read |
| Trusted beneficiaries: approve, revoke | POST …/trusted-beneficiaries, DELETE …/{id} | a person only, step-up | never — 403 session_required |
| Test funds | POST /v1/sandbox/banking/accounts/{id}/simulate-deposit | ✓ | payments:write |
| Fiat test funds (the EUR a convert starts from) | POST /v1/sandbox/banking/faucet | ✓ | payments:write |
| A send-back's arrival | POST /v1/sandbox/banking/payouts/{id}/simulate-arrival | ✓ | payments:write |
| A send the provider's sandbox leaves in flight, settled | POST /v1/sandbox/banking/payouts/{id}/simulate-completion | ✓ | payments:write |
A session acting for another account (Cxc-Account) is refused
403 session_required on every send to a third party and on a send-back. A
session's seat needs payouts.create to send or to approve a trusted
beneficiary. See Step-up for sessions and
API keys and trusted beneficiaries.
Start with the Quickstart. An integration that moves stablecoins with an API key follows the API transfer guide.