Fills Channel

Real-time fill feed for authenticated users.

This channel provides per-account trade data with realized PnL, similar to the REST /v1/trade-history endpoint but in real-time.

Authentication Required: Yes - This channel requires authentication and automatically filters fills to the authenticated account.

Subscribe

{
  "method": "subscribe",
  "params": {
    "channel": "fills",
    "market_ids": [1, 2]
  }
}
ParameterTypeRequiredDescription
market_idsnumber[]NoFilter by market IDs. Empty = all markets

Note: The account is automatically determined from the authenticated session. You cannot subscribe to fills for other accounts.

Authentication

Before subscribing to the fills channel, you must authenticate:

{
  "method": "auth",
  "params": {
    "account": "0x1234567890123456789012345678901234567890",
    "signer": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "message": "WebSocket Authentication",
    "nonce": 1703123456,
    "signature": "0x..."
  }
}

Message Format

Update

Sent immediately when a trade occurs where you are either the maker or taker. There is no snapshot for this channel - historical fills are available via the REST API.

{
  "channel": "fills",
  "type": "update",
  "market_id": "1",
  "data": {
    "id": "318622-318647",
    "market_id": "1",
    "order_id": "318622",
    "side": "BUY",
    "price": "92995",
    "size": "0.144208",
    "fee": "0.0005",
    "liquidity_indicator": "MAKER",
    "time": "1705317000000000000",
    "is_liquidation": false,
    "realized_pnl": "123.456",
    "realized_pnl_percentage": "2.5",
    "avg_price": "92000",
    "position_side": "BUY",
    "leverage": "10",
    "margin_mode": "cross",
    "blockchain_data": {
      "tx_hash": "0xabc123def456...",
      "block_number": 33759944,
      "log_index": 211
    }
  },
  "tx_hash": "0xabc123def456...",
  "block_number": 33759944,
  "log_index": 211,
  "block_timestamp": "1705317000000000000",
  "timestamp": "1705317000123456789"
}

Update Message Fields

FieldTypeDescription
channelstringAlways "fills"
typestringAlways "update"
market_idstringMarket ID
dataobjectFill object (see below)
tx_hashstringTransaction hash
block_numbernumberBlockchain block number
log_indexnumberLog index within the block
block_timestampstringBlockchain timestamp (nanoseconds)
timestampstringServer timestamp (nanoseconds)

Fill Object Fields

FieldTypeDescription
idstringUnique trade ID (maker_order_id-taker_order_id)
market_idstringMarket ID
order_idstringYour order ID (maker or taker)
sidestringYour trade side: "BUY" or "SELL"
pricestringTrade price (decimal)
sizestringTrade size (decimal)
feestringFee you paid (decimal)
liquidity_indicatorstring"MAKER" or "TAKER"
timestringTrade time (nanoseconds)
is_liquidationbooleanWhether this is a liquidation
realized_pnlstringRealized PnL from this trade (decimal, optional)
realized_pnl_percentagestringRealized PnL percentage (decimal, optional)
avg_pricestringAverage entry price after trade (decimal, optional)
position_sidestringPosition side after trade: "BUY", "SELL", or ""
leveragestringLeverage (decimal, optional)
margin_modestring"cross" or "isolated" (optional)
blockchain_dataobjectBlockchain metadata (optional)

Blockchain Data Object

FieldTypeDescription
tx_hashstringTransaction hash
block_numbernumberBlock number
log_indexnumberLog index within block

Liquidity Indicator

ValueDescription
MAKERYou provided liquidity (your order was resting on book)
TAKERYou removed liquidity (your order crossed the spread)

Position Side

ValueDescription
BUYLong position after this trade
SELLShort position after this trade
""Flat (no position) after this trade

PnL Calculation

  • realized_pnl: The realized profit/loss from this trade, calculated as After.RealizedPNL - Before.RealizedPNL
  • realized_pnl_percentage: Percentage relative to the position's entry cost

PnL fields are only present when there is realized PnL (position size decreased or flipped).

Examples

Subscribe to all fills

{
  "method": "subscribe",
  "params": {
    "channel": "fills"
  }
}

Subscribe to specific markets

{
  "method": "subscribe",
  "params": {
    "channel": "fills",
    "market_ids": [1, 2]
  }
}

Unsubscribe

{
  "method": "unsubscribe",
  "params": {
    "channel": "fills"
  }
}

Error Responses

Authentication Required

If you try to subscribe without authenticating first:

{
  "method": "subscribe",
  "status": "error",
  "channel": "fills",
  "message": "Failed to subscribe to fills: authentication required for fills channel"
}

Testing with wscat

# Connect
wscat -c ws://localhost:8090/ws

# Authenticate first (replace with valid signature)
{"method":"auth","params":{"account":"0x...","signer":"0x...","message":"WebSocket Authentication","nonce":1703123456,"signature":"0x..."}}

# Subscribe to all fills
{"method":"subscribe","params":{"channel":"fills"}}

# Subscribe to market 1 only
{"method":"subscribe","params":{"channel":"fills","market_ids":[1]}}

# Unsubscribe
{"method":"unsubscribe","params":{"channel":"fills"}}

Notes

No Snapshot

Unlike other channels (orders, positions), the fills channel does not send a snapshot on subscription. Historical fills are available via the REST /v1/trade-history endpoint.

Price Format

All price and size fields are in decimal format (human-readable), not wei.

  • Example price: "92995" = $92,995
  • Example size: "0.144208" = 0.144208 units

Real-time Delivery

Fills are broadcast immediately when the MatchOrder event is processed from the blockchain. There is no batching or throttling.

Private Channel

This channel requires authentication. You will only receive fills for your own account.

Difference from Trades Channel

AspectTrades ChannelFills Channel
AuthenticationNot requiredRequired
ScopeAll trades (public)Your fills only (private)
PnL DataNoYes
Position DataNoYes (side, leverage, margin)
Order IDBoth maker/takerYour order ID only
FeeBoth maker/takerYour fee only