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):
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
{
"method": "subAccountEvent",
"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"
}
}Order Filled
{
"method": "subAccountEvent",
"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"
}
}Order Cancelled
{
"method": "subAccountEvent",
"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"
}
}Order Rejected
{
"method": "subAccountEvent",
"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"
}
}Trade Execution
{
"method": "subAccountEvent",
"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"
}
}
}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,
"position": {
"side": null,
"size": "0.0",
"entryPrice": "0.0",
"unrealizedPnl": "0.00"
}
}
}Funding
{
"method": "subAccountEvent",
"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
}
}Wick Insurance - Position Increased
{
"method": "subAccountEvent",
"data": {
"eventType": "wickInsurancePositionIncreased",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"oldQuantity": "0.1",
"newQuantity": "0.2",
"timestamp": 1704067200000
}
}Wick Insurance - Protection Activated
{
"method": "subAccountEvent",
"data": {
"eventType": "wickInsuranceProtectionActivated",
"subAccountId": "1867542890123456789",
"expiredTime": 1704067800000,
"timestamp": 1704067200000
}
}Wick Insurance - Protection Completed
{
"method": "subAccountEvent",
"data": {
"eventType": "wickInsuranceProtectionCompleted",
"subAccountId": "1867542890123456789",
"protectionId": "12345",
"expiredTime": 1704067800000,
"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.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