Withdraw Collateral (WebSocket)
Withdraw collateral from your Synthetix trading account back to your wallet through the WebSocket connection. Withdrawals are subject to approval, margin requirements, and risk checks.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "withdraw-1",
"method": "post",
"params": {
"action": "withdrawCollateral",
"subAccountId": "1867542890123456789",
"symbol": "USDC",
"amount": "1000.0",
"destination": "0x742d35Cc6634C0532925a3b8D371d1c62a39b6e2",
"nonce": 1704067200000,
"expiresAfter": 1704067300,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}
}Parameters
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Client-generated unique request identifier |
method | string | Yes | Must be "post" |
params | object | Yes | Contains the withdrawal request payload with all fields flattened |
Params Object Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Must be "withdrawCollateral" |
subAccountId | string | Yes | Subaccount identifier |
symbol | string | Yes | Collateral asset symbol to withdraw (e.g., "USDC", "ETH") |
amount | string | Yes | Amount to withdraw as decimal string (e.g., "1000.0") |
destination | string | Yes | Destination wallet address (0x-prefixed Ethereum address) |
nonce | integer | Yes | Incrementing nonce (Unix ms timestamp as number) |
expiresAfter | integer | No | Optional expiration timestamp in seconds (0 = no expiration) |
signature | object | Yes | EIP-712 signature |
Important: Withdrawals must be signed by the master account owner. Delegate addresses cannot initiate withdrawals.
EIP-712 Type Definition
const WithdrawCollateralTypes = {
WithdrawCollateral: [
{ name: "subAccountId", type: "uint256" },
{ name: "symbol", type: "string" },
{ name: "amount", type: "string" },
{ name: "destination", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
}Response Format
Success Response
{
"id": "withdraw-1",
"status": 200,
"result": {
"requestId": "withdraw-req-123",
"symbol": "USDC",
"amount": "1000.0",
"destination": "0x742d35Cc6634C0532925a3b8D371d1c62a39b6e2"
}
}| Field | Type | Description |
|---|---|---|
requestId | string | Unique withdrawal request identifier |
symbol | string | Asset symbol being withdrawn |
amount | string | Amount being withdrawn |
destination | string | Destination wallet address |
Error Response
{
"id": "withdraw-1",
"status": 400,
"result": null,
"error": {
"code": 400,
"message": "Insufficient withdrawable balance"
}
}Implementation Example
import { ethers } from 'ethers';
async function withdrawCollateral(ws, signer, subAccountId, symbol, amount, destination) {
const nonce = Date.now();
const expiresAfter = Math.floor(Date.now() / 1000) + 300; // 5 minutes
// EIP-712 signature using WithdrawCollateral type
const domain = {
name: "Synthetix",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000"
};
const types = {
WithdrawCollateral: [
{ name: "subAccountId", type: "uint256" },
{ name: "symbol", type: "string" },
{ name: "amount", type: "string" },
{ name: "destination", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
};
const message = {
subAccountId: BigInt(subAccountId),
symbol,
amount,
destination,
nonce: BigInt(nonce),
expiresAfter: BigInt(expiresAfter)
};
const sig = await signer.signTypedData(domain, types, message);
const signature = ethers.Signature.from(sig);
// Send request
ws.send(JSON.stringify({
id: `withdraw-${Date.now()}`,
method: "post",
params: {
action: "withdrawCollateral",
subAccountId,
symbol,
amount,
destination,
nonce,
expiresAfter,
signature: { v: signature.v, r: signature.r, s: signature.s }
}
}));
}
// Usage: Withdraw 1000 USDC to your wallet
await withdrawCollateral(
ws,
signer,
"1867542890123456789",
"USDC",
"1000.0",
"0x742d35Cc6634C0532925a3b8D371d1c62a39b6e2"
);Validation Rules
noncemust be a timestamp in milliseconds and must be increasingsymbolmust be a valid collateral symbol (e.g.,"USDC","ETH")amountmust be a positive number as stringdestinationmust be a valid Ethereum address (0x-prefixed)- Account must have sufficient withdrawable balance of the specified asset
- Withdrawal must not violate margin requirements
- Must be signed by master account owner (no delegate support)
Error Handling
Common Errors
| Error Code | Message | Description |
|---|---|---|
| 400 | Insufficient withdrawable balance | Account lacks required funds for specified asset |
| 400 | Margin requirement violation | Withdrawal would violate margin rules |
| 400 | Invalid asset symbol | Asset type not supported as collateral |
| 400 | Account health check failed | Withdrawal would make account unhealthy |
| 401 | Delegate signature not allowed | Must be signed by account owner |
| 400 | Minimum withdrawal amount | Amount below minimum threshold |
Signing
All trading methods are signed using EIP-712. Each successful trading request will contain:
- A piece of structured data that includes the sender address
- A signature of the hash of that structured data, signed by the sender
For detailed information on EIP-712 signing, see EIP-712 Signing.
Nonce Management
The nonce system prevents replay attacks and ensures order uniqueness:
- Use current timestamp in milliseconds as nonce
- Each nonce must be greater than the previous one
- Recommended: Use
Date.now()or equivalent - If nonce conflicts occur, increment by 1 and retry
:::note SubAccountAction Exception
SubAccountAction endpoints (getPositions, getOpenOrders, getOrdersHistory, getTrades, getFundingPayments, getSubAccount, getDelegatedSigners, getBalanceUpdates) do not require a nonce. Only the signature and optional expiresAfter parameters are needed.
:::
| Error | Description |
|---|---|
| Invalid signature | EIP-712 signature validation failed |
| Invalid market symbol | Market symbol not recognized |
| Nonce already used | Nonce must be greater than previous value |
| Rate limit exceeded | Too many requests in time window |
| Request expired | expiresAfter timestamp has passed |
Next Steps
- Deposits - How to deposit collateral into your account
- Get Subaccount - Check withdrawable balance
- Get Positions - View positions affecting margin
- WebSocket Authentication - Connection setup
- REST Alternative - REST API comparison