GET /odds/history - Fetch Odds Movement
Get the tick-by-tick odds history of an Event
GET https://api.sockodds.com/v2/odds/history/
SockOdds extension. Every price, line and bet-limit change every bookmaker has published for one event, oldest first — the raw movement behind opening, closing and steam. Captured since 2026-08-14 and kept indefinitely; the last ~28 days are answered from the live store and everything older from the archive.
Usage notesFilter with oddID and bookmakerID — an NFL game logs ~25,000 ticks a day, and each request reads at most 50,000 ticks per tier before paging. Your plan's league scope and bookmaker cap apply exactly as on /events/. One bookmaker is one series: where a book reaches the log under two sources, the higher-ranked source is kept for the whole window. `notice` says when the archive tier did not answer, in which case the series is incomplete at its old end.
Query parameters
| Parameter | Type | Description |
|---|---|---|
eventID | string | The eventID to get odds history for (required) e.g. afl_2026-09-12_brisbane_lions_vs_adelaide_crows |
oddID | string | An oddID or comma-separated list of oddIDs to include ticks for. `oddIDs` is accepted as an alias. e.g. points-home-game-ml-home |
bookmakerID | string | A bookmakerID or comma-separated list of bookmakerIDs to include ticks for e.g. sportsbet,pinnacle |
from | date-time | Start of the window. Defaults to 21 days before the event's kickoff date. e.g. 2026-08-22T00:00:00Z |
to | date-time | End of the window (exclusive, capped at now). Defaults to 2 days after kickoff. from/to may span at most 400 days. |
limit | number | The maximum number of ticks to return (default 1000, max 5000) |
cursor | string | The cursor for the request. Used to get the next group of results. This is an opaque token — pass the nextCursor value from the prior response unchanged. |
Response
Paginated: { "success": true, "data": OddsHistoryTick[], "nextCursor": string | null }
OddsHistoryTick
One recorded change to one bookmaker's price on one market (SockOdds extension). Odds are given as American strings (bookOdds) and decimals.
| Field | Type | Description |
|---|---|---|
eventID | string | The event |
oddID | string | The market side, in the oddID format (statID-statEntityID-periodID-betTypeID-sideID) |
bookmakerID | string | The bookmaker |
changedAt | string (date-time) | When the bookmaker's quote changed |
kind | string | open = first quote seen · move = price, line or main-line status changed · limit = only the bet limit changed (Pinnacle) · close = the quote was withdrawn |
bookOdds | string | null | The new price as American odds; null on a close |
decimalOdds | number | null | The new price as decimal odds |
previousBookOdds | string | null | The price this change replaced (American); null on an open |
previousDecimalOdds | number | null | The price this change replaced (decimal) |
line | number | null | The spread or total the price applies to; null for moneylines and yes/no markets |
isMainLine | boolean | null | Whether this line was the bookmaker's headline line at the time |
layOdds | number | null | Exchange lay price, where the bookmaker is an exchange |
maxStake | number | null | The bet limit after the change, where the bookmaker publishes one |
previousMaxStake | number | null | The bet limit before the change |
Status codes
| Status | Body |
|---|---|
200 | Success |
400 | {"success":false,"error":"Invalid params"} |
401 | {"success":false,"error":"Invalid API key"} |
403 | {"success":false,"error":"Inactive API key"} |
404 | {"success":false,"error":"Not found"} |
429 | {"success":false,"error":"Rate limit exceeded"} (Retry-After header) |
500 | {"success":false,"error":"Query failed"} |
503 | |
Code samples
curl -X GET "https://api.sockodds.com/v2/odds/history/?eventID=afl_2026-09-12_brisbane_lions_vs_adelaide_crows&oddID=points-home-game-ml-home&bookmakerID=sportsbet,pinnacle" \
-H "x-api-key: YOUR_API_KEY"const r = await fetch("https://api.sockodds.com/v2/odds/history/?eventID=afl_2026-09-12_brisbane_lions_vs_adelaide_crows&oddID=points-home-game-ml-home&bookmakerID=sportsbet,pinnacle", { headers: { "x-api-key": "YOUR_API_KEY" } });
const { success, data, nextCursor, notice } = await r.json();import requests
r = requests.get("https://api.sockodds.com/v2/odds/history/", params=dict(eventID="afl_2026-09-12_brisbane_lions_vs_adelaide_crows", oddID="points-home-game-ml-home", bookmakerID="sportsbet,pinnacle"), headers={"x-api-key": "YOUR_API_KEY"})
body = r.json()req, _ := http.NewRequest("GET", "https://api.sockodds.com/v2/odds/history/?eventID=afl_2026-09-12_brisbane_lions_vs_adelaide_crows&oddID=points-home-game-ml-home&bookmakerID=sportsbet,pinnacle", nil)
req.Header.Set("x-api-key", "YOUR_API_KEY")
res, err := http.DefaultClient.Do(req)HttpRequest req = HttpRequest.newBuilder().uri(URI.create("https://api.sockodds.com/v2/odds/history/?eventID=afl_2026-09-12_brisbane_lions_vs_adelaide_crows&oddID=points-home-game-ml-home&bookmakerID=sportsbet,pinnacle"))
.header("x-api-key", "YOUR_API_KEY").GET().build();
HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://api.sockodds.com/v2/odds/history/?eventID=afl_2026-09-12_brisbane_lions_vs_adelaide_crows&oddID=points-home-game-ml-home&bookmakerID=sportsbet,pinnacle");Try it
// the response appears here