Each book's closing line for one fixture
const url = 'https://oddslink.app/v1/historical/sports/americanfootball_nfl/events/nfl%3Afalcons-panthers%3A2026-09-20/closing?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/closing?markets=h2h%2Cspreads%2Ctotals&bookmakers=draftkings%2Cfanduel&oddsFormat=american&dateFormat=iso' \ --header 'X-API-Key: <X-API-Key>'The last price each book showed before this fixture started, its closing line: the single most valuable row in the archive. Same shape, plan and 14-day-or-everything split as openers, including the 403 PLAN_REQUIRED for a fixture older than the plan covers.
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 ”Closing lines for this fixture.
object
A readable, constructible fixture id. Treat as opaque.
object
object
recorded or not_recorded today. More values may be added.
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
The last price recorded before kickoff
{ "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", "bookmakers": [ { "key": "draftkings", "title": "DraftKings", "markets": [ { "key": "spreads", "status": "recorded", "recorded_at": "2026-09-20T16:59:41Z", "outcomes": [ { "name": "Atlanta Falcons", "price": 100, "point": 2.5 }, { "name": "Carolina Panthers", "price": -120, "point": -2.5 } ] } ] } ], "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.