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
Public subscriptions (candles, marketPrices, orderbook, trades):
wss://papi.synthetix.io/v1/ws/infoPrivate subscriptions (subAccountUpdates - requires authentication):
wss://papi.synthetix.io/v1/ws/tradeSubscription Request
Subscribe to SubAccount Updates
{
"id": "sub-1",
"method": "subscribe",
"params": {
"type": "subAccountUpdates",
"sub_account_id": "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.sub_account_id | 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 |
funding | Funding payment for open positions |
wickInsurancePositionIncreased | Wick insurance position size increased |
wickInsuranceProtectionActivated | Wick insurance protection activated |
wickInsuranceProtectionCompleted | Wick insurance protection completed |
User Event Messages
Order Placed
{
"channel": "subAccountUpdate",
"data": {
"eventType": "orderPlaced",
"subAccountId": "1867542890123456789",
"orderId": "1948058938469519360",
"symbol": "BTC-USDT",
"timestamp": 1704067200000,
"side": "buy",
"orderType": "limit",
"price": "50000.00",
"quantity": "0.1",
"filledQuantity": "0",
"remainingQuantity": "0.1",
"direction": "long",
"status": "OrderStatePlaced",
"createdAt": 1704067199998,
"placedAt": 1704067200000,
"updatedAt": 1704067200000,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
},
"timestamp": 1704067200000
}Order Filled
{
"channel": "subAccountUpdate",
"data": {
"eventType": "orderFilled",
"subAccountId": "1867542890123456789",
"orderId": "1948058938469519360",
"symbol": "BTC-USDT",
"timestamp": 1704067210000,
"side": "buy",
"orderType": "limit",
"price": "50000.00",
"quantity": "0.1",
"filledQuantity": "0.1",
"remainingQuantity": "0",
"direction": "long",
"status": "OrderStateFilled",
"createdAt": 1704067199998,
"placedAt": 1704067200000,
"updatedAt": 1704067210000,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
},
"timestamp": 1704067210000
}Order Cancelled
{
"channel": "subAccountUpdate",
"data": {
"eventType": "orderCancelled",
"subAccountId": "1867542890123456789",
"orderId": "1948058938469519360",
"symbol": "BTC-USDT",
"timestamp": 1704067220000,
"side": "buy",
"orderType": "limit",
"price": "50000.00",
"quantity": "0.1",
"filledQuantity": "0",
"remainingQuantity": "0.1",
"direction": "long",
"status": "OrderStateCancelled",
"cancelledAt": 1704067220000,
"createdAt": 1704067199998,
"placedAt": 1704067200000,
"updatedAt": 1704067220000,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
},
"timestamp": 1704067220000
}Order Rejected
{
"channel": "subAccountUpdate",
"data": {
"eventType": "orderRejected",
"subAccountId": "1867542890123456789",
"orderId": "1948058938469519360",
"symbol": "BTC-USDT",
"timestamp": 1704067200000,
"side": "buy",
"orderType": "limit",
"price": "50000.00",
"quantity": "0.1",
"direction": "long",
"status": "OrderStateRejected",
"reason": "Insufficient margin",
"createdAt": 1704067199998,
"updatedAt": 1704067200000,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
},
"timestamp": 1704067200000
}Trade Execution
{
"channel": "subAccountUpdate",
"data": {
"eventType": "trade",
"tradeId": "123456790",
"orderId": "1948058938469519360",
"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,
"tradedAt": 1704067230000,
"position": {
"side": "long",
"size": "0.1",
"entryPrice": "50010.00",
"unrealizedPnl": "0.00"
}
},
"timestamp": 1704067230000
}Margin Update
{
"channel": "subAccountUpdate",
"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"
}
},
"timestamp": 1704067800000
}Liquidation
{
"channel": "subAccountUpdate",
"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,
"position": {
"side": null,
"size": "0.0",
"entryPrice": "0.0",
"unrealizedPnl": "0.00"
}
},
"timestamp": 1704067900000
}Funding
{
"channel": "subAccountUpdate",
"data": {
"eventType": "funding",
"paymentId": "fp_1958787130134106112",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"positionSize": "0.2",
"fundingRate": "0.0000125",
"payment": "-3.625312",
"markPrice": "50000.00",
"timestamp": 1704067800000
},
"timestamp": 1704067800000
}Wick Insurance - Position Increased
{
"channel": "subAccountUpdate",
"data": {
"eventType": "wickInsurancePositionIncreased",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"oldQuantity": "0.1",
"newQuantity": "0.2",
"timestamp": 1704067200000
},
"timestamp": 1704067200000
}Wick Insurance - Protection Activated
{
"channel": "subAccountUpdate",
"data": {
"eventType": "wickInsuranceProtectionActivated",
"subAccountId": "1867542890123456789",
"expiredTime": 1704067800000,
"timestamp": 1704067200000
},
"timestamp": 1704067200000
}Wick Insurance - Protection Completed
{
"channel": "subAccountUpdate",
"data": {
"eventType": "wickInsuranceProtectionCompleted",
"subAccountId": "1867542890123456789",
"protectionId": "12345",
"expiredTime": 1704067800000,
"timestamp": 1704067200000
},
"timestamp": 1704067200000
}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: "limit", "market", "stopLoss", "takeProfit" |
price | string | Order price (empty for market orders) |
quantity | string | Total order quantity |
filledQuantity | string | Amount already filled |
remainingQuantity | string | Amount remaining to fill |
direction | string | Position direction: "long" or "short" |
status | string | Order status (see Order Status Values below) |
reason | string | Cancellation/rejection reason |
createdAt | integer | Order creation timestamp in milliseconds |
placedAt | integer | Order placement timestamp in milliseconds |
cancelledAt | integer | Order cancellation timestamp in milliseconds (cancelled orders only) |
updatedAt | integer | Order last update timestamp in milliseconds |
Order Status Values
| Status | Description |
|---|---|
OrderStatePlaced | Order placed on orderbook |
OrderStatePartiallyFilled | Order partially executed |
OrderStateFilled | Order fully executed |
OrderStateCancelled | Order cancelled |
OrderStateRejected | Order rejected |
OrderStateModify | Order modification in progress |
OrderStateModified | Order successfully modified |
Trade Fields
| Field | Type | Description |
|---|---|---|
tradeId | string | Unique trade identifier |
orderId | string | Order ID that generated this trade |
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 |
timestamp | integer | Event timestamp in milliseconds (deprecated, use tradedAt) |
tradedAt | integer | Trade execution timestamp in milliseconds |
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 |
Funding Fields
| Field | Type | Description |
|---|---|---|
paymentId | string | Unique funding payment identifier |
symbol | string | Trading pair |
positionSize | string | Position size at time of funding |
fundingRate | string | Funding rate applied |
payment | string | Funding payment amount (negative = paid, positive = received) |
markPrice | string | Mark price at time of funding |
Wick Insurance Fields
| Field | Type | Description |
|---|---|---|
symbol | string | Trading pair (position increased only) |
oldQuantity | string | Previous position size (position increased only) |
newQuantity | string | New position size (position increased only) |
expiredTime | integer | Protection expiry time in milliseconds (protection events) |
protectionId | string | Protection identifier (protection completed only) |
Implementation Example
// Subscribe to all subaccount updates
const subscription = {
id: "sub-1",
method: "subscribe",
params: {
type: "subAccountUpdates",
sub_account_id: "1867542890123456789"
}
};
ws.send(JSON.stringify(subscription));
// Handle subaccount events
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.channel === "subAccountUpdate") {
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"subAccountUpdate"channel - 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