Historical Odds Data API
Recorded price changes, opening and closing prices and graded results, in the same shape as live odds.
Historical odds answer the questions live prices cannot: where a line opened, how it moved, and where it closed before the start. SockOdds v1 records its own observations of the bookmakers it delivers and keeps every change in price or availability. History is on the Pro plan. It goes back to 22 December 2025 for the leagues listed on the history page and to 8 October 2026 for the rest, and it holds only our own recordings: a stretch we did not record is never filled in.
Why SockOdds
- Every change, not samples.
GET /odds/historyreturns one row per change for a game, withkindset toopened,changedorwithdrawn, plusdecimal_odds,lineandobserved_at. - Opening and closing in one call.
snapshots=opening,closingon a game's odds adds the first and last price recorded before the start to each quote. - Same ids as live odds. History rows use the same market and outcome ids as the odds routes and the results, so joins are exact.
- Graded results.
GET /resultssettles outcomes from official sources, so every recorded price can be labelledwon,lost,void,dead_heat,half_wonorhalf_lost. - Honest limits. A game, market or bookmaker with no history rows means nothing was recorded, not that the price never moved.
What you can build
Line movement charts
Request one game over a window of up to 24 hours and plot decimal_odds against observed_at, one line per bookmaker. Step through longer periods one window at a time.
Backtests
Replay a strategy over the prices that were really on offer at each moment, then grade every pick with /results.
Closing line value
Compare the price you took with the closing snapshot for the same outcome and bookmaker. Averaged over many bets, it shows whether your timing is good.
Try it
This request asks for Sportsbet's winner prices on the Rugby League World Cup opener over an eight hour window.
curl -sS "https://api.sockodds.com/v1/odds/history?event_id=ev_000ckk0zrx33&from=2026-10-15T00:00:00Z&to=2026-10-15T08:00:00Z&markets=winner&bookmakers=sportsbet" \
-H "Authorization: Bearer $SOCKODDS_API_KEY"const response = await fetch("https://api.sockodds.com/v1/odds/history?event_id=ev_000ckk0zrx33&from=2026-10-15T00:00:00Z&to=2026-10-15T08:00:00Z&markets=winner&bookmakers=sportsbet", {
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/odds/history?event_id=ev_000ckk0zrx33&from=2026-10-15T00:00:00Z&to=2026-10-15T08:00:00Z&markets=winner&bookmakers=sportsbet",
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": [
{
"event": "ev_000ckk0zrx33",
"market": {
"id": "mk_pz0msgze2rqwwktb",
"key": "winner",
"name": "Winner",
"period": "full",
"subject": null
},
"outcome": {
"id": "oc_nncgcssmzjhyt5pe",
"name": "Australia",
"side": "home"
},
"bookmaker": "sportsbet",
"observed_at": "2026-10-15T01:58:00.000Z",
"kind": "opened",
"decimal_odds": 1.79,
"implied_probability": 0.558659,
"line": null
},
{
"event": "ev_000ckk0zrx33",
"market": {
"id": "mk_pz0msgze2rqwwktb",
"key": "winner",
"name": "Winner",
"period": "full",
"subject": null
},
"outcome": {
"id": "oc_cwsr1gda0qcgf03j",
"name": "New Zealand",
"side": "away"
},
"bookmaker": "sportsbet",
"observed_at": "2026-10-15T01:58:00.000Z",
"kind": "opened",
"decimal_odds": 2.2,
"implied_probability": 0.454545,
"line": null
},
{
"event": "ev_000ckk0zrx33",
"market": {
"id": "mk_pz0msgze2rqwwktb",
"key": "winner",
"name": "Winner",
"period": "full",
"subject": null
},
"outcome": {
"id": "oc_nncgcssmzjhyt5pe",
"name": "Australia",
"side": "home"
},
"bookmaker": "sportsbet",
"observed_at": "2026-10-15T07:58:00.000Z",
"kind": "changed",
"decimal_odds": 1.72,
"implied_probability": 0.581395,
"line": null
},
{
"event": "ev_000ckk0zrx33",
"market": {
"id": "mk_pz0msgze2rqwwktb",
"key": "winner",
"name": "Winner",
"period": "full",
"subject": null
},
"outcome": {
"id": "oc_cwsr1gda0qcgf03j",
"name": "New Zealand",
"side": "away"
},
"bookmaker": "sportsbet",
"observed_at": "2026-10-15T07:58:00.000Z",
"kind": "changed",
"decimal_odds": 2.12,
"implied_probability": 0.471698,
"line": null
}
],
"meta": {
"count": 4,
"cursor": null
},
"links": {
"next": null
}
}Each row has a kind. The first two are opened, with the price each team opened at, and the next two are changed, with the price it moved to and when. A long window can return more rows than one page holds: follow links.next unchanged until it is null. The line movement example charts the result.