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",
"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 |
delegationAdded | Delegation created or refreshed for a signer |
delegationRevoked | Delegation removed for a signer |
funding | Funding payment for open positions |
wickInsurancePositionIncreased | Wick insurance position size increased |
wickInsuranceProtectionActivated | Wick insurance protection activated |
wickInsuranceProtectionCompleted | Wick insurance protection completed |
Order events can include additive optional expiresAt and cancelReason fields. Trade events include additive direction, order (with venueId/clientId), maker, reduceOnly, postOnly, markPrice, entryPrice, and triggeredByLiquidation fields, and the position object now includes netFunding. marginUpdate notifications include an additive debt field. funding notifications include additive paymentTime, fundingTime (replacing the deprecated timestamp and fundingTimestamp). If your client uses an exhaustive switch over eventType, keep a safe default branch so future additive event types do not break message handling.
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",
"order": {
"venueId": "1948058938469519360",
"clientId": "cli-1948058938469519360"
},
"orderId": "1948058938469519360",
"subAccountId": "1867542890123456789",
"symbol": "BTC-USDT",
"side": "buy",
"direction": "open long",
"price": "50010.00",
"quantity": "0.1",
"fee": "5.00",
"feeRate": "0.001",
"realizedPnl": "0.00",
"isTaker": true,
"maker": false,
"reduceOnly": false,
"postOnly": false,
"markPrice": "50025.00",
"entryPrice": "50010.00",
"timestamp": 1704067230000,
"tradedAt": 1704067230000,
"position": {
"adlBucket": 2,
"side": "long",
"size": "0.1",
"entryPrice": "50010.00",
"unrealizedPnl": "0.00",
"netFunding": "0.00"
}
},
"timestamp": 1704067230000
}Trade event fields
| Field | Type | Description |
|---|---|---|
tradeId | string | Unique trade execution identifier |
order | object | Canonical composite order identifier (venueId, optional clientId) |
order.venueId | string | Venue-generated order identifier |
order.clientId | string | Optional client-provided order identifier |
orderId | string | Deprecated legacy venue identifier |
subAccountId | string | Subaccount identifier |
symbol | string | Trading pair symbol |
side | string | Trade side: "buy" or "sell" |
direction | string | Position effect: "open long", "close long", "open short", "close short" |
price | string | Filled price |
quantity | string | Filled quantity |
fee | string | Trading fee amount |
feeRate | string | Fee rate applied |
realizedPnl | string | Realized P&L from position closure |
isTaker | boolean | Deprecated; prefer maker |
maker | boolean | true if the trade was maker (provided liquidity), false if taker |
reduceOnly | boolean | true if the trade reduced an existing position |
postOnly | boolean | true if the order was post-only (maker-only) |
markPrice | string | Mark price at time of trade |
entryPrice | string | Position average entry price at time of trade |
timestamp | integer | Trade timestamp (Unix milliseconds) |
tradedAt | integer | Trade execution timestamp (Unix milliseconds) |
position | object | Post-trade position snapshot |
position.netFunding | string | Net funding accrued on the position (positive = received) |
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",
"debt": "0.00",
"timestamp": 1704067800000,
"position": {
"adlBucket": 3,
"symbol": "BTC-USDT",
"upnl": "125.50",
"initialMargin": "750.00",
"maintenanceMargin": "375.00",
"markPrice": "50125.50"
}
},
"timestamp": 1704067800000
}Margin update fields
| Field | Type | Description |
|---|---|---|
subAccountId | string | Subaccount identifier |
accountValue | string | Total account value (equity) |
availableMargin | string | Margin available for opening new positions |
totalUnrealizedPnl | string | Aggregated unrealized P&L across all positions |
maintenanceMargin | string | Total maintenance margin requirement |
initialMargin | string | Total initial margin requirement |
withdrawable | string | Amount currently withdrawable |
adjustedAccountValue | string | Account value adjusted for unrealized P&L |
debt | string | Outstanding debt on the subaccount (e.g. unpaid funding). "0.00" when no debt is owed. |
timestamp | integer | Event timestamp (Unix milliseconds) |
position | object | Optional per-position snapshot included when the update is triggered by a specific position |
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": {
"adlBucket": 0,
"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,
"paymentTime": 1704067800000,
"fundingTimestamp": 1704067800000,
"fundingTime": 1704067800000
},
"timestamp": 1704067800000
}Funding event fields
| Field | Type | Description |
|---|---|---|
paymentId | string | Unique identifier for the funding payment |
subAccountId | string | Subaccount identifier |
symbol | string | Trading pair symbol |
positionSize | string | Position size at funding time (signed) |
fundingRate | string | Funding rate applied |
payment | string | Funding payment amount (negative = paid out) |
markPrice | string | Mark price used for payment calculation |
timestamp | integer | DEPRECATED - use paymentTime. When the payment was processed (Unix milliseconds) |
paymentTime | integer | When the payment was processed (Unix milliseconds) — replaces timestamp |
fundingTimestamp | integer | DEPRECATED - use fundingTime. Funding period timestamp (Unix milliseconds) |
fundingTime | integer | Funding period timestamp (Unix milliseconds) — replaces fundingTimestamp |
Delegation Added
{
"channel": "subAccountUpdate",
"data": {
"eventType": "delegationAdded",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x1234567890abcdef1234567890abcdef12345678",
"permissions": ["trade", "transfer"],
"expiresAt": 1767225600000,
"addedBy": "0xabcdef1234567890abcdef1234567890abcdef12",
"timestamp": 1704068000000
},
"timestamp": 1704068000000
}Delegation Revoked
{
"channel": "subAccountUpdate",
"data": {
"eventType": "delegationRevoked",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x1234567890abcdef1234567890abcdef12345678",
"timestamp": 1704068100000
},
"timestamp": 1704068100000
}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 |
expiresAt | integer | Order expiry timestamp in milliseconds, when the order has an explicit expiry |
cancelReason | string | Machine-readable cancellation reason when supplied by the backend |
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) |
direction | string | Position direction associated with the fill, when included |
markPrice | string | Mark price at execution time, when included |
entryPrice | string | Average entry price relevant to the execution, when included |
maker | boolean | Whether the fill executed as maker liquidity |
reduceOnly | boolean | Whether the order was reduce-only |
postOnly | boolean | Whether the order was post-only |
triggeredByLiquidation | boolean | Whether the trade was triggered by liquidation flow |
Position Snapshot (in Trade Events)
| Field | Type | Description |
|---|---|---|
position.adlBucket | integer | ADL priority bucket (1–5). 5 = highest risk, 1 = lowest risk. 0 when position is closed. |
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 |
position.netFunding | string | Cumulative net funding received/paid for this position |
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.adlBucket | integer | ADL priority bucket (1–5). 5 = highest risk, 1 = lowest risk. |
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 |
Delegation Fields
| Field | Type | Description |
|---|---|---|
delegateAddress | string | Wallet address whose delegation was added or revoked |
permissions | array | Delegated permissions granted to the signer (delegationAdded only) |
expiresAt | integer | Expiry timestamp in milliseconds when the delegation is time-bounded (delegationAdded only) |
addedBy | string | Wallet address that added or refreshed the delegation (delegationAdded only) |
timestamp | integer | Event timestamp in milliseconds |
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",
subAccountId: "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;
case "delegationAdded":
case "delegationRevoked":
console.log(`Delegation update: ${eventType}`);
handleDelegationUpdate(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;
case "delegationAdded":
case "delegationRevoked":
handleDelegationUpdate(event);
break;
default:
handleUnknownSubAccountEvent(event);
}
});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
