Real-time fill feed for authenticated users.
This channel provides per-account trade data with realized PnL — the real-time counterpart to the REST /v1/trade-history endpoint.
Authentication Required: Yes — the channel is always scoped to the authenticated account.
Subscribe
{
"method": "subscribe",
"params": {
"channel": "fills",
"market_ids": [1, 2]
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
market_ids | number[] | No | Filter by market IDs. Empty = all markets |
makers | string[] | No | Account filter. Omit it — the channel uses your authenticated account |
Authentication
Authenticate before subscribing — see Authentication for the EIP-712 flows:
{
"method": "auth_v2",
"params": {
"account": "0x1234567890123456789012345678901234567890",
"signer": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
"message": "WebSocket Authentication",
"nonce": "deadbeefcafebabe0123456789abcdef0123456789abcdef0123456789abcdef",
"signature": "0x..."
}
}Message Format
Update
Sent when a trade executes where you are the maker or the taker. There is no snapshot — historical fills come from the REST API.
{
"channel": "fills",
"type": "update",
"market_id": "1",
"data": {
"id": "0x00000000000058c8000000000126f109000000000000027b-0x0000000400001157000000000126f0fc000000000000026d",
"market_id": "1",
"order_id": "0x00000000000058c8000000000126f109000000000000027b",
"client_order_id": "4078518646",
"side": "BUY",
"price": "63232.6",
"size": "0.000273",
"fee": "0.005178",
"liquidity_indicator": "TAKER",
"time": "1786935048000000000",
"is_liquidation": false,
"is_otc": false,
"realized_pnl": "1.234567",
"realized_pnl_percentage": "2.5",
"avg_price": "62000.1",
"position_side": "BUY",
"leverage": "10",
"margin_mode": 0,
"blockchain_data": {
"tx_hash": "0x68327dc379122ea0caf5572e2aec8d4ec3ce3b2df4ccc44d73f20755c25e3d05",
"block_number": 19329289,
"log_index": 634
}
},
"tx_hash": "0x68327dc379122ea0caf5572e2aec8d4ec3ce3b2df4ccc44d73f20755c25e3d05",
"block_number": 19329289,
"log_index": 634,
"worker_timestamp": "1786935049200112233"
}Update Message Fields
| Field | Type | Description |
|---|---|---|
channel | string | Always "fills" |
type | string | Always "update" |
market_id | string | Market ID |
data | object | Fill object (see below) |
tx_hash | string | Transaction hash |
block_number | number | Blockchain block number |
log_index | number | Log index within the block |
worker_timestamp | string | Server time in nanoseconds |
There is no timestamp or block_timestamp field on this channel — data.time carries the block time of the trade.
Fill Object Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique trade ID — "<maker_order_id>-<taker_order_id>", both 24-byte hex |
market_id | string | Market ID |
order_id | string | Your order's composite ID, hex (0x…) |
client_order_id | string | Your client order ID, if one was sent |
side | string | Your trade side: "BUY" or "SELL" |
price | string | Trade price, decimal |
size | string | Trade size, decimal |
fee | string | Fee you paid, decimal USDC |
liquidity_indicator | string | "MAKER" or "TAKER" |
time | string | Block time of the trade (nanoseconds) |
is_liquidation | boolean | This fill came from a liquidation |
is_otc | boolean | This fill came from an OTC vault trade |
realized_pnl | string | Realized PnL from this fill, decimal. Absent when nothing was realized |
realized_pnl_percentage | string | Realized PnL as a percentage, decimal. Absent when nothing was realized |
avg_price | string | Average entry price of the position after the fill, decimal |
position_side | string | Position side after the fill: "BUY", "SELL", or "" when flat |
leverage | string | Leverage after the fill, decimal |
margin_mode | number | 0 = cross, 1 = isolated — a number, not a string |
blockchain_data | object | Block metadata, mirroring the envelope fields |
Optional fields (client_order_id, the PnL fields, avg_price, position_side, leverage, blockchain_data) are omitted entirely when empty rather than sent as "".
Blockchain Data Object
| Field | Type | Description |
|---|---|---|
tx_hash | string | Transaction hash |
block_number | number | Block number |
log_index | number | Log index within block |
Liquidity Indicator
| Value | Description |
|---|---|
MAKER | You provided liquidity (your order was resting on book) |
TAKER | You removed liquidity (your order crossed the spread) |
Position Side
| Value | Description |
|---|---|
BUY | Long position after this trade |
SELL | Short position after this trade |
"" | Flat (no position) after this trade |
PnL Calculation
realized_pnl: realized profit/loss from this fill, computed asAfter.RealizedPNL − Before.RealizedPNLrealized_pnl_percentage: percentage relative to the position's entry cost
Both are present only when the fill actually realized PnL — that is, when the position shrank 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
Subscribing without authenticating first:
{
"type": "subscribed",
"method": "subscribe",
"status": "error",
"channel": "fills",
"message": "Failed to subscribe to fills: no authenticated account for fills channel"
}Note that type still says subscribed — it echoes the request, not the outcome. Read status.
Testing with wscat
# Connect (mainnet)
wscat -c wss://ws.rise.trade/ws
# Authenticate first (see the Authentication page for how to build the signature)
{"method":"auth_v2","params":{"account":"0x...","signer":"0x...","message":"WebSocket Authentication","nonce":"...","signature":"0x..."}}
# Subscribe to all fills
{"method":"subscribe","params":{"channel":"fills"}}
# Subscribe to market 1 only (BTC/USDC)
{"method":"subscribe","params":{"channel":"fills","market_ids":[1]}}
# Unsubscribe
{"method":"unsubscribe","params":{"channel":"fills"}}Notes
No Snapshot
Nothing is sent at subscription time. Historical fills are available from GET /v1/trade-history.
Price Format
All price, size and fee fields are decimal strings (human-readable), not wei.
Real-time Delivery
Fills are broadcast as soon as the match event is processed from the chain. There is no batching or throttling.
Private Channel
Authenticate before subscribing. The channel is meant to carry your own fills only.
Difference from Trades Channel
| Aspect | Trades Channel | Fills Channel |
|---|---|---|
| Authentication | Not required | Required |
| Scope | All trades (public) | Your fills only (private) |
| PnL Data | No | Yes |
| Position Data | No | Yes (side, leverage, margin) |
| Order ID | Both maker/taker | Your order ID only |
| Fee | Both maker/taker | Your fee only |