Skip to content

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/subscriptions

Subscription Request

Subscribe to SubAccount Updates

{
  "id": "sub-1",
  "method": "subscribe",
  "params": {
    "type": "subAccountUpdates",
    "subAccountId": "1867542890123456789"
  }
}

Request Parameters

ParameterTypeRequiredDescription
idstringYesClient-generated unique request identifier
methodstringYesMust be "subscribe"
params.typestringYesMust be "subAccountUpdates"
params.subAccountIdstringYesSubaccount ID to receive events for

Event Types

Event TypeDescription
orderPlacedOrder successfully placed on orderbook
orderFilledOrder fully executed
orderPartiallyFilledOrder partially executed
orderCancelledOrder cancelled by user or system
orderModifiedOrder price or quantity modified
orderRejectedOrder rejected due to validation failure
tradeTrade execution with fill details
marginUpdateAccount margin/balance state updated
liquidationPosition 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

FieldTypeDescription
eventTypestringType of event
subAccountIdstringAffected subaccount
timestampintegerEvent timestamp in milliseconds
symbolstringTrading pair (when applicable)

Order Fields

FieldTypeDescription
orderIdstringUnique order identifier
clientOrderIdstringClient-provided order ID
sidestringOrder side: "buy" or "sell"
orderTypestringOrder type (e.g., "limitGtc", "market")
pricestringOrder price (empty for market orders)
quantitystringTotal order quantity
statusstringCurrent order status
filledQuantitystringAmount already filled
remainingQuantitystringAmount remaining to fill
reasonstringCancellation/rejection reason

Trade Fields

FieldTypeDescription
tradeIdstringUnique trade identifier
feestringTrading fee amount
feeRatestringFee rate applied
realizedPnlstringRealized P&L from trade
isTakerbooleanWhether this was a taker trade
liquidationPricestringLiquidation price (liquidations only)

Position Snapshot (in Trade Events)

FieldTypeDescription
position.sidestring | nullPosition side after event
position.sizestringPosition size after event
position.entryPricestringAverage entry price
position.unrealizedPnlstringCurrent unrealized P&L

Margin Update Fields

FieldTypeDescription
accountValuestringTotal account value including unrealized P&L
availableMarginstringMargin available for new positions
totalUnrealizedPnlstringSum of unrealized P&L across all positions
maintenanceMarginstringRequired margin to maintain positions
initialMarginstringRequired margin to open positions
withdrawablestringAmount available for withdrawal
adjustedAccountValuestringAccount value adjusted for risk
positionobjectOptional position that triggered update
position.symbolstringMarket symbol
position.upnlstringPosition unrealized P&L
position.initialMarginstringPosition initial margin requirement
position.maintenanceMarginstringPosition maintenance margin requirement
position.markPricestringCurrent 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:

  1. Replace multiple subscriptions with single subAccountUpdates subscription
  2. Update event handlers to use eventType field and "subAccountEvent" method
  3. Remove correlation logic - each event is self-contained
  4. Simplify state management - position data included in trade events
  5. 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

ErrorDescriptionSolution
Invalid subaccount IDSubaccount doesn't exist or no accessVerify subaccount ownership
Authentication requiredWebSocket not authenticatedComplete authentication first
Rate limit exceededToo many eventsImplement backpressure handling

Related Endpoints