/stream/prediction-markets

Description

Stream the full real-time order book for non-sport prediction markets — politics, economics, finance, crypto, tech, culture, climate, health, geopolitics, companies, and other — across Kalshi and Polymarket. This is a Server-Sent Events (SSE) connection: instead of polling for updates, the server pushes a message every time a market's order book changes.

Unlike the sports odds stream (/stream/{sport}/odds), which sends incremental deltas, every message on this stream is a complete order book snapshot for a single market — bids, asks, best bid/ask, and spread. Consumers should replace their cached copy of that market on every message rather than patch it.

Best Practice: Don't Rely on canonical_id From the Stream

The stream's canonical_id field is not populated — join to the mapping endpoints yourself, on market_id.

Each snapshot carries a canonical_id field, but it currently comes back as an empty string. The stream does not do the Kalshi↔Polymarket join for you in-line.

What to do instead

Build your canonical_market_id lookup separately from /prediction-markets/canonical-events, keyed on each platform's source_market_id. Then match it against the stream's market_id (formatted as <platform>:<source_market_id>, e.g. kalshi:AMAZONFTC-29DEC31 or polymarket:897017) to attach the canonical mapping to each incoming snapshot yourself.

Why this matters

If you wait on the stream to hand you a populated canonical_id, your pipeline will silently treat every market as unmapped. Do the join client-side using the REST mapping endpoints, and refresh that lookup periodically since /prediction-markets/canonical-events/ids can surface new events.

Specific Parameter Information

For a full list of parameters, scroll to the bottom of this page.

You must pass exactly one category. Authenticate with the X-Api-Key header.

category

(Required.) One of: politics, economics, finance, crypto, tech, culture, climate, health, geopolitics, companies, other. An invalid value returns a 4xx with the valid list.

Note: only one category is honored per connection. Passing it more than once (e.g. category=politics&category=culture) does not stream both — the last value wins and the earlier one is silently dropped. Open a separate connection per category if you need more than one.

platform

(Optional.) Filter to one platform: kalshi or polymarket. An invalid value returns a 4xx with the valid list. Omit to receive both.

Example Responses

Notes

This is a Server-Sent Events connection, so the "response" is a sequence of events rather than a single payload. You will see connected once on open, ping roughly every 5 seconds as a keepalive, and snapshot on every order book change for a market in the requested category.

Connected

event: connected
retry: 5000
data: ok go

Ping (keepalive, ~every 5s)

event: ping
retry: 5000
data: 2026-08-25T20:12:37Z

Snapshot — Kalshi

URL: https://api.opticodds.com/api/v3/stream/prediction-markets?category=politics&platform=kalshi

event: snapshot
retry: 5000
data: {
  "entry_id": "",
  "type": "snapshot",
  "data": {
    "market_id": "kalshi:AMAZONFTC-29DEC31",
    "platform": "kalshi",
    "source_market_id": "AMAZONFTC-29DEC31",
    "source_event_id": "AMAZONFTC-29DEC31",
    "outcomes": {
      "yes": {
        "token_id": "yes",
        "best_bid": 0.42,
        "best_ask": 0.45,
        "spread": 0.03,
        "last_trade_price": 0,
        "tick_size": 0,
        "bids": [
          { "price": 0.42, "size": 21.78 },
          { "price": 0.41, "size": 500 }
        ],
        "asks": [
          { "price": 0.45, "size": 50 }
        ]
      },
      "no": {
        "token_id": "no",
        "best_bid": 0.55,
        "best_ask": 0.58,
        "spread": 0.03,
        "last_trade_price": 0,
        "tick_size": 0,
        "bids": [
          { "price": 0.55, "size": 40 }
        ],
        "asks": [
          { "price": 0.58, "size": 60 }
        ]
      }
    },
    "timestamp_ns": 1787680501517000000,
    "category": "politics",
    "canonical_id": ""
  }
}

Snapshot — Polymarket

URL: https://api.opticodds.com/api/v3/stream/prediction-markets?category=politics&platform=polymarket

event: snapshot
retry: 5000
data: {
  "entry_id": "",
  "type": "snapshot",
  "data": {
    "market_id": "polymarket:897017",
    "platform": "polymarket",
    "source_market_id": "897017",
    "source_event_id": "100229",
    "outcomes": {
      "no": {
        "token_id": "no",
        "best_bid": 0.995,
        "best_ask": 0.998,
        "spread": 0.003,
        "last_trade_price": 0,
        "tick_size": 0,
        "bids": [
          { "price": 0.995, "size": 448.12 },
          { "price": 0.99, "size": 35 }
        ],
        "asks": [
          { "price": 0.998, "size": 20 }
        ]
      },
      "yes": {
        "token_id": "yes",
        "best_bid": 0.002,
        "best_ask": 0.005,
        "spread": 0.003,
        "last_trade_price": 0,
        "tick_size": 0,
        "bids": [
          { "price": 0.002, "size": 500 }
        ],
        "asks": [
          { "price": 0.005, "size": 700 }
        ]
      }
    },
    "timestamp_ns": 1787680911430000000,
    "category": "politics",
    "canonical_id": ""
  }
}
Query Params
string

The API key that you want to use. You can also use the X-Api-Key header.

string
required

The prediction-market category that you want to receive order-book updates for. Ensure that this is URL encoded.

platform
array of strings
Defaults to []

The platforms that you want to receive order-book updates for. If ommitted, you will get updates for all platforms.

platform
source_event_id
array of strings
Defaults to []

The platform-native event IDs that you want to receive order-book updates for. Ensure that these are URL encoded.

source_event_id
source_market_id
array of strings
Defaults to []

The platform-native market IDs that you want to receive order-book updates for. Ensure that these are URL encoded.

source_market_id
canonical_id
array of strings
Defaults to []

The canonical event IDs that you want to receive order-book updates for. Ensure that these are URL encoded.

canonical_id
Response

Language
Credentials
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
text/event-stream