SubAccount Updates
Consolidated real-time stream of all subaccount activity including orders, trades, margin updates, and liquidations. This subscription replaces the need to subscribe to multiple separate streams.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/subscriptionsSubscription Request
Subscribe to SubAccount Updates
{
"id": "sub-1",
"method": "subscribe",
"params": {
"type": "subAccountUpdates",
"subAccountId": "1867542890123456789"
}
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Client-generated unique request identifier |
method | string | Yes | Must be "subscribe" |
params.type | string | Yes | Must be "subAccountUpdates" |
params.subAccountId | string | Yes | Subaccount ID to receive events for |
Event Types
| Event Type | Description |
|---|---|
orderPlaced | Order successfully placed on orderbook |
orderFilled | Order fully executed |
orderPartiallyFilled | Order partially executed |
orderCancelled | Order cancelled by user or system |
orderModified | Order price or quantity modified |
orderRejected | Order rejected due to validation failure |
trade | Trade execution with fill details |
marginUpdate | Account margin/balance state updated |
liquidation | Position liquidated due to insufficient margin |
User Event Messages
Order Placed
{
"method": "subAccountEvent",
"data": {
"eventType": "orderPlaced",
"orderId": "1948058938469519360",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limit",
"price": "50000.00",
"quantity": "0.1",
"status": "open",
"timestamp": 1704067200000,
"created_at": 1704067200000,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
}
}Order Filled
{
"method": "subAccountEvent",
"data": {
"eventType": "orderFilled",
"orderId": "1948058938469519360",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limit",
"price": "50000.00",
"quantity": "0.1",
"status": "filled",
"timestamp": 1704067210000,
"created_at": 1704067200000,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
}
}Order Cancelled
{
"method": "subAccountEvent",
"data": {
"eventType": "orderCancelled",
"orderId": "1948058938469519360",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limit",
"price": "50000.00",
"quantity": "0.1",
"status": "cancelled",
"timestamp": 1704067220000,
"created_at": 1704067200000,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
}
}Trade Execution
{
"method": "subAccountEvent",
"data": {
"eventType": "trade",
"tradeId": "123456790",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"side": "buy",
"price": "50010.00",
"quantity": "0.1",
"fee": "5.00",
"feeRate": "0.001",
"realizedPnl": "0.00",
"isTaker": true,
"timestamp": 1704067230000,
"position": {
"side": "long",
"size": "0.1",
"entryPrice": "50010.00",
"unrealizedPnl": "0.00"
}
}
}Margin Update
{
"method": "subAccountEvent",
"data": {
"eventType": "marginUpdate",
"subAccountId": "1867542890123456789",
"accountValue": "10000.00",
"availableMargin": "8500.00",
"totalUnrealizedPnl": "125.50",
"maintenanceMargin": "750.00",
"initialMargin": "1500.00",
"withdrawable": "8500.00",
"adjustedAccountValue": "9875.50",
"timestamp": 1704067800000,
"position": {
"symbol": "BTC-USDT",
"upnl": "125.50",
"initialMargin": "750.00",
"maintenanceMargin": "375.00",
"markPrice": "50125.50"
}
}
}Liquidation
{
"method": "subAccountEvent",
"data": {
"eventType": "liquidation",
"tradeId": "123456791",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"side": "sell",
"price": "40000.00",
"quantity": "0.2",
"realizedPnl": "-2000.00",
"fee": "20.00",
"feeRate": "0.005",
"liquidationPrice": "40000.00",
"timestamp": 1704067900000
}
}Event Data Fields
Common Fields
| Field | Type | Description |
|---|---|---|
eventType | string | Type of event |
subAccountId | string | Affected subaccount |
timestamp | integer | Event timestamp in milliseconds |
symbol | string | Trading pair (when applicable) |
Order Fields
| Field | Type | Description |
|---|---|---|
orderId | string | Unique order identifier |
clientOrderId | string | Client-provided order ID |
side | string | Order side: "buy" or "sell" |
orderType | string | Order type (e.g., "limitGtc", "market") |
price | string | Order price (empty for market orders) |
quantity | string | Total order quantity |
status | string | Current order status |
filledQuantity | string | Amount already filled |
remainingQuantity | string | Amount remaining to fill |
reason | string | Cancellation/rejection reason |
Trade Fields
| Field | Type | Description |
|---|---|---|
tradeId | string | Unique trade identifier |
fee | string | Trading fee amount |
feeRate | string | Fee rate applied |
realizedPnl | string | Realized P&L from trade |
isTaker | boolean | Whether this was a taker trade |
liquidationPrice | string | Liquidation price (liquidations only) |
Position Snapshot (in Trade Events)
| Field | Type | Description |
|---|---|---|
position.side | string | null | Position side after event |
position.size | string | Position size after event |
position.entryPrice | string | Average entry price |
position.unrealizedPnl | string | Current unrealized P&L |
Margin Update Fields
| Field | Type | Description |
|---|---|---|
accountValue | string | Total account value including unrealized P&L |
availableMargin | string | Margin available for new positions |
totalUnrealizedPnl | string | Sum of unrealized P&L across all positions |
maintenanceMargin | string | Required margin to maintain positions |
initialMargin | string | Required margin to open positions |
withdrawable | string | Amount available for withdrawal |
adjustedAccountValue | string | Account value adjusted for risk |
position | object | Optional position that triggered update |
position.symbol | string | Market symbol |
position.upnl | string | Position unrealized P&L |
position.initialMargin | string | Position initial margin requirement |
position.maintenanceMargin | string | Position maintenance margin requirement |
position.markPrice | string | Current mark price |
Implementation Example
// Subscribe to all subaccount updates
const subscription = {
id: "sub-1",
method: "subscribe",
params: {
type: "subAccountUpdates",
subAccountId: "1867542890123456789"
}
};
ws.send(JSON.stringify(subscription));
// Handle subaccount events
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.method === "subAccountEvent") {
const { eventType, symbol } = message.data;
switch (eventType) {
case "orderPlaced":
console.log(`Order placed: ${message.data.orderId}`);
updateOrdersUI(message.data);
break;
case "orderFilled":
case "orderPartiallyFilled":
console.log(`Order ${eventType}: ${message.data.orderId}`);
updateOrdersUI(message.data);
break;
case "orderCancelled":
console.log(`Order cancelled: ${message.data.orderId}`);
updateOrdersUI(message.data);
break;
case "trade":
console.log(`Trade executed: ${message.data.tradeId}`);
updateTradesUI(message.data);
updatePositionsUI(message.data.position);
break;
case "marginUpdate":
console.log(`Margin updated for account: ${message.data.subAccountId}`);
updateMarginUI(message.data);
if (message.data.position) {
updatePositionMarginUI(message.data.position);
}
break;
case "liquidation":
console.log(`LIQUIDATION: ${symbol} at ${message.data.price}`);
handleLiquidation(message.data);
break;
default:
console.log(`${eventType} event:`, message.data);
}
}
};Benefits
Single Subscription
- One WebSocket connection for all user activity
- Simplified client implementation
- Reduced connection overhead
Complete Context
- Each event includes all relevant data
- Position snapshots after trades
- No need to correlate multiple streams
Consistent Format
- Unified event structure
- Standard field naming
- Predictable data types
Migration from Separate Subscriptions
If you're currently using separate subscriptions:
- Replace multiple subscriptions with single
subAccountUpdatessubscription - Update event handlers to use
eventTypefield and"subAccountEvent"method - Remove correlation logic - each event is self-contained
- Simplify state management - position data included in trade events
- Add margin update handling - receive real-time margin/balance updates
Before (Multiple Subscriptions)
// Old approach - multiple subscriptions
subscribeToOrders(subAccountId, handleOrderUpdate);
subscribeToTrades(subAccountId, handleTradeUpdate);After (Single Subscription)
// New approach - single subscription
subscribeToSubAccountUpdates(subAccountId, (event) => {
switch(event.eventType) {
case "orderPlaced":
case "orderFilled":
case "orderPartiallyFilled":
case "orderCancelled":
case "orderModified":
case "orderRejected":
handleOrderUpdate(event);
break;
case "trade":
handleTradeUpdate(event);
break;
case "marginUpdate":
handleMarginUpdate(event);
break;
case "liquidation":
handleLiquidation(event);
break;
}
});Error Handling
Subscription Errors
{
"id": "sub-1",
"status": 401,
"result": null,
"error": {
"code": 401,
"message": "Invalid subaccount ID"
}
}Common Issues
| Error | Description | Solution |
|---|---|---|
| Invalid subaccount ID | Subaccount doesn't exist or no access | Verify subaccount ownership |
| Authentication required | WebSocket not authenticated | Complete authentication first |
| Rate limit exceeded | Too many events | Implement backpressure handling |
Related Endpoints
- WebSocket Authentication - Required before subscribing to this stream
- Get Positions - Current position state via REST API
- Get Orders - Historical order data via REST API
- Get Trades - Historical trade data via REST API
- Get SubAccount - Account information via REST API