Update Leverage (WebSocket)
Adjust leverage settings for trading markets through the WebSocket connection for rapid risk management and position scaling.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "leverage-1",
"method": "post",
"params": {
"action": "updateLeverage",
"symbol": "BTC-USDT",
"leverage": "20",
"isCross": true,
"subAccountId": "1867542890123456789",
"nonce": 1704067200000,
"expiresAfter": 1704067300000,
"signature": {
"v": 28,
"r": "0x...",
"s": "0x..."
}
}
}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 trading request payload with all fields flattened |
Params Object Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
params.action | string | Yes | Must be "updateLeverage" |
params.symbol | string | Yes | Market symbol (e.g., "BTC-USDT") |
params.leverage | string | Yes | Desired leverage multiplier |
params.isCross | boolean | Yes | true for cross margin, false for isolated |
params.subAccountId | string | Yes | Subaccount identifier |
params.nonce | integer | Yes | Incrementing nonce (Unix ms timestamp as number) |
params.expiresAfter | integer | No | Optional expiration timestamp (Unix ms as number) |
params.signature | object | Yes | EIP-712 signature |
Response Format
Success Response
{
"id": "leverage-1",
"status": 200,
"result": {
"symbol": "BTC-USDT",
"previousLeverage": "10",
"newLeverage": "20",
"isCross": true,
"maxLeverage": "50",
"marginRequirementChange": "+500.00",
"timestamp": 1704067200500
}
}Error Response
{
"id": "leverage-1",
"status": 400,
"result": null,
"error": {
"code": 400,
"message": "Leverage exceeds maximum allowed"
}
}Implementation Example
class LeverageManager {
constructor(ws, signer) {
this.ws = ws;
this.signer = signer;
this.requestId = 0;
this.leverageSettings = new Map();
}
async updateLeverage(subAccountId, symbol, leverage, isCross = true) {
// Generate nonce
const nonce = Date.now();
// Create leverage signature
const signature = await this.signUpdateLeverage(subAccountId, symbol, leverage, isCross, nonce);
// Build request
const request = {
type: "request",
requestId: `update-leverage-${++this.requestId}`,
method: "updateLeverage",
params: {
action: {
type: "updateLeverage",
symbol,
leverage: leverage.toString(),
isCross
},
subAccountId,
nonce,
signature,
expiresAfter: nonce + 30000 // 30 second expiry
}
};
// Send and wait for response
const result = await this.sendRequest(request);
// Update local tracking
this.leverageSettings.set(symbol, {
leverage: parseFloat(result.newLeverage),
isCross,
lastUpdated: Date.now()
});
return result;
}
async signUpdateLeverage(subAccountId, symbol, leverage, isCross, nonce) {
const domain = {
name: "Synthetix",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000"
};
const types = {
UpdateLeverageRequest: [
{ name: "subAccountId", type: "uint64" },
{ name: "symbol", type: "string" },
{ name: "leverage", type: "string" },
{ name: "isCross", type: "bool" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
};
const message = {
subAccountId: BigInt(subAccountId),
symbol,
leverage: leverage.toString(),
isCross,
nonce: BigInt(nonce),
expiresAfter: BigInt(nonce + 30000)
};
const signature = await this.signer._signTypedData(domain, types, message);
return ethers.utils.splitSignature(signature);
}
sendRequest(request) {
return new Promise((resolve, reject) => {
this.pendingRequests.set(request.requestId, { resolve, reject });
this.ws.send(JSON.stringify(request));
setTimeout(() => {
if (this.pendingRequests.has(request.requestId)) {
this.pendingRequests.delete(request.requestId);
reject(new Error('Request timeout'));
}
}, 15000); // 15 second timeout
});
}
getCurrentLeverage(symbol) {
return this.leverageSettings.get(symbol);
}
getAllLeverageSettings() {
return Object.fromEntries(this.leverageSettings);
}
}
// Usage Examples
async function increaseRiskTolerance(manager, subAccountId, symbol) {
try {
const current = manager.getCurrentLeverage(symbol);
const currentLeverage = current ? current.leverage : 10;
const newLeverage = Math.min(currentLeverage * 1.5, 50); // Max 50x
const result = await manager.updateLeverage(subAccountId, symbol, newLeverage, true);
console.log(`Increased ${symbol} leverage from ${result.previousLeverage}x to ${result.newLeverage}x`);
return result;
} catch (error) {
console.error(`Failed to increase leverage for ${symbol}:`, error);
throw error;
}
}
async function setConservativeLeverage(manager, subAccountId, symbols) {
const results = [];
for (const symbol of symbols) {
try {
const result = await manager.updateLeverage(subAccountId, symbol, 5, true); // Conservative 5x
results.push(result);
console.log(`Set conservative leverage for ${symbol}: 5x`);
} catch (error) {
console.error(`Failed to set conservative leverage for ${symbol}:`, error);
results.push({ symbol, error: error.message });
}
}
return results;
}Important Behavior
How Leverage Settings Work
When you update leverage for a market:
- The new leverage setting applies to all future positions you open in that market
- Existing positions retain their original leverage - they are NOT affected
- The setting persists until you explicitly change it again
1. You have an open BTC position at 10x leverage
2. You call updateLeverage(subAccountId, "BTC-USDT", 25, true)
3. Your existing position REMAINS at 10x
4. Any NEW BTC positions will open at 25xCan You Change Leverage on Existing Positions?
No, you cannot directly change leverage on existing positions. However:
- For Isolated Positions: Use
updateIsolatedMargin(REST API only) to add/remove margin, which changes effective leverage - For Cross Margin Positions: Leverage is fixed at position entry
Error Handling
Common Errors
| Error Code | Message | Description |
|---|---|---|
| -32000 | Invalid leverage | Leverage exceeds maximum allowed for symbol |
| -32001 | Position exists | Cannot change leverage with open positions |
| -32002 | Invalid symbol | Market symbol does not exist |
| -32003 | Margin insufficient | Not enough margin for new leverage setting |
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
| 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
- Place Orders - Use updated leverage for trading
- Transfer Collateral - Manage margin requirements
- WebSocket Authentication - Connection setup
- REST Alternative - REST API comparison