Skip to main content
Room ID: polymarket_markets_stream
Endpoint: wss://api.struct.to/ws
Rate: 0.025 credits per message
Low-latency push feed of market rows — same shape GET /polymarket/market returns, including per-outcome price with latest_block + latest_confirmed_at watermarks. The server maintains an in-memory cache of open markets only, refreshed via a slow full poll plus a fast 500ms newest-first poll, and merged live from the prediction_condition_metrics and prediction_trades Kafka streams with per-timeframe block/timestamp ordering. No initial snapshot is pushed on subscribe. Clients seed from GET /polymarket/market and then apply deltas from this stream.

Subscription model

Each client has up to 8 active slots per room (4 cadences × 2 modes). Re-subscribing to the same (interval_ms, mode) pair replaces the previous subscription. Unsubscribe one slot with action: "unsubscribe" plus interval_ms and mode, or clear everything with action: "unsubscribe_all".
  • Cadence (interval_ms): 500, 1000, 3000, or 10000.
  • Filter mode: same validation as the REST list endpoint (timeframe, search length, list caps). search is a case-insensitive substring match on title. No sort / limit — you get every matching row that changed.
  • Ids mode: any combination of condition_ids, market_slugs, and event_slugs (matches all child markets of those events). Max 500 ids total per subscription.
Updates fire only when a cache row is dirtied by (a) a fresh Kafka metric snapshot with latest_block >= cached, (b) a confirmed trade with block >= cached, (c) a slow-poll field diff, or (d) the fast newest-first poll discovering a brand-new market. Quiet markets produce zero messages. Each outcome in outcomes[] carries latest_block and latest_confirmed_at (Unix seconds) — the block/ts of the most recent price write from prediction_position_metrics. Consumers can use these to reject out-of-order price merges locally.

Subscribe

Message fields

FieldTypeRequiredDescription
action"subscribe" | "unsubscribe" | "unsubscribe_all"YesSlot lifecycle action.
interval_ms500 | 1000 | 3000 | 10000For subscribe / unsubscribeFlush cadence. Defaults to 1000 if omitted.
mode"filter" | "ids"NoSubscription mode. Defaults to filter.
filterMarketsStreamFiltermode=filter onlyFilter body; all fields optional.
condition_idsstring[]mode=ids only0x-prefixed lowercase 32-byte hex.
market_slugsstring[]mode=ids onlyMarket slug strings.
event_slugsstring[]mode=ids onlyEvent slugs — matches every child market of each event.

Filter fields (mode=filter)

Supports the same filters as the REST markets list: search, categories, exclude_categories, tags, exclude_tags, min_volume / max_volume, min_txns / max_txns, min_unique_traders / max_unique_traders, min_liquidity / max_liquidity, min_holders / max_holders, start_time / end_time, has_rewards, and timeframe (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d). status is not accepted — the cache only holds open markets.

Example — filter mode

{
  "type": "join_room",
  "payload": {
    "room_id": "polymarket_markets_stream"
  }
}
{
  "type": "room_message",
  "payload": {
    "room_id": "polymarket_markets_stream",
    "message": {
      "action": "subscribe",
      "interval_ms": 1000,
      "mode": "filter",
      "filter": {
        "search": "bitcoin",
        "categories": ["crypto"],
        "min_volume": 50000,
        "timeframe": "24h",
        "has_rewards": true
      }
    }
  }
}

Example — ids mode

{
  "type": "room_message",
  "payload": {
    "room_id": "polymarket_markets_stream",
    "message": {
      "action": "subscribe",
      "interval_ms": 500,
      "mode": "ids",
      "condition_ids": ["0xabc123..."],
      "market_slugs": ["will-bitcoin-hit-100k"],
      "event_slugs": ["bitcoin-price-markets"]
    }
  }
}

Unsubscribe one slot

{
  "type": "room_message",
  "payload": {
    "room_id": "polymarket_markets_stream",
    "message": {
      "action": "unsubscribe",
      "interval_ms": 500,
      "mode": "ids"
    }
  }
}

Response

{
  "type": "markets_stream_subscribe_response",
  "room_id": "polymarket_markets_stream",
  "data": {
    "mode": "ids",
    "interval_ms": 500,
    "condition_ids": ["0xabc123..."],
    "market_slugs": ["will-bitcoin-hit-100k"],
    "event_slugs": ["bitcoin-price-markets"],
    "rejected": [],
    "error": null
  }
}

Events

markets_stream_update

Server-pushed event fired only for rows that changed AND matched this subscription since the last flush tick. data contains full market rows — not deltas — so clients should merge by condition_id. Each outcome in data[i].outcomes carries latest_block + latest_confirmed_at price-update watermarks.

Envelope

FieldTypeDescription
type"markets_stream_update"Envelope discriminator.
room_id"polymarket_markets_stream"Room identifier.
mode"filter" | "ids"The mode this subscription was created with.
interval_ms500 | 1000 | 3000 | 10000The cadence slot this event is flushed under.
dataMarketResponse[]Full market rows, same shape as GET /polymarket/market.

MarketResponse

