Skip to main content

Client messages

Subscribe

Subscribe to orderbook updates. You can subscribe to specific markets by slug, condition ID, or token ID, or subscribe to the full firehose with "*".
{
  "action": "subscribe",
  "markets": ["*"]
}
Subscribes to every active Polymarket market (100,000+ tokens). Live updates start flowing immediately while snapshots stream in the background.
FieldTypeDescription
actionstringMust be "subscribe"
marketsstring[]Array of market identifiers. Use ["*"] for the full firehose, or pass specific identifiers: slugs (e.g. "bitcoin-100k"), condition IDs (e.g. "0x561ff..."), or CLOB token IDs (numeric string). Slugs and condition IDs are resolved to their corresponding token IDs automatically.
How identifiers are detected:
  • "*" → firehose (all active markets)
  • Starts with 0x → condition ID
  • All digits and longer than 10 characters → CLOB token ID
  • Everything else → slug
Subscribing again replaces your current subscription. To add markets, send a new subscribe with the full list.

Unsubscribe

Remove all subscriptions on this connection.
{
  "action": "unsubscribe"
}

Ping

Client-initiated keepalive.
{
  "action": "ping"
}
Response: {"type": "pong"}

Server messages

subscribed

Acknowledgment after a successful subscribe. The response format differs slightly depending on whether you subscribed to specific markets or the firehose.
{
  "type": "subscribed",
  "firehose": true,
  "markets": 104972
}
FieldTypeDescription
firehosebooleantrue when subscribed to the full firehose
marketsnumberTotal number of active tokens you’re now receiving updates for
If you subscribe with a slug and markets comes back as 0, the slug didn’t match any known event. Use the search API to find the correct slug.

snapshot_batch

Orderbook snapshots delivered in batches after subscribing. For small subscriptions (under 100 tokens), snapshots arrive in a single batch almost instantly. For large subscriptions (firehose), snapshots are streamed in batches of 50 every 200ms to avoid flooding your connection.
{
  "type": "snapshot_batch",
  "count": 2,
  "total_sent": 2,
  "snapshots": [
    {
      "type": "book_snapshot",
      "asset_id": "114694726451307654528948558967898493662917070661203465131156925998487819889437",
      "market": "0xd1796c09d0d6f876f8580086ae9808ec991784e3a74b25a1830a25de71a78c96",
      "condition_id": "0xd1796c09d0d6f876f8580086ae9808ec991784e3a74b25a1830a25de71a78c96",
      "event_title": "Netanyahu out by...?",
      "question": "Netanyahu out by end of 2026?",
      "outcome": "Yes",
      "slug": "netanyahu-out-before-2027",
      "bids": [
        { "price": "0.01", "size": "1130070" },
        { "price": "0.02", "size": "71015.52" }
      ],
      "asks": [
        { "price": "0.99", "size": "17615.05" },
        { "price": "0.98", "size": "5000" }
      ]
    }
  ]
}
FieldTypeDescription
countnumberNumber of snapshots in this batch
total_sentnumberRunning total of snapshots sent so far
snapshotsobject[]Array of book_snapshot objects (see below)
Once all snapshots have been delivered, you’ll receive a completion marker:
{
  "type": "snapshots_done",
  "total": 12239
}
Only tokens with active orderbook data are included in snapshots. Empty books are skipped. You’ll still receive live price_change and book_update events for all subscribed tokens via batched updates.

book_snapshot

Full orderbook state for a token. Sent inside snapshot_batch messages after subscribing, and occasionally in batch updates when the upstream source sends a full refresh.
{
  "type": "book_snapshot",
  "asset_id": "73624432805780182150964443951045800666977811185963019133914618974858599458273",
  "market": "0x561ffbf7de21ef3781c441f30536b026d2b301d7a4a0145a8f526f98db049ba2",
  "condition_id": "0x561ffbf7de21ef3781c441f30536b026d2b301d7a4a0145a8f526f98db049ba2",
  "event_title": "What price will Bitcoin hit in March?",
  "question": "Will Bitcoin reach $150,000 in March?",
  "outcome": "Yes",
  "slug": "what-price-will-bitcoin-hit-in-march-2026",
  "bids": [
    { "price": "0.001", "size": "8604930.58" },
    { "price": "0.002", "size": "4851192.42" }
  ],
  "asks": [
    { "price": "0.999", "size": "6152045.08" },
    { "price": "0.998", "size": "55007.54" },
    { "price": "0.997", "size": "5000" }
  ]
}
FieldTypeDescription
asset_idstringPolymarket CLOB token ID
marketstringCondition ID (hex)
condition_idstringCondition ID (hex), same as market
event_titlestringParent event title (e.g. “What price will Bitcoin hit in March?”)
questionstringSpecific market question (e.g. “Will Bitcoin reach $150,000 in March?”)
outcomestringWhich outcome this token represents (“Yes” or “No”)
slugstringURL-friendly slug for the event page on Polymarket
bidsPriceLevel[]Buy orders, sorted by price descending
asksPriceLevel[]Sell orders, sorted by price ascending
Each PriceLevel is {"price": "0.55", "size": "1000.00"} where price is the probability (0 to 1) and size is the number of shares.
If bids and asks are both empty, the market exists but has no active orders. You’ll still receive price_change updates in batches when the price moves.

