/ws/live
Live game state only. Scores, clock, period, status changes. Quiet by design — only emits when something actually happens. Low bandwidth.
/ws/odds
Every
price_change event from every book, plus the full game-state stream. High volume — 100 to 500 events per second during peak.Endpoints
Authorization: Bearer pn_live_YOUR_KEY header.
Which channel do I use?
| If you want to… | Use |
|---|---|
| Build a live scoreboard UI | /ws/live |
| Send push notifications on score changes | /ws/live |
| Track real-time odds movements for arbitrage / alerts | /ws/odds |
| Monitor a specific book’s price action | /ws/odds |
| Both scoreboard + odds | /ws/odds (it includes everything /ws/live has) |
/ws/live is the correct default for 90% of consumers. Subscribe to /ws/odds only if you actually need the raw price firehose.
Connection lifecycle
- Open connection with your API key. Bad/missing key → HTTP 401 before the upgrade.
- Receive welcome frame (JSON). Contains your
conn_idand the channel name. - Receive snapshot frame (JSON). Contains every currently-live game and their full state. Initialize your in-memory view from this, then apply subsequent deltas. See snapshot event.
- Receive delta events (JSON) as they happen. Apply each event on top of the snapshot baseline.
- Server sends
Pingevery 30 seconds to keep the TCP connection alive through NATs and middleboxes. Your client library auto-responds withPong. - Close the socket cleanly when done. On reconnect, discard your state and wait for the next snapshot — do NOT try to resume.
Welcome frame
First message received after a successful connection:Snapshot frame
Second message, immediately after welcome. Contains every currently-live game. Use this as your baseline before applying any subsequent delta events.Keepalive & client-side pings
The server sends protocol-levelPing frames every 30 seconds. Your WebSocket library should auto-respond with Pong — every mainstream client (websockets in Python, ws in Node, tokio-tungstenite in Rust, browser WebSocket) does this by default.
Some proxies strip WebSocket control frames. If you are behind one, send an application-level JSON ping periodically:
Scale and limits
- Hard cap: 20,000 total concurrent subscribers across both channels. New connections past the cap get
HTTP 503. - Per-subscriber bounded channel: 256 events. If your consumer stalls, events are dropped on the server (not buffered indefinitely).
- Server-side fan-out is serialize-once, refcount-cloned. Each event is encoded to JSON exactly once per broadcast, then distributed to all matching subscribers via
Arc<String>— so scaling to thousands of subscribers is cheap on CPU.
See also
- Live Channel — event set for
/ws/live - Odds Channel — event set for
/ws/odds - Event Reference — schema for every event type

