Skip to main content

Documentation Index

Fetch the complete documentation index at: https://polynode.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Subscribe message

Send a JSON message after connecting to start receiving events:
{
  "action": "subscribe",
  "type": "settlements",
  "filters": {
    "wallets": ["0x1234..."],
    "tokens": ["21742633..."],
    "slugs": ["bitcoin-100k-2026"],
    "condition_ids": ["0xabc..."],
    "side": "BUY",
    "status": "pending",
    "min_size": 100,
    "max_size": 10000,
    "event_types": ["settlement", "status_update"],
    "snapshot_count": 50,
    "since": 1774412600000
  }
}
All fields except action are optional.

Subscription types

The type field selects a preset of event types. If you also set filters.event_types, it overrides the preset.
fills
string
Events: settlement (reformatted as one flat event per fill)The simplest way to stream Polymarket trades. Each fill arrives as its own flat event with clear fields: user (the wallet whose fill this is), side, price, shares_normalized, token_label (outcome name), and title (market name). No arrays to iterate, no nested objects to unpack.Pre-confirmation delivery, 3-5 seconds before on-chain settlement. Same speed as settlements, just a cleaner format for per-trade tracking.
const ws = new WebSocket("wss://ws.polynode.dev/ws?key=YOUR_KEY");

ws.on("open", () => {
  ws.send(JSON.stringify({ action: "subscribe", type: "fills" }));
});

ws.on("message", (raw) => {
  const msg = JSON.parse(raw);
  if (msg.type !== "event") return;

  const fill = msg.data;
  console.log({
    outcome: fill.token_label,
    side: fill.side,
    price: fill.price,
    shares: fill.shares_normalized,
    user: fill.user,
    market: fill.title
  });
});
Example event:
{
  "type": "event",
  "data": {
    "order_hash": "0x7b281ecba532e471...",
    "user": "0x0c6367b4e0022ca702ad6f33cd2cf504b2cc3cbb",
    "taker": "0x4bfb41d5b3570defd03c39a9a4d8de6bd8b8982e",
    "tx_hash": "0xf7d09a5f24609e82...",
    "side": "BUY",
    "price": 0.59,
    "shares": 33898304,
    "shares_normalized": 33.898304,
    "token_id": "111868385514416639...",
    "token_label": "Astralis",
    "condition_id": "0xd546a1f7ff24a008...",
    "market_slug": "cs2-ast10-eye-2026-04-09-game1",
    "title": "Counter-Strike: Astralis vs EYEBALLERS - Map 1 Winner",
    "timestamp": 1775731431,
    "block_number": null,
    "log_index": null
  }
}
block_number: null means pre-confirmation (detected before the block). Once confirmed, a status_update fires on the settlements subscription if you have one active. If you only need trades and don’t care about the confirmation lifecycle, fills is all you need.
settlements
default
Events: settlement, status_updatePending and confirmed Polymarket settlements. The default subscription type. Each event contains a trades[] array with all fills in the transaction. Use this when you need the full settlement lifecycle (pending detection, block confirmation via status_update, and all fills grouped by transaction).If you just want individual trades in a flat format, use fills instead.
trades
string
Events: settlement, trade, status_updateAll trade activity including confirmed on-chain trades.
prices
string
Events: settlement, tradePrice-moving events only. Useful for building price feeds.
dome
string
Events: settlement (reformatted as per-fill flat events)Dome API-compatible feed. Each settlement is exploded into individual flat events — one per order fill — matching the exact field names and structure of Dome’s WebSocket API. Designed as a drop-in replacement for Dome with 3-5 second faster delivery. See Dome Migration for full field reference and copy trading examples.This is the simplest subscription type for per-wallet trade tracking. Each fill arrives as its own flat event with a user field. Filter incoming events by event.data.user === your_wallet to get the wallet’s actual trades — no array iteration, no maker/taker confusion.
import WebSocket from "ws";

const TRACKED_WALLET = "0x...";
const ws = new WebSocket("wss://ws.polynode.dev/ws?key=YOUR_KEY");

ws.on("open", () => {
  ws.send(JSON.stringify({
    action: "subscribe",
    type: "dome"
  }));
});

