fills to get one clean event per trade, or settlements for the full transaction lifecycle.
Fills
Individual trades, one per message. Pre-confirmation, flat format, no array parsing. The fastest way to track trades.
Settlements
Full transaction bundles with all fills in a
trades[] array plus status lifecycle tracking.Trades
Confirmed on-chain fills. Same data as settlements but after block confirmation with exact receipt values.
Combos
Polymarket combo executions and confirmations with enriched leg metadata.
Up to 5 second edge
Settlements and fills detected before on-chain confirmation. Typically 3-5 seconds (1-2 blocks) early.
Filtered subscriptions
Subscribe by wallet, token, market slug, side, size, or event type. Only receive what you need.
Enriched events
Every event includes market title, outcome name, slug, and image. No secondary lookups needed.
Crypto price feeds
Real-time prices for BTC, ETH, SOL, BNB, XRP, DOGE, and HYPE (~1/second each). Subscribe with
"type": "chainlink" on the same connection.Oracle resolution stream
UMA Optimistic Oracle events: market resolutions, disputes, proposals, and admin actions. Subscribe with
"type": "oracle" to track the full resolution lifecycle.Quick start
Stream trades (30 seconds)
Save this as You’ll see individual trades streaming in, one per line. Each event is a single fill with clear fields for outcome, side, price, shares, and the wallet involved.
stream.js and run with API_KEY=pn_live_... node stream.js:What you'll see
Every message is one flat event with everything you need. Here’s a real captured fill:
block_number: null means this was detected before the block confirmed. Pre-confirmation delivery, 3-5 seconds ahead of on-chain settlement. One event per fill, no arrays to iterate, all fields included.fills vs settlements — both stream the same trades at the same speed. fills gives you one flat event per trade (simplest). settlements gives you the full transaction bundle with a trades[] array and lifecycle tracking via status_update events. Start with fills, move to settlements when you need the full lifecycle. See Subscriptions for all options.Settlement-based quick start (full lifecycle)
Settlement-based quick start (full lifecycle)
If you need the full transaction format with nested fills and status lifecycle, subscribe to See Settlement Event for the full field reference.
settlements instead:Connection URL
pn_live_ or qm_live_ are accepted.
Connection limits
Most apps only need one Event WebSocket connection. A single connection can carry multiple filtered subscriptions at once, including fills, settlements, trades, blocks, wallet filters, market filters, oracle events, and Chainlink price feeds.| Tier | Concurrent Event WebSockets | Filter items per subscription | Session limit |
|---|---|---|---|
| Free | 1 | 10,000 | 1 hour/day |
| Starter ($50/mo) | 10 | 10,000 | Unlimited |
| Growth ($200/mo) | 50 | 10,000 | Unlimited |
| Enterprise ($750/mo) | Unlimited | Custom | Unlimited |
Event WebSocket limits apply to
ws.polynode.dev. Orderbook WebSocket limits for ob.polynode.dev are listed separately in the Orderbook Stream docs.Multiple streams, one connection
PolyNode supports multiple subscription types on the same WebSocket:| Stream | Purpose | Subscribe |
|---|---|---|
| Fills | Individual pre-confirmation trades, one flat event per fill. Simplest format. | {"action":"subscribe","type":"fills"} |
| Settlements | Pre-confirmation transaction bundles with all fills in a trades[] array (default) | {"action":"subscribe","type":"settlements"} |
| Trades | Confirmed on-chain fills with exact receipt values | {"action":"subscribe","type":"trades"} |
| Prices | Price-moving settlement and trade events for specific markets | {"action":"subscribe","type":"prices"} |
| Combos | Polymarket combo executions and confirmations with enriched legs | {"action":"subscribe","type":"combos"} |
| Blocks | New Polygon block notifications with Polymarket stats | {"action":"subscribe","type":"blocks"} |
| Wallets | All activity for specified wallets | {"action":"subscribe","type":"wallets","filters":{"wallets":["0x..."]}} |
| Markets | All activity for specified markets | {"action":"subscribe","type":"markets","filters":{"tokens":["..."]}} |
| Deposits | USDC.e and Polymarket USD deposit/withdrawal activity | {"action":"subscribe","type":"deposits"} |
| Large Trades | Whale alerts ($1K+ by default) | {"action":"subscribe","type":"large_trades"} |
| Global | Full firehose of the default public event set | {"action":"subscribe","type":"global"} |
| Oracle | UMA resolution lifecycle (resolutions, disputes, flags) | {"action":"subscribe","type":"oracle"} |
| Chainlink | Real-time crypto prices (7 feeds, ~1/sec each) | {"action":"subscribe","type":"chainlink"} |
Heartbeat
The server sends a heartbeat every 30 seconds:- A WebSocket-level Ping frame (handled automatically by WS clients)
- A text message:
{"type": "heartbeat", "ts": 1772386305181}
Application-level keepalive
Send a ping message to confirm the connection is alive:Connection lifecycle
Error handling
Invalid messages return structured errors:| Error code | Cause |
|---|---|
invalid_json | Message is not valid JSON |
invalid_message | Unknown action or missing required fields |
unresolved_slugs | Slug not found in market metadata |
unresolved_condition_ids | Condition ID not found in metadata |
Reconnection
PolyNode does not send a close frame before disconnecting. Implement reconnection with exponential backoff and use thesince filter to fill any gaps:
since filter returns all events after that timestamp within your tier’s lookback window (free: 30s, starter: 2min, growth/enterprise: 5min). When since is set, it overrides snapshot_count. For outages longer than your lookback window, use the REST API to backfill.
