Skip to main content
Moving USDC cash is three signed writes against /api/v1/trading: deposit adds collateral to a portfolio, withdraw takes it off the exchange, and transfer rebalances cash between portfolios without leaving. All three quote size in CentiCents, all three return a RequestAck, and a 200 OK can still be a rejection. For the units and balance model behind these moves, see collateral and cash.

Before you start

  • Cash is USDC only, in CentiCents on writes: 1 CentiCent = 0.0001 USDC, so 1,000 USDC is size = 10000000 (1000 × 10000). size is a signed 64-bit integer. Balances read back as USDC decimal strings, never integers.
  • Every body is signed. You POST a Base64SignedPayload envelope; the decoded bytes are the schema below. See signed payloads for the byte layout and signing procedure.
  • Branch on the ack. A signed write returns { status, processed_at_ns }. status = request_completed means accepted; any rejected_* value means the move did not happen. Read the status — do not infer success from the HTTP code.

Deposit

Add USDC collateral to one portfolio.
EndpointPOST /api/v1/trading/deposit
Authsession-key signed body
Decoded bodyDepositCash (request_type = 5)
The body is two fields:
portfolio_id
object
required
The receiving portfolio, as an account_id / subaccount_index / portfolio_index triple.
size
int64
required
Cash to add, in CentiCents. 10000000 deposits 1,000 USDC.
Spot deposit is not available. A DepositSpot request type is rejected with 400; only USDC cash deposit is live.

Withdraw

Remove USDC collateral from a portfolio. The body and signing are identical to a deposit, but the exchange holds withdrawals to a higher bar.
A valid session signature does not authorize a withdrawal on its own. The signing session must be admin-rooted — unpinned and chained to an admin master key. A pinned session, or one rooted on a scoped key, is rejected even when its signature verifies. See withdrawals are admin-rooted.
EndpointPOST /api/v1/trading/withdraw
Authadmin-rooted session-key signed body
Decoded bodyWithdrawCash (request_type = 7)
The fields match DepositCash: a portfolio_id triple (the source) and size in CentiCents. Spot withdrawal is not available. A WithdrawSpot request type is rejected with 400; only USDC cash withdrawal is live.

Transfer

Move USDC cash between portfolios without an external deposit or withdrawal. Both variants hit POST /api/v1/trading/transfer; the request_type in the signed header selects which one.
Move cash between two portfolios under one account. The shared account_id is carried once, which is why this variant is cheaper on the wire than encoding two full triples.
Decoded bodyIntraAccountCashTransfer (request_type = 32)
Authsession-key signed body
Fields: account_id, from_subaccount_index, from_portfolio_index, to_subaccount_index, to_portfolio_index, and size (CentiCents). Use this to fund an isolated-margin portfolio from your main one without leaving the exchange.
A transfer whose source and destination resolve to the same portfolio is rejected with status = rejected_self_transfer. Set distinct from/to portfolios.

Read the ack

Every one of these moves returns the same shape on 200:
status
string
request_completed on acceptance. A rejected_* value (for example rejected_invalid_portfolio_id, rejected_unauthorized, rejected_self_transfer) means the cash did not move — the HTTP code is still 200.
processed_at_ns
integer
Exchange processing time, nanoseconds since the Unix epoch.
A non-2xx response is a different surface: application/problem+json (RFC 9457) carrying a stable code. Branch on code, not on the human-readable detail. The error model lists both surfaces.

Confirm the move

Re-read the affected balances after a request_completed. GET /api/v1/portfolio/balance returns one portfolio’s free cash as a USDC string; GET /api/v1/portfolio/cash_balances returns one balance per portfolio. Both authenticate with a read credential. To fund a portfolio and place your first order end to end, follow the quickstart.