ws.on("message", (raw) => {
  const msg = JSON.parse(raw);
  if (msg.type !== "event") return;

  const fill = msg.data;
  if (fill.user.toLowerCase() !== TRACKED_WALLET.toLowerCase()) return;

  console.log(
    fill.side, fill.shares_normalized, fill.token_label,
    "@", fill.price, "in", fill.title
  );
});
Real captured event (live data from April 9, 2026):
{
  "type": "event",
  "data": {
    "order_hash": "0x7b281ecba532e47147e9919e073635b44ce0361527f46ee1067f2ca152aea765",
    "user": "0x0c6367b4e0022ca702ad6f33cd2cf504b2cc3cbb",
    "taker": "0x4bfb41d5b3570defd03c39a9a4d8de6bd8b8982e",
    "tx_hash": "0xf7d09a5f24609e8209298d7be35fa33ba8a3749ebb51f8a13d10d547467d104d",
    "side": "BUY",
    "price": 0.59,
    "shares": 33898304,
    "shares_normalized": 33.898304,
    "token_id": "111868385514416639450414573730782830447093166389406898626712932606174471659926",
    "token_label": "Astralis",
    "condition_id": "0xd546a1f7ff24a008a90bf80a06a7f7aa034abb33311d6727d325f9b848e93940",
    "market_slug": "cs2-ast10-eye-2026-04-09-game1",
    "title": "Counter-Strike: Astralis vs EYEBALLERS - Map 1 Winner",
    "timestamp": 1775731431,
    "block_number": null,
    "log_index": null
  }
}
In this event, user is the wallet whose trade this is (0x0c6367b4...), and taker is the CTF Exchange contract (0x4bfb41d5...) — that pattern means this is the user’s own fill, not a counterparty fill. The user bought Astralis at 0.59 for 33.9 shares.The same transaction also produces a separate event for the counterparty (with user = counterparty_wallet, taker = real_taker_wallet). To track only the wallet you care about, filter by event.data.user === your_wallet and ignore everything else.
blocks
string
Events: blockNew Polygon block notifications with Polymarket-specific stats (settlement count, trade volume).
wallets
string
Events: settlement, trade, position_change, deposit, status_update, position_split, position_merge, positions_converted, redemptionAll activity for specific wallets. Best used with the wallets filter.
markets
string
Events: settlement, trade, position_change, status_update, position_split, position_merge, positions_converted, redemptionAll activity for specific markets. Best used with tokens, slugs, or condition_ids filters.
large_trades
string
Events: settlement, tradeWhale alerts. Defaults to min_size: 1000 ($1K+) unless you set your own.
global
string
Events: all types including redemption, except position_split, position_merge, and positions_convertedUnfiltered stream of every event (firehose, full data stream), including oracle and redemption events. High throughput — use with caution. This counts toward your plan’s firehose connection limit. To include position_split/position_merge/positions_converted, add them explicitly via the event_types filter override.
Firehose refers to any WebSocket subscription with no filters applied — receiving every event at full throughput. Filtered subscriptions (specifying wallets, tokens, slugs, or size thresholds) don’t count toward your firehose limit and use far less bandwidth.
oracle
string
Events: oracleUMA Optimistic Oracle events: market resolutions, proposals, disputes, flags, and admin actions. See Oracle Event.
Events: price_feedReal-time crypto prices (~1 update/second per feed). 7 feeds available: BTC, ETH, SOL, BNB, XRP, DOGE, HYPE. Use the feeds filter to select specific feeds (e.g. ["BTC/USD", "ETH/USD"]). See Crypto Prices.

Filters

All filters are optional. Omit the filters object entirely to receive all events matching the subscription type.

Market identification

tokens
string[]
Filter by Polymarket conditional token IDs. Match if any token in the list appears in the event.
"tokens": ["21742633143463906290569404...", "98765432..."]
slugs
string[]
Filter by market URL slugs. Resolved to token IDs at subscribe time — zero performance cost after that.
"slugs": ["bitcoin-100k-2026", "trump-2024"]
If a slug isn’t found in metadata, you’ll get a warning in the subscribed response. The subscription still activates for any resolved slugs.
condition_ids
string[]
Filter by Polymarket condition IDs. Resolved to token IDs at subscribe time.
"condition_ids": ["0x123abc..."]

Wallet filtering

