Submit internal transfer
Move collateral between two account indexes of the same wallet.
X-API-Key / X-Signature headers. In v0 transfers are same-wallet only: both fromAccountIndex and toAccountIndex belong to ethereumAddress, so there is no cross-wallet recipient field. Funds never leave custody, so nothing settles on-chain.
Response behavior
Asynchronous. A202 Accepted means the transfer passed validation and was queued to the matching engine with status: PENDING. The definitive outcome (applied, or rejected for insufficient free collateral) is delivered asynchronously — poll GET /v1/accountTransferUpdates or subscribe to the account transfer update WebSocket channel and correlate on transferId.
Signing the request
Transfers use EIP-712 typed data (eth_signTypedData_v4). Sign this typed data with the wallet that owns ethereumAddress, then split the 65-byte result into {r, s, v} for the signature field. The gateway recovers the signer and rejects mismatches with HTTP 401.
Domain
amount is the integer collateral quote-quantum amount (same value as the amount request field).
Per-environment domain parameters. chainId and verifyingContract are identical to the withdraw domain — see the per-environment table under POST /v1/withdraw. Only the domain name differs ("Arcus Transfer" vs "Arcus Withdraw").
Complete eth_signTypedData_v4 call (ethers v6 / viem)
v component must be 0x1b (27) or 0x1c (28); wallets that return 0 / 1 should have 27 added before sending.Body
Master EVM address that owns both the source and destination accounts. In v0 an internal transfer is same-wallet only: the funds move between two account indexes of this one address — there is no cross-wallet recipient field.
^(0x|0X)?[0-9a-fA-F]{40}$"0x742d35cc6634c0532925a3b844bc9e7595f2bd18"
Account index to debit.
0 <= x <= 9Account index to credit. Must differ from fromAccountIndex; a transfer to the same index is rejected with HTTP 400.
0 <= x <= 9Amount to transfer, as a base-10 integer string in quote quantums (1e9 = $1; for example, 1000000000 represents $1). Amounts must be positive and fit in a signed 64-bit integer. Unlike withdrawals, an internal transfer never settles on-chain, so the amount is NOT constrained to collateral-base-unit multiples. Float-style decimals are rejected. The source account must have sufficient free collateral or the transfer is rejected asynchronously with REJECTED_INSUFFICIENT_COLLATERAL.
^[0-9]+$"100000000000"
Replay-protection nonce, single-use per (ethereumAddress, fromAccountIndex, toAccountIndex) — a repeated nonce is rejected with 409. Send the current time as nanoseconds since the Unix epoch (a plain base-10 integer, e.g. 1730000000000000000); the server accepts a timestamp up to 48 hours in the past by default and up to 24 hours in the future by default — both bounds are configurable per environment. A legacy opaque nonce (e.g. a UUID) is still accepted but deprecated. At most 64 characters.
1 - 64"1730000000000000000"
secp256k1 EIP-712 typed-data signature (r, s, v) over the Transfer payload (eth_signTypedData_v4). See the POST /v1/transfer endpoint description for the exact domain, types, and message. Produced by the wallet that owns ethereumAddress; requests whose recovered signer does not match are rejected with HTTP 401.
Response
Transfer accepted and queued to the matching engine. The body carries status: PENDING and a transferId; the terminal outcome is delivered on the account transfer update stream.
Server-generated identifier (UUID) correlating this transfer with the matching AccountTransferUpdate on the account transfer update stream.
"b3f1c2d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d"
20-byte EVM address as hex: optional 0x or 0X prefix and exactly 40 hexadecimal digits. API responses normalize to lowercase a–f after 0x.
^(0x|0X)?[0-9a-fA-F]{40}$Account index (account index, 0–9). Identifies the account for orders, positions, fills, and API keys.
0 <= x <= 9Account index (account index, 0–9). Identifies the account for orders, positions, fills, and API keys.
0 <= x <= 9Transfer amount echoed back as a human-readable decimal in quote currency (quote resolution 1e9), matching how the amount is reported on the account transfer update feed.
"100"
"1.5"
Synchronous status of a submitted transfer. Always PENDING on the 202 response — the transfer has been queued to the matching engine but not yet applied. The terminal outcome (APPLIED, REJECTED_INSUFFICIENT_COLLATERAL, ...) is delivered asynchronously on the account transfer update stream (see AccountTransferUpdate).
PENDING Server receive timestamp (epoch microseconds).