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,
        "allocMargin": 2500.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)
allocMarginAllocated margin for this position
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 (placed, working, etc.)
timestampOrder placement time (nanoseconds)
Leverage Settings (included in initial snapshot only):
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,
    "allocMargin": 2500.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"
}
Legacy order messages: For backwards compatibility, order messages with status: "placed" or status: "cancelled" may still be emitted alongside orderUpdate. New integrations should use orderUpdate messages exclusively.

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"
}

Liquidation Event

Emitted when the account is liquidated:
{
  "type": "account",
  "data": {
    "type": "liquidation",
    "symbol": "BTC-USD",
    "price": 95000.0,
    "size": 0.5,
    "isBuy": false,
    "marginPrior": 5000.0,
    "marginAfter": 0.0,
    "timestamp": 1763316177219383423
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}
FieldDescription
symbolMarket symbol
priceLiquidation price
sizePosition size that was liquidated
isBuyDirection of the liquidation fill
marginPriorMargin balance before liquidation
marginAfterMargin balance after liquidation
timestampTimestamp (nanoseconds)

ADL (Auto-Deleveraging) Event

Emitted when the account is auto-deleveraged:
{
  "type": "account",
  "data": {
    "type": "ADL",
    "symbol": "BTC-USD",
    "price": 95000.0,
    "size": 0.5,
    "isBuy": false,
    "timestamp": 1763316177219383423
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}
FieldDescription
symbolMarket symbol
priceADL price
sizePosition size that was auto-deleveraged
isBuyDirection of the ADL fill
timestampTimestamp (nanoseconds)

Cancel Rejected

Emitted when a single-order cancel is rejected (e.g. order not found):
{
  "type": "account",
  "data": {
    "type": "cancelOneRejected",
    "symbol": "BTC-USD",
    "orderId": "Fpa3oVuL3UzjNANAMZZdmrn6D1Zhk83GmBuJpuAWG51F",
    "reason": "Order not found",
    "timestamp": 1763316177219383423
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Cancel All Rejected

Emitted when cancel-all is rejected (e.g. no open orders):
{
  "type": "account",
  "data": {
    "type": "cancelAllRejected",
    "symbol": "BTC-USD",
    "reason": "No open orders",
    "timestamp": 1763316177219383423
  },
  "topic": "account.FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7"
}

Leverage Update

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

Update Frequency

  • Initial Snapshot: Sent immediately on subscription (single unified accountSnapshot message).
  • Event-driven: Margin, positions, and leverage settings are sent when they change.
  • Real-time: Immediately on all order state changes (orderUpdate), including:
    • Order placement (placed, resting)
    • Partial fills (working)
    • Full fills (filled)
    • Cancellations (cancelled, cancelledRiskLimit, cancelledIOC, etc.)
    • Rejections (rejectedCrossing, rejectedRiskLimit, etc.)

Example: Monitor Account

const WebSocket = require('ws');

const PUBLIC_KEY = 'FuueqefENiGEW6uMqZQgmwjzgpnb85EgUcZa5Em4PQh7';
const ws = new WebSocket('wss://exchange-ws1.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;
      case 'liquidation':
        console.log('Liquidation:', details);
        break;
      case 'ADL':
        console.log('ADL:', details);
        break;
      case 'cancelOneRejected':
        console.log('Cancel rejected:', details);
        break;
      case 'cancelAllRejected':
        console.log('Cancel all rejected:', details);
        break;
    }
  }
});

Unsubscribe

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