FieldTypeDescription
condition_idstring0x-prefixed condition ID. Required.
idstring | nullMarket ID.
market_slugstring | nullURL-safe market slug.
questionstring | nullMarket question.
titlestring | nullMarket title.
descriptionstring | nullLong description.
image_urlstring | nullCDN image URL.
oraclestring | nullOracle contract address.
statusstringMarket status. Required (cache holds only open markets).
created_timeinteger | nullUnix seconds.
start_timeinteger | nullUnix seconds.
game_start_timeinteger | nullUnix seconds (sports markets).
closed_timeinteger | nullUnix seconds.
end_timeinteger | nullUnix seconds.
accepting_ordersboolean | nullWhether CLOB is accepting new orders.
uma_resolution_statusstring | nullUMA oracle resolution status.
is_neg_riskboolean | nullWhether this market uses the neg-risk exchange.
market_maker_addressstring | nullMarket maker contract.
creatorstring | nullWallet address of creator.
categorystring | nullCategory label.
volume_usdnumber | nullLifetime USD volume.
liquidity_usdnumber | nullCurrent USD liquidity.
highest_probabilitynumber | nullHighest outcome probability (0 – 1).
total_holdersinteger | nullUnique holder count.
total_daily_ratenumber | nullCombined daily reward rate across sponsors.
winning_outcomeMarketOutcome | nullResolved winning outcome, when applicable.
outcomesMarketOutcome[]Market outcomes.
clob_rewardsClobReward[]Active reward configs.
tagsstring[]Tag labels attached to the market.
event_slugstring | nullParent event slug.
resolution_sourcestring | nullResolution source URL.
metricsRecord<Timeframe, SimpleTimeframeMetrics>Keyed by timeframe (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d).
relevance_scorenumber | nullSearch relevance score, when applicable.

MarketOutcome

FieldTypeDescription
namestringOutcome label (e.g. "Yes").
pricenumber | nullLatest price (0 – 1).
position_idstring | nullERC-1155 outcome token ID (decimal string).
outcome_indexinteger | null0-indexed outcome position.
latest_blockinteger | nullBlock of the most recent price update for this outcome.
latest_confirmed_atinteger | nullUnix seconds of the most recent price update.

SimpleTimeframeMetrics

FieldTypeDescription
volumenumberUSD volume within the window.
feesnumberUSD fees within the window.
txnsintegerTrade count within the window.
unique_tradersintegerUnique wallet count within the window.

ClobReward

FieldTypeDescription
idstringReward config ID. Required.
condition_idstringMarket condition ID. Required.
asset_addressstring | nullReward token contract.
rewards_amountnumber | nullTotal rewards remaining.
rewards_daily_ratenumber | nullRewards emitted per day.
start_datestring | nullISO date the reward starts emitting.
end_datestring | nullISO date the reward stops emitting.
rewards_max_spreadnumber | nullMax spread eligible for rewards (probability).
rewards_min_sizenumber | nullMin order size eligible for rewards (USD).
native_daily_ratenumber | nullNative (Polymarket) daily rate.
sponsored_daily_ratenumber | nullSponsored daily rate.
total_daily_ratenumber | nullCombined daily rate.
sponsors_countinteger | nullNumber of active sponsors.

Example

{
  "type": "markets_stream_update",
  "room_id": "polymarket_markets_stream",
  "mode": "ids",
  "interval_ms": 500,
  "data": [
    {
      "condition_id": "0xabc123...",
      "id": "m_1",
      "market_slug": "will-bitcoin-hit-100k",
      "question": "Will Bitcoin hit $100k by Dec 31, 2026?",
      "title": "Bitcoin $100k by EOY 2026",
      "description": "Resolves YES if BTC closes above $100,000 on any day before Dec 31, 2026.",
      "image_url": "https://cdn.struct.to/markets/btc-100k.png",
      "oracle": "0xoracle...",
      "status": "open",
      "created_time": 1743400000,
      "start_time": 1743500000,
      "game_start_time": null,
      "closed_time": null,
      "end_time": 1798761600,
      "accepting_orders": true,
      "uma_resolution_status": null,
      "is_neg_risk": false,
      "market_maker_address": "0xmm...",
      "creator": "0xcreator...",
      "category": "crypto",
      "volume_usd": 125000.5,
      "liquidity_usd": 42000.0,
      "highest_probability": 0.65,
      "total_holders": 312,
      "total_daily_rate": 150.0,
      "winning_outcome": null,
      "outcomes": [
        {
          "name": "Yes",
          "price": 0.65,
          "position_id": "12345678901234567",
          "outcome_index": 0,
          "latest_block": 65000000,
          "latest_confirmed_at": 1743500000
        },
        {
          "name": "No",
          "price": 0.35,
          "position_id": "98765432109876543",
          "outcome_index": 1,
          "latest_block": 65000000,
          "latest_confirmed_at": 1743500000
        }
      ],
      "clob_rewards": [
        {
          "id": "1",
          "condition_id": "0xabc123...",
          "asset_address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
          "rewards_amount": 18250.0,
          "rewards_daily_rate": 50.0,
          "start_date": "2026-01-01",
          "end_date": "2026-12-31",
          "rewards_max_spread": 0.04,
          "rewards_min_size": 20.0,
          "native_daily_rate": 100.0,
          "sponsored_daily_rate": 50.0,
          "total_daily_rate": 150.0,
          "sponsors_count": 1
        }
      ],
      "tags": ["crypto", "bitcoin"],
      "event_slug": "bitcoin-price-markets",
      "resolution_source": "https://example.com/btc-resolution",
      "metrics": {
        "24h": { "volume": 3200.0, "fees": 6.4, "txns": 42, "unique_traders": 18 },
        "7d": { "volume": 22000.0, "fees": 44.0, "txns": 310, "unique_traders": 121 }
      },
      "relevance_score": null
    }
  ]
}
Last modified on April 14, 2026