batch

Batched updates delivered every 250ms. Contains all changes for your subscribed tokens since the last batch. Multiple updates to the same price level within a batch window are coalesced into a single net change, reducing bandwidth without losing accuracy.
{
  "type": "batch",
  "ts": 1773794605604,
  "count": 4,
  "updates": [
    {
      "type": "price_change",
      "market": "0xd1796c09d0d6f876f8580086ae9808ec991784e3a74b25a1830a25de71a78c96",
      "slug": "netanyahu-out-before-2027",
      "assets": [
        {
          "asset_id": "66255671088804707681511323064315150986307471908131081808279119719218775249892",
          "outcome": "No",
          "price": "0.55"
        },
        {
          "asset_id": "114694726451307654528948558967898493662917070661203465131156925998487819889437",
          "outcome": "Yes",
          "price": "0.45"
        }
      ]
    },
    {
      "type": "book_update",
      "asset_id": "73624432805780182150964443951045800666977811185963019133914618974858599458273",
      "market": "0x561ffbf7de21ef3781c441f30536b026d2b301d7a4a0145a8f526f98db049ba2",
      "outcome": "Yes",
      "slug": "what-price-will-bitcoin-hit-in-march-2026",
      "bids": [
        { "price": "0.45", "size": "12000" }
      ],
      "asks": []
    }
  ]
}
FieldTypeDescription
tsnumberBatch timestamp (Unix milliseconds)
countnumberNumber of updates in this batch
updatesobject[]Array of update objects (see below)
Each update in the updates array is one of:

price_change

A market’s price moved due to an order placement or cancellation.
FieldTypeDescription
typestring"price_change"
marketstringCondition ID
slugstringEvent slug
assetsobject[]Array of {asset_id, outcome, price} for each side

book_update

Incremental change to the orderbook. Apply these to the last snapshot.
FieldTypeDescription
typestring"book_update"
asset_idstringToken ID
marketstringCondition ID
outcomestringOutcome label
slugstringEvent slug
bidsPriceLevel[]Changed bid levels (size "0" means remove)
asksPriceLevel[]Changed ask levels (size "0" means remove)
book_update messages are incremental deltas, not full replacements. To maintain an accurate orderbook:
  • If a level’s size is "0", remove that price level
  • Otherwise, upsert the level (add or update)

book_snapshot

Occasional full orderbook replacement (sent when the upstream source resets). Same schema as the initial book_snapshot message above.

last_trade_price

A trade executed on Polymarket. Delivered for every fill, not coalesced — each trade in a batch window is its own event.
{
  "type": "last_trade_price",
  "asset_id": "196889930626949471000189353840...",
  "market": "0x8f3a...",
  "price": "0.76",
  "size": "5",
  "side": "BUY",
  "fee_rate_bps": "0",
  "timestamp": "1773991152458",
  "outcome": "Up",
  "slug": "btc-updown-15m-1773990900"
}
FieldTypeDescription
typestring"last_trade_price"
asset_idstringToken ID that was traded
marketstringCondition ID
pricestringExecution price (0-1 probability)
sizestringNumber of shares traded
sidestring"BUY" or "SELL"
fee_rate_bpsstringFee rate in basis points
timestampstringUnix milliseconds of the trade
outcomestringOutcome label (e.g. “Yes”, “Up”)
slugstringEvent slug
Use last_trade_price events to build trade tapes, calculate VWAP, detect large fills, or trigger alerts on execution activity. Unlike price_change events which fire on order placement/cancellation, these fire only when an order is actually filled.
Need sub-millisecond granularity? Enterprise plans can be configured with a dedicated stream that delivers every individual orderbook event without batching, including per-event timestamps. Contact us if your strategy requires tick-by-tick data.

unsubscribed

Acknowledgment after unsubscribe.
{
  "type": "unsubscribed"
}

pong

Response to a client ping.
{
  "type": "pong"
}

Error messages

{
  "error": "token_limit",
  "message": "Your starter tier allows max 200 tokens. Requested 500. Upgrade at https://polynode.dev/pricing",
  "max": 200,
  "requested": 500
}
{
  "error": "session_limit",
  "message": "Free tier 1-hour daily limit reached."
}
ErrorCause
token_limitSubscription exceeds your tier’s token limit (starter/growth only)
session_limitFree tier 1-hour daily session expired (resets at midnight UTC)