All posts
API ReferenceWebSocketsPolymarket APIMigration

Polymarket Replaced RTDS: Migrating to PolyBolt

On 15 September Polymarket quietly made RTDS legacy for reference prices. If you stream spot into a bot, six things changed at once — including the price source and the symbol format — and most of them fail silently rather than loudly.

10 min read

If your bot streams spot prices to decide anything — and on crypto Up/Down markets, most do — this touches you. Six things changed at once, and the awkward part is that several of them fail quietly: you stay connected, you just stop getting the prices you think you are getting.

The six breaking changes

RTDS (legacy)PolyBolt
URLwss://ws-live-data.polymarket.comwss://ws-live-v2.polymarket.com/ws
AuthPublicCLOB API credentials required
HeartbeatClient sends PING every 5sNothing to send — server pings every 25s
Subscribe frame{action, subscriptions:[{topic,type,filters}]}{op, subscriptions:[{channel,filter}]} — filter is an object, not a string
Crypto sourceBinance / ChainlinkPyth
Symbolsbtcusdt, btc/usdbtcusd — lowercase, USD not USDT

Channel mapping

RTDS topicPolyBolt channelFilterNote
crypto_pricesprice.crypto{"symbol":"btcusd"}Source Binance → Pyth; USDT → USD
crypto_prices_chainlinkprice.crypto{"symbol":"btcusd"}Source Chainlink → Pyth
crypto_prices_twap_sixtyprice.crypto.twap{"symbol":"btcusd","window_seconds":60}60s Chainlink TWAP
crypto_prices_twap_thirtyNone—No replacement exists
equity_pricesprice.equity{"symbol":"aapl"}Same catalog, lowercase

Connecting

Authenticate on the open connection first, wait for confirmation, then subscribe. Reference-price channels reject unauthenticated subscriptions.

{
  "op": "auth",
  "rid": "a1",
  "auth": {
    "apiKey": "<api key>",
    "secret": "<api secret>",
    "passphrase": "<api passphrase>"
  }
}

Those same credentials are the ones you derive for CLOB trading — key, secret and passphrase together. If you have never created them, the endpoint guide covers the L1/L2 flow.

Three things PolyBolt gives you that RTDS did not

  • A snapshot on every subscribe. Each subscription returns the preceding two minutes of prices with snapshot: true, possibly empty. Seed local state from it, then apply live updates. Under RTDS a quiet symbol just gave you silence and you had no idea whether you were connected or simply between ticks.
  • A dense seq and a dropped counter. You can finally detect gaps. RTDS had no sequence at all, so a missed message was invisible. Track seq per channel and treat any jump as a resync trigger.
  • Typed close codes instead of raw 1006: 4001 auth, 4002 slow consumer, 4003 draining, 4008 policy. A 4002 means you are too slow to drain the socket — that is a consumer bug, not a network problem, and reconnecting will not fix it.

Connection limits

RTDS published none. PolyBolt does, and breaching any of them closes the socket with 4008:

LimitValue
Subscriptions per connection64
Subscribe frames per second20
Maximum frame size64 KB
Auth frames8

64 subscriptions is the one to plan around. If you track BTC, ETH and SOL across spot and TWAP that is six, so there is plenty of headroom for a crypto bot — but a system that fans out across the equity catalogue will hit it.

Migrating a bot, in order

  1. Derive CLOB API credentials if you do not have them. RTDS was public; PolyBolt is not. This is the step that blocks everything else.
  2. Change the URL to wss://ws-live-v2.polymarket.com/ws.
  3. Delete your client heartbeat. The 5-second PING loop is not just unnecessary, it is now noise. The server pings you every 25 seconds.
  4. Rewrite subscribe frames — action → op, topic → channel, and filter becomes a JSON object rather than a string.
  5. Fix every symbol: btcusdt and btc/usd both become btcusd. Lowercase, USD.
  6. Handle the snapshot frame so you do not treat two minutes of backfill as live ticks.
  7. Add seq gap detection and resync on a jump.
  8. Recalibrate anything tuned to Binance prices. The source is Pyth now.

What this does not change

Worth being precise, because it is easy to over-migrate. The CLOB market and user channels are untouched. wss://ws-subscriptions-clob.polymarket.com/ws/market still carries order book and price updates, still wants a client PING every 10 seconds, and still hides best_bid_ask, new_market and market_resolved behind custom_feature_enabled. Only reference prices moved. Details in the WebSocket guide.

And the deeper limitation is unchanged too: a stream gives you prices from the moment you connect. It cannot tell you what the book looked like last Tuesday. Polymarket returns 404 for a resolved market's book and keeps only about one point a minute of price history, which is why backtesting needs an archive recorded while the markets ran. See how Up/Down markets work or look up a specific market in the market lookup.

Frequently asked questions

What is PolyBolt and when did it replace RTDS?
PolyBolt is Polymarket's WebSocket for crypto, equity and TWAP reference prices, launched 15 September 2026 at wss://ws-live-v2.polymarket.com/ws. It makes RTDS legacy for reference prices: crypto_prices, crypto_prices_chainlink and equity_prices all map to new PolyBolt channels. The comments topic remains on RTDS for now.
Do I need authentication for PolyBolt?
Yes. Reference-price channels require CLOB API credentials — key, secret and passphrase — sent as an auth frame on the open connection before subscribing. This is the main operational difference from RTDS, which was public. Wait for the server to confirm authentication before sending subscribe frames.
What replaced crypto_prices_chainlink?
The price.crypto channel with filter {"symbol":"btcusd"}. Two things change beyond the name: the source moves from Chainlink to Pyth, and the symbol format changes from btc/usd to lowercase btcusd. For the 60-second Chainlink TWAP, use price.crypto.twap with window_seconds set to 60. The 30-second TWAP topic has no PolyBolt replacement.
Does PolyBolt still need a client PING?
No. Under RTDS the client sent a text PING every 5 seconds. On PolyBolt the server pings every 25 seconds and the client sends nothing, though an optional {"op":"ping"} is accepted. Note this is different from the CLOB market channel, which is unchanged and still requires a client PING every 10 seconds.
Why am I connected to PolyBolt but receiving no prices?
Almost always a symbol format problem. PolyBolt uses lowercase symbols ending in usd, so btcusdt and btc/usd are both invalid — use btcusd. A bad symbol does not raise an error; the subscription simply never delivers. Check also that authentication was confirmed before you sent the subscribe frame, and that you are not treating the initial snapshot frame as the only data.
What do the PolyBolt close codes mean?
4001 is an authentication failure, 4002 means you are a slow consumer and not draining the socket fast enough, 4003 means the server is draining, and 4008 is a policy breach such as exceeding 64 subscriptions, 20 subscribe frames per second, a 64 KB frame or 8 auth frames. A 4002 is a bug in your consumer rather than a network fault, so reconnecting without fixing throughput will just repeat it.

Get the historical data Polymarket does not keep

PolyTest records Polymarket crypto Up/Down markets as they run — 240M+ snapshots with 8 levels of order book depth, sub-second timestamps, and resolved markets preserved. Start with a 3-day free trial.

Keep reading