The full recorded price series for one fixture
const url = 'https://oddslink.app/v1/historical/sports/americanfootball_nfl/events/nfl%3Afalcons-panthers%3A2026-09-20/odds?markets=h2h%2Cspreads%2Ctotals&bookmakers=draftkings%2Cfanduel&oddsFormat=american&dateFormat=iso';const options = {method: 'GET', headers: {'X-API-Key': '<X-API-Key>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://oddslink.app/v1/historical/sports/americanfootball_nfl/events/nfl%3Afalcons-panthers%3A2026-09-20/odds?markets=h2h%2Cspreads%2Ctotals&bookmakers=draftkings%2Cfanduel&oddsFormat=american&dateFormat=iso' \ --header 'X-API-Key: <X-API-Key>'Every recorded price for one fixture between its opening line and its closing line: the full line movement. Requires the Scale plan or above. Scale covers fixtures that started in the last 14 days and fixtures that have not started yet; Business covers everything recorded. On Scale, a fixture that started more than 14 days ago is refused with 403 PLAN_REQUIRED naming business as required_plan, never answered with a partial or empty series. The archive begins in September 2026, so a fixture from before that has nothing recorded, and this endpoint says so explicitly with movement: not_recorded rather than an empty array. A market recorded once and never repriced is distinguished from one that moved: movement is no_movement or recorded.
Authorizations
Section titled “Authorizations”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters”A sport key, for example americanfootball_nfl or soccer_epl.
Example
americanfootball_nflA fixture id, as returned by GET /v1/sports/{sport}/events. Treat as opaque.
Example
nfl:falcons-panthers:2026-09-20Query Parameters
Section titled “Query Parameters”Comma-separated market keys, period suffix included (spreads_h1, totals_f5). Defaults to the main full-game markets (h2h,spreads,totals) when omitted.
Example
h2h,spreads,totalsComma-separated book keys. Defaults to every book when omitted.
Example
draftkings,fanduelOne number per price.
How commence_time, every last_update and recorded_at, and archive_from are written: ISO-8601 UTC strings (iso) or integer unix seconds (unix).
Responses
Section titled “ Responses ”The recorded series for this fixture.
object
A readable, constructible fixture id. Treat as opaque.
object
object
recorded: more than one price seen. no_movement: exactly one price ever recorded, meaning it opened and closed at the same number. not_recorded: nothing in the archive for this market on this fixture, either from before the archive began or never captured. More values may be added.
Empty when movement is not_recorded.
object
object
The team, player or side this price is for. Never home/away.
Present where name alone does not say what the price is for. On team_totals (and its period variants) name is Over or Under and description is the team the total belongs to.
The line/spread/total this price is for, always written as a decimal number (2.5, -3.0). Absent (not present) on h2h.
object
posted_limit: one number that applies to both legs, a sportsbook’s maximum bet. resting_depth: a separate number per leg, an exchange’s live order book. contracts: a contract count, as an exchange like Kalshi reports it. More kinds may be added.
Examples
A spread that moved twice, a total recorded once
{ "id": "nfl:falcons-panthers:2026-09-20", "sport_key": "americanfootball_nfl", "sport_title": "NFL", "commence_time": "2026-09-20T17:00:00Z", "home_team": "Atlanta Falcons", "away_team": "Carolina Panthers", "archive_from": "2026-09-01T00:00:00Z", "bookmakers": [ { "key": "draftkings", "title": "DraftKings", "markets": [ { "key": "spreads", "movement": "recorded", "points": [ { "recorded_at": "2026-09-15T14:00:03Z", "outcomes": [ { "name": "Atlanta Falcons", "price": -110, "point": 3 }, { "name": "Carolina Panthers", "price": -110, "point": -3 } ] }, { "recorded_at": "2026-09-18T18:08:20Z", "outcomes": [ { "name": "Atlanta Falcons", "price": 100, "point": 2.5 }, { "name": "Carolina Panthers", "price": -120, "point": -2.5 } ] } ] }, { "key": "totals", "movement": "no_movement", "points": [ { "recorded_at": "2026-09-15T14:00:03Z", "outcomes": [ { "name": "Over", "price": -108, "point": 43.5 }, { "name": "Under", "price": -112, "point": 43.5 } ] } ] }, { "key": "h2h_h1", "movement": "not_recorded", "points": [] } ] } ], "unmatched_bookmakers": []}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.
A parameter was malformed.
object
object
403 only: the plan on the presented key.
403 only: the lowest plan that includes this request. For history, that depends on how long ago the fixture started as well as on the endpoint.
Example
{ "error": { "code": "BAD_REQUEST", "message": "commenceTimeFrom is not a valid ISO-8601 timestamp.", "docs_url": "https://oddslink.app/docs/errors/#bad-request", "request_id": "req_01hz8k3z9e2v6w1x" }}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.
The API key (or session) is missing or invalid.
object
object
403 only: the plan on the presented key.
403 only: the lowest plan that includes this request. For history, that depends on how long ago the fixture started as well as on the endpoint.
Examples
No X-API-Key header sent
{ "error": { "code": "MISSING_KEY", "message": "X-API-Key header is missing.", "docs_url": "https://oddslink.app/docs/errors/#missing-key", "request_id": "req_01hz8k4a1f3w7x2y" }}Key does not exist or was revoked
{ "error": { "code": "INVALID_KEY", "message": "API key is not valid.", "docs_url": "https://oddslink.app/docs/errors/#invalid-key", "request_id": "req_01hz8k4b2g4x8y3z" }}No Authorization: Bearer header sent (account endpoints only)
{ "error": { "code": "MISSING_SESSION", "message": "Sign in and try again.", "docs_url": "https://oddslink.app/docs/errors/#missing-session", "request_id": "req_01hz8k4b9h5y0z1a" }}Session is expired or invalid (account endpoints only)
{ "error": { "code": "INVALID_SESSION", "message": "Your session has expired. Sign in again.", "docs_url": "https://oddslink.app/docs/errors/#invalid-session", "request_id": "req_01hz8k4c0j6z1a2b" }}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.
The key’s plan does not include history (Scale plan and up), or does not reach back to this fixture: Scale covers fixtures that started in the last 14 days, Business covers everything recorded.
object
object
403 only: the plan on the presented key.
403 only: the lowest plan that includes this request. For history, that depends on how long ago the fixture started as well as on the endpoint.
Examples
History is not on this plan
{ "error": { "code": "PLAN_REQUIRED", "message": "History requires the Scale plan or above.", "docs_url": "https://oddslink.app/docs/errors/#plan-required", "request_id": "req_01hz8k4c4j6z0a5b", "current_plan": "growth", "required_plan": "scale" }}This fixture is older than the plan's 14-day window
{ "error": { "code": "PLAN_REQUIRED", "message": "The Scale plan covers fixtures from the last 14 days. This one started 2026-09-02; the Business plan covers everything recorded.", "docs_url": "https://oddslink.app/docs/errors/#plan-required", "request_id": "req_01hz8k4c5k7a1b6c", "current_plan": "scale", "required_plan": "business" }}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.
The sport key, or the fixture id within it, does not exist.
object
object
403 only: the plan on the presented key.
403 only: the lowest plan that includes this request. For history, that depends on how long ago the fixture started as well as on the endpoint.
Examples
No fixture with this id under this sport key
{ "error": { "code": "UNKNOWN_EVENT", "message": "Unknown fixture id for americanfootball_nfl: nfl:falcons-panthers:2026-09-27", "docs_url": "https://oddslink.app/docs/errors/#unknown-event", "request_id": "req_01hz8k4d6m8b2c7d" }}Sport key does not exist
{ "error": { "code": "UNKNOWN_SPORT", "message": "Unknown sport key: basketbal_nba", "docs_url": "https://oddslink.app/docs/errors/#unknown-sport", "request_id": "req_01hz8k4d7n9c3d8e" }}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.
A parameter was well-formed but not valid (an unknown market key, for example).
object
object
403 only: the plan on the presented key.
403 only: the lowest plan that includes this request. For history, that depends on how long ago the fixture started as well as on the endpoint.
Example
{ "error": { "code": "INVALID_MARKET", "message": "Invalid markets: not_a_market", "docs_url": "https://oddslink.app/docs/errors/#invalid-market", "request_id": "req_01hz8k4e5k7a1b6c" }}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.
Either the plan’s speed limit or its monthly allowance was exceeded. error.code tells you which. Only the calls that count against the allowance can answer ALLOWANCE_SPENT.
object
object
403 only: the plan on the presented key.
403 only: the lowest plan that includes this request. For history, that depends on how long ago the fixture started as well as on the endpoint.
Examples
Too many requests this second (Retry-After is set)
{ "error": { "code": "SPEED_LIMIT", "message": "Speed limit exceeded: 10 requests/second on the Growth plan.", "docs_url": "https://oddslink.app/docs/errors/#speed-limit", "request_id": "req_01hz8k4f6l8b2c7d" }}The month's allowance is used up
{ "error": { "code": "ALLOWANCE_SPENT", "message": "Monthly allowance of 100000 requests used. Resets 2026-10-01.", "docs_url": "https://oddslink.app/docs/errors/#allowance-spent", "request_id": "req_01hz8k4g7m9c3d8e" }}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.
Seconds to wait before retrying (429 SPEED_LIMIT only).
Something failed on our side.
object
object
403 only: the plan on the presented key.
403 only: the lowest plan that includes this request. For history, that depends on how long ago the fixture started as well as on the endpoint.
Example
{ "error": { "code": "INTERNAL_ERROR", "message": "Something went wrong on our side. It has been logged.", "docs_url": "https://oddslink.app/docs/errors/#internal-error", "request_id": "req_01hz8k4h8n0d4e9f" }}Headers
Section titled “Headers”Requests used this billing period.
Requests remaining this billing period.
What this one call cost against the allowance (0 for a free call).
This plan’s speed limit, in requests per second.
Requests left in the current one-second window.
Seconds until the speed-limit window resets.
This request’s id, for support and for matching against error.request_id.