Live and In-Play Betting Odds API
Game status and the latest price each bookmaker shows, polled or streamed.
A live product needs the state of each game and the latest price each bookmaker shows. SockOdds v1 is pre-match first. It records bookmaker prices before the start, and a quote stays in current responses only while it is fresh: anything older than 10 minutes is withheld. Quotes refresh on each bookmaker's own cadence, and the WebSocket stream sends snapshots every 15 seconds on Pro.
Not a trading feed. v1 is not a low-latency in-play feed. Do not build anything on it that depends on reacting to a price within seconds of a bookmaker changing it.
Why SockOdds
- Status on every game. Each event has a
status:scheduled,live,final,postponedorcancelled. - A time on every price. Every quote carries
observed_at, so your screen can say how recent each number is. - Old prices withheld. A quote that stops updating drops out after 10 minutes rather than lingering as a stale number. A missing price means no fresh quote, never a price of zero.
- A WebSocket stream on Pro.
/stream/oddssends a snapshot of one game, or of up to 20 games in a league, every 15 seconds. When nothing has changed it sends a heartbeat instead, which does not count towards your allowance. - Polling on every plan. The same odds routes answer a poll, within your plan's per-minute limit. See limits.
What you can build
A games board
List a league's games with GET /events?league=, show each status, and fetch odds for the games about to start.
A price ticker
Open a stream for one game and redraw on each snapshot message. A stream lasts at most an hour, so reconnect when it closes.
Movement alerts
Compare each snapshot with the last one and flag changes in decimal_odds or line, with the observed_at time in the alert.
Try it
This request asks for TAB's winner prices on the Rugby League World Cup opener, about an hour before the start.
curl -sS "https://api.sockodds.com/v1/events/ev_000ckk0zrx33/odds?markets=winner&bookmakers=tab" \
-H "Authorization: Bearer $SOCKODDS_API_KEY"const response = await fetch("https://api.sockodds.com/v1/events/ev_000ckk0zrx33/odds?markets=winner&bookmakers=tab", {
headers: { Authorization: `Bearer ${process.env.SOCKODDS_API_KEY}` },
});
console.log(JSON.stringify(await response.json(), null, 2));import json, os, urllib.request
request = urllib.request.Request(
"https://api.sockodds.com/v1/events/ev_000ckk0zrx33/odds?markets=winner&bookmakers=tab",
headers={"Authorization": "Bearer " + os.environ["SOCKODDS_API_KEY"]},
)
with urllib.request.urlopen(request) as response:
print(json.dumps(json.load(response), indent=2))Response from a local copy of the API with invented test prices
{
"data": {
"id": "ev_000ckk0zrx33",
"name": "Australia v New Zealand",
"league": {
"key": "rlwc",
"name": "Rugby League World Cup"
},
"scheduled_start": "2026-10-15T09:05:00.000Z",
"status": "scheduled",
"participants": [
{
"role": "away",
"identity": {
"key": "new_zealand_rugby_league",
"name": "New Zealand"
}
},
{
"role": "home",
"identity": {
"key": "australia_rugby_league",
"name": "Australia"
}
}
],
"markets": [
{
"id": "mk_pz0msgze2rqwwktb",
"key": "winner",
"name": "Winner",
"period": "full",
"subject": null,
"alternate": false,
"outcomes": [
{
"id": "oc_nncgcssmzjhyt5pe",
"name": "Australia",
"side": "home",
"line": null,
"prices": [
{
"bookmaker": "tab",
"decimal_odds": 1.77,
"implied_probability": 0.564972,
"available": true,
"observed_at": "2026-10-15T07:58:00.000Z"
}
]
},
{
"id": "oc_cwsr1gda0qcgf03j",
"name": "New Zealand",
"side": "away",
"line": null,
"prices": [
{
"bookmaker": "tab",
"decimal_odds": 2.18,
"implied_probability": 0.458716,
"available": true,
"observed_at": "2026-10-15T07:58:00.000Z"
}
]
}
]
}
]
},
"meta": {
"count": 1,
"cursor": null
},
"links": {
"next": null
}
}Read status (still scheduled here) and each quote's observed_at, two minutes before the request. A stream snapshot has exactly this body, so the same code reads both. The streaming guide shows how to open the stream.