Endpoint
Each connection is scoped to exactly one subaccount. To watch fills across multiple subaccounts, open one connection per subaccount. The server pushes one frame per execution as fills arrive.
Unlike the orders stream — which carries only cumulative per-order totals (traded_qty, average_price, fees_paid) — this stream delivers each discrete execution with its true exchange_trade_id, price, qty, fee, maker/taker flag, and counterparty.
Query parameters
| Parameter | Required | Default | Description |
|---|
subaccount_id | yes | — | UUID of the subaccount whose fills you want to stream. Must belong to the authenticated user. |
key_id / ts / sig | yes (programmatic) | — | Ed25519 signed-handshake params. See Authentication. |
access_token | yes (browser) | — | Supabase JWT for first-party web clients. |
Authentication
Browsers can’t set custom headers on the WebSocket handshake, so the signed-request
flow moves to query params. The signature covers
WS\nPATH\nSORTED_QUERY (excluding key_id/ts/sig)\nTIMESTAMP.
The official SDKs sign the handshake for you. The raw recipe below is for
integrations without an SDK.
The authenticated user must own subaccount_id — otherwise the connection is closed with code 4401. A missing or malformed subaccount_id is closed with 4400.
Protocol
All frames are JSON. Server frames are bytes (orjson-serialized UTF-8). Client frames are accepted but ignored — there is no subscribe/unsubscribe action; the subaccount is fixed at handshake time.
This is a pure live-delta stream — there is no snapshot frame. Backfill history with GET /v1/fills and dedup any overlap against the live stream by the composite fill identity: (exchange_trade_id, exchange_order_id, counterparty_address, counterparty_exchange_order_id). exchange_trade_id alone is not unique — one Polymarket trade produces one fill per matched maker order.
Server → client
connected is sent immediately after the handshake completes.
reconnect is sent during graceful pod shutdown. Reconnect with a small jitter.
Fill payload
| Field | Description |
|---|
river_id | Instrument the fill occurred on. |
river_order_id | Internal id of the order this fill belongs to. Links a fill back to the orders stream’s id. |
client_order_id | Your client-supplied order id, if one was set. |
exchange_order_id | Exchange-side order id. |
exchange_trade_id | Exchange-side trade id. Not unique on its own: a multi-maker trade shares one trade id across several fills. |
exchange_timestamp | Execution time reported by the exchange (UTC). |
price | Execution price of this fill. |
qty | Executed quantity of this fill. |
fee | Fee charged for this execution, in the settlement currency. |
buy_flag | true if this was a buy. |
is_maker | true if you provided liquidity (maker), false if you took it (taker). |
counterparty_address | On-chain counterparty address where applicable, else null. |
counterparty_exchange_order_id | Exchange-side id of the counterparty’s order where applicable, else null. |
Keepalive
Liveness is handled at the WebSocket protocol layer (RFC 6455 PING/PONG control frames). Standard clients (Python websockets, browser WebSocket) reply to server PINGs automatically — no application-level heartbeat is needed.
Minimal client
Using the SDK (handles signing automatically):
Or signing the handshake manually:
Errors
Recoverable problems arrive as an error frame followed by a close. code is stable and safe to branch on; message is human-readable.
code | When |
|---|
unauthorized | API key / JWT was missing or invalid. |
missing_subaccount_id | ?subaccount_id= was not supplied on the handshake. |
invalid_subaccount_id | subaccount_id is not a valid UUID. |
subaccount_forbidden | The subaccount does not belong to the authenticated user. |
Close codes
| Code | Meaning |
|---|
1000 | Normal closure |
1011 | Server-side overflow (client couldn’t keep up with the send rate) |
4400 | Bad request (missing/invalid subaccount_id) |
4401 | Missing or invalid authentication, or subaccount does not belong to the user |
4503 | Server draining for deploy — reconnect with jitter |