/odds endpoint, but in real time. Instead of polling, you receive updates instantly whenever odds change.
We recommend all clients move to WebSocket for efficiency and lower latency. It reduces request overhead, scales better, and gives you immediate updates for live markets.
Why Use WebSocket?
Real-Time Updates
Receive odds changes instantly without polling
Lower Latency
Sub-150ms updates for live markets
Reduced Overhead
Single persistent connection vs repeated HTTP calls
Better Scaling
Perfect for bots, live dashboards, and in-play betting apps
Access & Pricing
Add-on Feature: WebSocket access is available as an add-on. Subscribe through odds-api.io to enable it for your account.
/bookmakers/selected/select endpoint or through the dashboard.
Connection Details
Endpoint:- API key passed as query parameter
- One connection per API key
- New connections automatically close older ones
- Automatic cleanup keeps your feed stable
Filter Parameters
Using
leagues or eventIds is recommended to reduce bandwidth. You cannot use both together.Channels
Subscribe to one or more streams withchannels. Omitting it keeps the default odds stream, so existing connections are unchanged. Add scores and/or status for live event state:
odds(default):created,updated,deleted,no_marketsscores:scoremessages on every score changestatus:statusmessages onpending(new match added),live,settled,cancelled(carries the current scores, so you get the final result on settle)
score/status messages also carry an optional clock snapshot (same shape as GET /events/live) so you can re-anchor a match-clock ticker on every event without polling. See the Live Events guide.
score/status are event-level (no bookie/markets), best-effort (no seq, not replayed). See the WebSocket API reference for full details.
Example Connection URLs
Welcome Message
Upon successful connection, you’ll receive a welcome message confirming your active filters:Error Responses
If your connection parameters are invalid, you’ll receive a400 Bad Request with one of these errors:
Update Types
Messages come in as JSON objects. Each has atype field:
deleted and no_markets messages carry an empty markets array and are always delivered, even when you subscribe with a markets= filter, so filtered clients still learn when a match goes off the board.
They do respect your status=, sport= and leagues= filters, and carry the event’s date, so a removal for a pre-match fixture is not delivered on a status=live connection.
no_markets means the bookmaker has no active markets for that event at all. If the bookmaker still prices the event but not in your markets= list, you receive nothing rather than a no_markets.
Message Format
Each message includes aseq field: a globally unique, monotonically increasing sequence number. Use this to detect gaps and to reconnect without missing updates (see Reconnection with Replay below).
Quick Start
JavaScript Example
Python Example
PHP Example
Handling Different Update Types
Advanced Implementation: Live Odds Tracker
React Integration
Reconnection with Replay
When your client disconnects and reconnects, you can resume from where you left off using thelastSeq parameter. The server will replay any messages you missed during the disconnection.
How It Works
- Track the
seqfield from every message you receive - When reconnecting, pass the last seq you received as a query parameter:
lastSeq=482917 - The server sends a burst of missed messages before resuming the live stream
- After the replay burst, live updates continue as normal with no gap
Connection URL with Replay
Replay Behavior
- Compacted latest-state replay: You receive the most recent state for each
eventId:bookiecombination, not every intermediate tick. If odds changed multiple times while you were disconnected, you get the final value only. This is correct for state sync; trading clients who need every tick should use/odds/movementsper event. - The replay burst is delivered as a batch of messages immediately after the welcome message
- Messages are filtered through your active filters (sport, leagues, markets, etc.), so you only receive updates relevant to your session
deletedandno_marketsupdates are replayed as latest state. If an event was deleted while you were disconnected, you will receive the deletion during replay- Replay data is retained for up to 24 hours
- Each message is delivered as its own WebSocket frame - parse every frame with
JSON.parse(event.data), exactly like live updates - and the burst is sent as fast as the connection allows
Replay Limits and Resync
If the replay cannot be served reliably, the server will not silently truncate. Instead, it sends aresync_required message. This happens when:
- Too many replay candidates (
reason: "replay_limit_exceeded"): the gap between yourlastSeqand the current seq produced more updates than the server will process - Expired replay data (
reason: "replay_window_expired"): one or more replay payloads have aged out of the retention window, which would leave gaps in the catch-up
last_seq is outside the replay window, the server first pushes the
current state of your subscription as ordinary created updates, then continues
streaming live on the same connection. No REST refetch or reconnect is needed -
your existing message handler applies them like any other update.
resync_required is only sent when complete state cannot be guaranteed: there
was nothing cached to send, or the snapshot exceeded the per-connection limit
(reason: "snapshot_truncated"). In those cases refetch from REST and discard
the last_seq you stored so the next reconnect starts fresh.
When you receive resync_required, rebuild your state from REST:
- Fetch a fresh snapshot from
/oddsor/odds/multiwithincludeSeq=true - Read the
X-OddsAPI-Seqresponse header - Reconnect to the WebSocket with
lastSeqset to that value - You are now caught up with no gap
Example: Reconnect with Replay
REST to WebSocket Handoff
You can obtain a seq cursor from REST API responses by addingincludeSeq=true to the snapshot odds endpoints (/odds, /odds/multi). The current sequence number is returned in the X-OddsAPI-Seq response header.
lastSeq when opening your WebSocket connection to ensure no updates are missed between the REST snapshot and the live stream.
Best Practices
Use Filters to Reduce Bandwidth
Use Filters to Reduce Bandwidth
Use
leagues or eventIds filters when you only need specific data. This significantly reduces bandwidth and improves performance.Implement Reconnection Logic
Implement Reconnection Logic
Use
lastSeq for gap-free reconnection. Always implement exponential backoff as a fallback. The connection is stable, but networks can drop.Handle All Message Types
Handle All Message Types
Handle
welcome, created, updated, deleted, and no_markets to keep your data in sync.Replace Markets, Never Merge Them
Replace Markets, Never Merge Them
Each
updated message contains the full current market set for that event and bookmaker, so overwrite what you have stored rather than merging into it.Merging is the most common integration mistake we see. A suspended market is dropped from the payload rather than marked, so if you merge, it stays in your data forever and you keep showing a price that is no longer available.One Connection Per API Key
One Connection Per API Key
New connections automatically close older ones. Don’t create multiple connections with the same API key.
Process Updates Asynchronously
Process Updates Asynchronously
If receiving many updates, process them asynchronously to avoid blocking your main thread.
Benefits Over REST API
Get Access
Enable WebSocket Access
Subscribe to WebSocket as an add-on through your odds-api.io account
Next Steps
Fetching Odds
Learn about REST API odds fetching
Best Practices
Optimize your implementation
Value Bets
Identify profitable opportunities
API Reference
Explore all API endpoints