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:
| Field | Description |
|---|
totalBalance | Total margin balance |
availableBalance | Available margin (total - maintenance margin) |
marginUsed | Maintenance margin used |
notional | Total notional value of all positions |
realizedPnl | Realized profit/loss |
unrealizedPnl | Unrealized profit/loss |
fees | Total fees paid |
funding | Total funding paid/received |
Positions:
| Field | Description |
|---|
symbol | Market symbol |
size | Position size (positive=long, negative=short) |
price | VWAP entry price |
fairPrice | Current fair/mark price |
notional | Notional value (size × fair_price) |
realizedPnl | Realized P&L for this position |
unrealizedPnl | Unrealized P&L for this position |
leverage | Position leverage |
liquidationPrice | Liquidation price |
fees | Fees paid for this position |
funding | Funding paid/received |
maintenanceMargin | Required maintenance margin |
lambda | Lambda (risk parameter) |
riskAllocation | Risk allocation (C_i) |
Open Orders:
| Field | Description |
|---|
symbol | Market symbol |
orderId | Order ID (base58, use for cancellation) |
price | Order price |
originalSize | Original order size |
size | Current remaining size |
filledSize | Filled size |
vwap | VWAP fill price (0 if no fills) |
isBuy | true for buy, false for sell |
maker | true if maker order |
reduceOnly | true if reduce-only |
tif | Time in force (gtc, ioc, postOnly) |
status | Order status |
timestamp | Order placement time (nanoseconds) |
Leverage Settings:
| Field | Description |
|---|
symbol | Market symbol |
leverage | Maximum 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
| Field | Description |
|---|
status | Order status (see table below) |
symbol | Market symbol |
orderId | Order ID (base58) |
price | Order price |
originalSize | Original order size |
size | Current remaining size |
filledSize | Amount filled |
vwap | VWAP fill price |
isBuy | true for buy orders |
maker | true if maker order |
timestamp | Order timestamp (nanoseconds) |
reason | Rejection/cancellation reason (optional) |
Order Status Values
| Status | Terminal | Description |
|---|
placed | No | Order placed and resting on book |
working | No | Order has partial fills, still resting |
filled | Yes | Order fully filled |
partiallyFilled | Yes | Order partially filled and terminal |
cancelled | Yes | Order cancelled by user |
cancelledRiskLimit | Yes | Cancelled due to risk limit |
cancelledSelfCrossing | Yes | Cancelled due to self-crossing (STP) |
cancelledReduceOnly | Yes | Cancelled - would not reduce position |
cancelledIOC | Yes | IOC expired without full fill |
rejectedCrossing | Yes | Post-only rejected for crossing |
rejectedDuplicate | Yes | Duplicate order ID |
rejectedRiskLimit | Yes | Rejected due to risk limit |
rejectedInvalid | Yes | Invalid 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 Type | Frequency |
|---|
| Initial Snapshot | Immediately on subscription |
| Order Updates | Real-time (immediate) |
| Fills | Real-time (immediate) |
| Leverage Updates | On 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"
}