wallets
string[]
Filter by wallet addresses (case-insensitive). Matches if the wallet is involved as maker or taker.
"wallets": ["0xabcdef1234567890..."]
Tracking a specific wallet’s trades? Always match by maker, never by taker.For settlement events: iterate data.trades[] and find entries where fill.maker === your_wallet.For trade events: filter incoming events by data.maker === your_wallet.The maker field on each fill is the wallet that placed the order. The taker field is the counterparty — matching against it returns the wrong wallet’s perspective with the opposite token and the complement price (e.g. shows BUY Down 0.20 when the wallet actually bought Up at 0.80). This is how on-chain OrderFilled events are structured. See the Settlement Event or Trade Event reference for full code examples.

Trade filtering

side
string
Filter by trade side. Case-insensitive.Values: "BUY" or "SELL"
min_size
number
Minimum trade size in USD. Events below this size are dropped.
"min_size": 1000
max_size
number
Maximum trade size in USD. Events above this size are dropped.
status
string
default:"all"
Filter by settlement status.
ValueDescription
"pending"Only pre-chain detections
"confirmed"Only confirmed in a block
"all"Both pending and confirmed (default)

Event control

event_types
string[]
Override the subscription type’s default event list. Valid values: "settlement", "trade", "status_update", "block", "position_change", "deposit", "position_split", "position_merge", "positions_converted", "redemption"
snapshot_count
number
default:"20"
Number of recent matching events to receive immediately after subscribing. Max varies by tier (free: 20, starter: 100, growth: 200, enterprise: 500).
since
number
UNIX timestamp in milliseconds. When set, the initial snapshot returns all events after this timestamp instead of just the most recent N events. Useful for gap-filling after a reconnect or cold start.
"since": 1774412600000
The server keeps a rolling window of recent events in memory. Timestamps older than your tier’s lookback window are clamped to the window edge.
TierMax lookback
Free30 seconds
Starter2 minutes
Growth5 minutes
Enterprise5 minutes
since vs snapshot_count — these are two separate snapshot modes. Use snapshot_count when you just want the last N events (capped by tier). Use since when you need every event after a specific timestamp (e.g. reconnecting after a drop). If you pass both, since takes priority and snapshot_count is ignored. See tier limits for the full breakdown.

Price feed filtering

feeds
string[]
Filter by price feed names. Only applies to chainlink subscriptions. Available feeds: BTC/USD, ETH/USD, SOL/USD, BNB/USD, XRP/USD, DOGE/USD, HYPE/USD.
"feeds": ["BTC/USD", "ETH/USD", "SOL/USD"]
Omit to receive all 7 feeds. See Crypto Prices for details.

Matching logic

Filters use AND logic between different filter types and OR logic within each filter:
  • An event must match all active filter categories (wallets AND tokens AND side AND size range)
  • Within a category, matching any value is sufficient (wallet A OR wallet B)
  • Empty/omitted filters match everything in that category

Multiple subscriptions

You can send multiple subscribe messages on the same connection — they stack. Each subscribe creates an independent subscription with its own filters. Events matching any of your active subscriptions are delivered, deduplicated so you never receive the same event twice.
// Subscribe to two different wallet groups independently
ws.send(JSON.stringify({
  action: "subscribe",
  type: "wallets",
  filters: { wallets: ["0xaaa..."] }
}));

ws.send(JSON.stringify({
  action: "subscribe",
  type: "wallets",
  filters: { wallets: ["0xbbb..."] }
}));
// Both subscriptions are active — events for either wallet are delivered

Subscribe response

After subscribing, you receive two messages: 1. Snapshot — recent events matching your filters:
{
  "type": "snapshot",
  "count": 20,
  "events": [...]
}
2. Confirmation — your subscription ID and any warnings:
{
  "type": "subscribed",
  "subscriber_id": "550e8400-e29b-41d4-a716-446655440000",
  "subscription_id": "550e8400-e29b-41d4-a716-446655440000:1",
  "subscription_type": "settlements",
  "warnings": []
}
Save the subscription_id if you need to remove a specific subscription later.

Unsubscribe

Remove a specific subscription

{"action": "unsubscribe", "subscription_id": "550e8400-...:1"}
Response:
{
  "type": "unsubscribed",
  "subscriber_id": "550e8400-...",
  "subscription_id": "550e8400-...:1"
}

Remove all subscriptions

{"action": "unsubscribe"}
Response:
{"type": "unsubscribed", "subscriber_id": "550e8400-..."}
To change filters on an existing subscription, unsubscribe by subscription_id and send a new subscribe with the updated filters.