Skip to main content

Subscribe

Single Account

{
  "method": "subscribe",
  "subscription": [{
    "type": "account",
    "user": "FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
  }]
}

Multiple Accounts (Batched)

Subscribe to multiple accounts in a single request:
{
  "method": "subscribe",
  "subscription": [{
    "type": "account",
    "user": [
      "FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7",
      "5Am6JkEHAjYG1itNWRMGpQrxvY8AaqkXCo1TZvenqVux",
      "9J8TUdEWrrcADK913r1Cs7DdqX63VdVU88imfDzT1ypt"
    ]
  }]
}

Response

{
  "type": "subscriptionResponse",
  "topics": [
    "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7",
    "account.5Am6JkEHAjYG1itNWRMGpQrxvY8AaqkXCo1TZvenqVux",
    "account.9J8TUdEWrrcADK913r1Cs7DdqX63VdVU88imfDzT1ypt"
  ]
}
Parameters:
  • user (String or Array): User public key(s) in base58 format
    • Single: "user": "9J8T..."
    • Multiple: "user": ["9J8T...", "5Am6...", "ABC..."]

Initial Snapshot

On subscription, you receive a unified accountSnapshot message with complete account state:
{
  "type": "account",
  "data": {
    "type": "accountSnapshot",
    "margin": {
      "totalBalance": 100000.0,
      "availableBalance": 95000.0,
      "marginUsed": 5000.0,
      "notional": 50000.0,
      "realizedPnl": 1234.5,
      "unrealizedPnl": 567.8,
      "fees": 12.34,
      "funding": 5.67
    },
    "positions": [
      {
        "symbol": "BTC-USD",
        "size": 0.5,
        "price": 100000.0,
        "fairPrice": 101000.0,
        "notional": 50500.0,
        "realizedPnl": 500.0,
        "unrealizedPnl": 500.0,
        "leverage": 5.0,
        "liquidationPrice": 95000.0,
        "fees": 10.0,
        "funding": 2.5,
        "maintenanceMargin": 1000.0,
        "lambda": 0.05,
        "riskAllocation": 5000.0
      }
    ],
    "openOrders": [
      {
        "symbol": "BTC-USD",
        "orderId": "Fpa3oVuL3UzjNANAMZZdmrn6D1Zhk83GmBuJpuAWG51F",
        "price": 102000.0,
        "originalSize": 0.1,
        "size": 0.1,
        "filledSize": 0.0,
        "vwap": 0.0,
        "isBuy": true,
        "maker": true,
        "reduceOnly": false,
        "tif": "gtc",
        "status": "placed",
        "timestamp": 1763316177219383423
      }
    ],
    "leverageSettings": [
      { "symbol": "BTC-USD", "leverage": 5.0 },
      { "symbol": "ETH-USD", "leverage": 3.0 }
    ]
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Account Snapshot Fields

Margin:
FieldDescription
totalBalanceTotal margin balance
availableBalanceAvailable margin (total - maintenance margin)
marginUsedMaintenance margin used
notionalTotal notional value of all positions
realizedPnlRealized profit/loss
unrealizedPnlUnrealized profit/loss
feesTotal fees paid
fundingTotal funding paid/received
Positions:
FieldDescription
symbolMarket symbol
sizePosition size (positive=long, negative=short)
priceVWAP entry price
fairPriceCurrent fair/mark price
notionalNotional value (size × fair_price)
realizedPnlRealized P&L for this position
unrealizedPnlUnrealized P&L for this position
leveragePosition leverage
liquidationPriceLiquidation price
feesFees paid for this position
fundingFunding paid/received
maintenanceMarginRequired maintenance margin
lambdaLambda (risk parameter)
riskAllocationRisk allocation (C_i)
Open Orders:
FieldDescription
symbolMarket symbol
orderIdOrder ID (base58, use for cancellation)
priceOrder price
originalSizeOriginal order size
sizeCurrent remaining size
filledSizeFilled size
vwapVWAP fill price (0 if no fills)
isBuytrue for buy, false for sell
makertrue if maker order
reduceOnlytrue if reduce-only
tifTime in force (gtc, ioc, postOnly)
statusOrder status
timestampOrder placement time (nanoseconds)
Leverage Settings:
FieldDescription
symbolMarket symbol
leverageMaximum leverage (1.0 to 50.0)

Real-time Delta Updates

After the initial snapshot, you receive delta updates for changes:

Margin Update

{
  "type": "account",
  "data": {
    "type": "marginUpdate",
    "totalBalance": 100500.0,
    "availableBalance": 95500.0,
    "marginUsed": 5000.0,
    "notional": 50500.0,
    "realizedPnl": 1234.5,
    "unrealizedPnl": 567.8,
    "fees": 12.34,
    "funding": 5.67
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Position Update

{
  "type": "account",
  "data": {
    "type": "positionUpdate",
    "symbol": "BTC-USD",
    "size": 0.5,
    "price": 100000.0,
    "realizedPnl": 500.0,
    "unrealizedPnl": 500.0,
    "leverage": 5.0,
    "liquidationPrice": 95000.0,
    "fairPrice": 101000.0,
    "notional": 50500.0,
    "fees": 10.0,
    "funding": 2.5,
    "maintenanceMargin": 1000.0,
    "lambda": 0.05,
    "riskAllocation": 5000.0
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Order Update

All order state changes are delivered via unified orderUpdate messages with full state information.
{
  "type": "account",
  "data": {
    "type": "orderUpdate",
    "status": "placed",
    "symbol": "BTC-USD",
    "orderId": "Fpa3oVuL3UzjNANAMZZdmrn6D1Zhk83GmBuJpuAWG51F",
    "price": 102000.0,
    "originalSize": 0.1,
    "size": 0.1,
    "filledSize": 0.0,
    "vwap": 0.0,
    "isBuy": true,
    "maker": true,
    "timestamp": 1763316177219383423,
    "reason": null
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Order Update Fields

FieldDescription
statusOrder status (see table below)
symbolMarket symbol
orderIdOrder ID (base58)
priceOrder price
originalSizeOriginal order size
sizeCurrent remaining size
filledSizeAmount filled
vwapVWAP fill price
isBuytrue for buy orders
makertrue if maker order
timestampOrder timestamp (nanoseconds)
reasonRejection/cancellation reason (optional)

Order Status Values

StatusTerminalDescription
placedNoOrder placed and resting on book
workingNoOrder has partial fills, still resting
filledYesOrder fully filled
partiallyFilledYesOrder partially filled and terminal
cancelledYesOrder cancelled by user
cancelledRiskLimitYesCancelled due to risk limit
cancelledSelfCrossingYesCancelled due to self-crossing (STP)
cancelledReduceOnlyYesCancelled - would not reduce position
cancelledIOCYesIOC expired without full fill
rejectedCrossingYesPost-only rejected for crossing
rejectedDuplicateYesDuplicate order ID
rejectedRiskLimitYesRejected due to risk limit
rejectedInvalidYesInvalid order parameters

Order Update Examples

{
  "type": "account",
  "data": {
    "type": "orderUpdate",
    "status": "placed",
    "symbol": "BTC-USD",
    "orderId": "Fpa3oVuL3UzjNANAMZZdmrn6D1Zhk83GmBuJpuAWG51F",
    "price": 100000.0,
    "originalSize": 0.1,
    "size": 0.1,
    "filledSize": 0.0,
    "vwap": 0.0,
    "isBuy": true,
    "maker": true,
    "timestamp": 1763316177219383423,
    "reason": null
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Fill Update

Emitted on each trade execution (in addition to orderUpdate):
{
  "type": "account",
  "data": {
    "type": "fill",
    "symbol": "BTC-USD",
    "orderId": "Fpa3oVuL3UzjNANAMZZdmrn6D1Zhk83GmBuJpuAWG51F",
    "price": 102000.0,
    "size": 0.05,
    "isBuy": true,
    "timestamp": 1763316177219383423,
    "maker": false
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Leverage Update

{
  "type": "account",
  "data": {
    "type": "leverageUpdate",
    "leverage": [
      { "symbol": "BTC-USD", "leverage": 5.0 }
    ]
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Update Frequency

Update TypeFrequency
Initial SnapshotImmediately on subscription
Order UpdatesReal-time (immediate)
FillsReal-time (immediate)
Leverage UpdatesOn change

Example: Monitor Account

const WebSocket = require('ws');

const PUBLIC_KEY = 'FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7';
const ws = new WebSocket('wss://exchange-wss.bulk.trade');

ws.on('open', () => {
  console.log('Connected');
  
  // Subscribe to account updates
  ws.send(JSON.stringify({
    method: 'subscribe',
    subscription: [{
      type: 'account',
      user: PUBLIC_KEY
    }]
  }));
});

ws.on('message', (data) => {
  const message = JSON.parse(data);
  
  if (message.type === 'subscriptionResponse') {
    console.log('Subscribed to:', message.topics);
    return;
  }
  
  if (message.type === 'account') {
    const { type, ...details } = message.data;
    
    switch(type) {
      case 'accountSnapshot':
        console.log('Account snapshot:', details);
        console.log('Positions:', details.positions);
        console.log('Open orders:', details.openOrders);
        break;
      case 'marginUpdate':
        console.log('Margin update:', details);
        break;
      case 'positionUpdate':
        console.log('Position update:', details);
        break;
      case 'orderUpdate':
        console.log(`Order ${details.status}:`, details);
        break;
      case 'fill':
        console.log('Fill:', details);
        break;
      case 'leverageUpdate':
        console.log('Leverage updated:', details);
        break;
    }
  }
});

Unsubscribe

{
  "method": "unsubscribe",
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}