Spot Transfer
Type: SESSION · Weight: — (not on the /api/v3 rate limiter)
Status: Implemented.
POST /v1/spot/transfer
Move balance between the funding account of an exchange wallet session (the perpetuals account) and the spot account of the session's Canton party. Authenticated by the wallet-session bearer token, like /v1/wallet/*; there is no X-MBX-APIKEY / signature. The spot side is the same deterministic account (UUIDv5("rocky-spot:" + party)) that session-key issues keys for, so funds moved here appear in GET /api/v3/account under that party's session key.
Only CUSD can be transferred. Wallet-funded (enrolled) accounts cannot use this endpoint at all once on-chain settlement is active — their wallet is the only funding source.
Request — JSON body
POST /v1/spot/transfer
Authorization: Bearer <exchange wallet session token>
Content-Type: application/json
{ "asset": "CUSD", "amount": "12.5", "direction": "toSpot" }
| Field | Type | Required | Notes |
|---|---|---|---|
asset | string | yes | CUSD (the alias USDC is accepted and mapped to CUSD). Case-insensitive. Any other asset → 400. |
amount | string | yes | Positive decimal. |
direction | string | yes | toSpot (funding → spot) or toFunding (spot → funding). Case-insensitive; TO_SPOT / FUNDING_TO_SPOT and TO_FUNDING / SPOT_TO_FUNDING are also accepted. |
Response — 200 (values illustrative)
{
"asset": "CUSD",
"direction": "toSpot",
"amount": "12.5",
"fundingAvailable": "987.5",
"spotFree": "112.5"
}
| Field | Type | Notes |
|---|---|---|
asset | string | Always CUSD. |
direction | string | Normalized to toSpot or toFunding. |
amount | string | The amount moved, as parsed. |
fundingAvailable | string | Funding-account available balance after the transfer. |
spotFree | string | Spot free balance of CUSD after the transfer. |
Wallet-funded gates (active only once on-chain settlement is enabled for the venue; see On-chain Settlement)
| Account | toSpot | toFunding |
|---|---|---|
| Enrolled (wallet-funded) | rejected | rejected |
| Party-bound, not yet enrolled | rejected | allowed (so a legacy internal balance can still be cleared) |
| Not party-bound | allowed | allowed |
Errors — body is { "error": "<message>" }, not the {code,msg} envelope
| HTTP | error / cause |
|---|---|
400 | amount must be a positive decimal; only CUSD can be transferred between contract and spot accounts; unknown transfer direction: …; body not valid JSON; or the ledger rejected an argument. |
401 | missing bearer token / invalid session. |
403 | session has no Canton party; connect a wallet first. |
422 | Wallet-funded account: fund via your Canton wallet; internal transfer is disabled. (the gate table above); or the ledger reported a precondition failure such as insufficient balance (its message is passed through). |
500 | spot transfer failed; try again. |