On this page
  1. Status: closed since July 2025
  2. Authentication and access rules
  3. Core concepts: sports, leagues, fixtures, odds, lines
  4. Endpoint reference (archived)
  5. Data conventions worth keeping
  6. Old endpoint to 2026 replacement
  7. Migrating existing code

This is a reference for people who wrote code against the Pinnacle API and need to understand it well enough to move it. It is not a copy of the official documentation. The primary source is still the pinnacleapi-documentation repository on GitHub, and the current documentation for the replacement we recommend lives at pinnodds.com/docs. What we add is the mapping between the two.

Status: closed since July 2025

The public Pinnacle API stopped accepting requests from ordinary accounts on 23 July 2025. Remaining access is granted case by case to selected high-value bettors, commercial partners and academic projects that write to [email protected].

Before that date the API had been stable for years. It went through a few versions, with /v2/leagues and /v2/bets replacing their v1 forms and /v3/odds arriving late in its life, but the overall model never changed. That stability is why so much code still exists that targets it, and why a mapping page is useful a year later.

If you inherited a codebase and are not sure whether it used the Pinnacle API, search for the host api.pinnacle.com, for the sister host used by ps3838, and for the path fragments in the endpoint table below. A hit on any of them means the code stopped receiving data in July 2025, even if it still runs and fails quietly. Libraries that wrapped the API, in Python, PHP, Node and Java, are affected in the same way, since they all called the same endpoints underneath.

Authentication and access rules

The old API used HTTP Basic authentication over HTTPS with the credentials of a funded Pinnacle account, returned JSON only, allowed at most two distinct IP addresses per client, and applied fair-use rate limits to the odds endpoints. Every one of those rules disappears when you move to an independent feed.

In practice the request looked like this. The sportId values were Pinnacle's own, for example 29 for soccer.

Old request · api.pinnacle.com (closed)
GET https://api.pinnacle.com/v1/fixtures?sportId=29&since=123456789
Authorization: Basic base64(username:password)
Accept: application/json

The published fair-use limits changed over time. Earlier versions of the documentation asked for snapshot requests no more than about once per minute per endpoint per sport, with delta requests using since permitted more often. The final wording tightened this to one request per two minutes, per endpoint, per sport id, for the odds endpoints. Clients that ignored the limits were throttled or blocked.

The two-IP rule was the constraint that caught cloud deployments. Each account could call from at most two distinct addresses, so anything running behind a rotating egress pool needed a fixed NAT or proxy in front of it.

For comparison, the same request against pinnodds authenticates with a single header and carries no account or IP requirement. Kit endpoints also accept the key as a key query parameter, which is convenient for quick tests.

2026 request · pinnodds.com
GET https://pinnodds.com/kit/v1/prematch/fixtures?sport_id=1&since=123456789
x-api-key: YOUR_KEY

Core concepts: sports, leagues, fixtures, odds, lines

The Pinnacle API modeled the world as sports, which contain leagues, which contain fixtures (events); each fixture carried odds organized by period and market, and a separate line endpoint returned the exact price for one selection at the moment you intended to bet.

Understanding these five nouns is most of the migration work, because the replacement feeds use the same nouns even when the field names differ.

  • Sports. A fixed list with integer ids. Pinnacle numbered soccer 29, tennis 33, basketball 4, and so on. Independent feeds use their own ids; pinnodds numbers soccer 1, tennis 2, basketball 3, hockey 4, American football 5, baseball 6, rugby 7, MMA 8, boxing 9, other 10, esports 11, golf 12 and cricket 13.
  • Leagues. Competitions within a sport, each with an id and a flag for whether it currently had offerings. Many clients cached the league list and joined it to fixtures by id.
  • Fixtures. Events with a start time, home and away participants, a live status flag and a parent id for derived events. Fixtures and odds were fetched separately and joined on event id.
  • Odds. Prices per event, grouped by period (0 for the full match, then sport-specific ids for halves, quarters, sets and so on) and by market: moneyline, spread, total, and team totals. Special markets such as player props lived on separate endpoints.
  • Line. A single-selection lookup that returned the current price, the maximum stake and a line id. It existed because the bets endpoint required a line id, and because odds snapshots could be stale by the time you acted on them.

The sixth noun, bets, has no equivalent in any data-only feed. Placing and settling wagers required a funded account by definition, and the independent services carry market data, not betting facilities.

Endpoint reference (archived)

The public API exposed roughly fourteen versioned endpoints, of which five carried almost all traffic: sports, leagues, fixtures, odds and line. The table lists each one with what it did, so you can search your codebase for the paths.

Scroll for more

Endpoints of the closed public Pinnacle API, their purpose and notes
EndpointPurposeNotes
/v1/sportsList of sports with idsStatic, cached by most clients
/v2/leaguesLeagues for a sport idReplaced v1; included "has offerings" flag
/v1/fixturesEvents for a sport, optionally by leagueSupported since delta cursor; live flag per event
/v1/oddsPrices for all events in a sportSupported since; grouped by league, event, period
/v3/oddsLater odds versionSame shape with additions; rate limits applied
/v1/linePrice and max stake for one selectionReturned a line id for betting
/v2/betsPlace and list wagersRequired funded account; no data-only equivalent
/v1/fixtures/settledSettled events and resultsUsed for grading and CLV studies
/v1/fixtures/specialSpecial (prop) fixturesSeparate namespace from main fixtures
/v1/odds/specialPrices for special fixturesPaired with fixtures/special
/v1/periodsPeriod ids and names per sportStatic lookup
/v1/inrunningIn-running state for live eventsElapsed time and state codes
/v1/currenciesCurrency list and ratesAccount-related
/v1/client/balanceAccount balanceAccount-related; no equivalent

Two endpoints deserve a note. The fixtures and odds calls both accepted a since parameter, and returned a last value in every response to feed into the next call. Using it correctly was the difference between a client that stayed within the rate limits and one that was blocked. That pattern survives in the replacement feeds, and the code below shows how little changes.

since_loop.py
# Old pattern (pseudocode) — unchanged in spirit
last = None
while True:
    resp = get("/v1/odds", sportId=29, since=last)
    last = resp["last"]
    apply(resp["leagues"])
    sleep(60)

# 2026 pattern against pinnodds
last = None
while True:
    resp = get("/kit/v1/markets", sport_id=1, event_type="prematch", since=last)
    last = resp.get("last") or last
    apply(resp["events"])
    sleep(60)

Data conventions worth keeping

Four conventions from the Pinnacle API carry straight over to the independent feeds: decimal odds, period 0 meaning the full match, handicaps expressed from the home side, and quarter lines appearing as separate rows. If your parsing code already handles these, it needs little change.

  • Decimal odds. The API supported a format parameter, but nearly all integrations used decimal. pinnodds returns decimal prices only.
  • Periods. Period 0 is always the full match or full game. Other ids are sport-specific and were listed by the periods endpoint. Keep whatever period lookup table you built.
  • Handicaps from the home side. A spread of −3 meant the home team gave three points. The away handicap is the negation. This is the convention pinnodds uses as well, so your sign handling stays valid.
  • Quarter lines. Totals such as 2.25 or 2.75 and handicaps such as −0.75 appeared as their own entries alongside the main line, each with its own price. Our guide on how to read Pinnacle lines explains what they mean and why they exist.
  • Max stake. The line endpoint returned a maximum bet for each selection, and many tools used it as a confidence signal. pinnodds exposes a limit field in its SSE drop alerts. The concept is discussed in Pinnacle max bet limit explained.

Old endpoint to 2026 replacement

Each data endpoint of the old Pinnacle API has a direct equivalent in the pinnodds REST API; the account and betting endpoints have none, because independent feeds carry data only. The table below is the shortest route through a migration.

Paths in the right-hand column are relative to https://pinnodds.com and authenticate with the x-api-key header. Parameter names are shown as they appear in the pinnodds documentation, which remains the authority if anything here falls out of date.

Scroll for more

Each closed Pinnacle API endpoint and the pinnodds endpoint that replaces it in 2026
Old Pinnacle endpointWhat replaces it in 2026Notes
/v1/sportsIds differ from Pinnacle's. Update your constants; the SDKs export a SPORTS map.
/v2/leaguesNo separate league call. Derive the league list from the events you receive.
/v1/fixturesSupports since and include_specials=1. Live events come from the markets endpoint with event_type=live.
/v1/odds, /v3/oddsFull board per sport. Supports since deltas and include_specials=1.
/v1/lineReturns the line ladder for one event and market type, rather than one selection.
Odds for one event (filtered client-side)Per-event detail was never a separate call in the old API; it is now.
/v1/fixtures/special, /v1/odds/specialSpecials are folded into the main responses instead of a separate namespace.
/v1/periodsNo lookup endpoint. Period 0 is still the full match.
/v1/inrunningLive status is a property of the event rather than a separate feed.
Polling for line moves (no old equivalent)Server-side drop detection and push transports did not exist in the old API.
/v1/fixtures/settledCheck the current pinnodds documentation; plan to keep your own results source if you grade bets.
/v2/betsIndependent feeds do not place bets.
/v1/client/balance, /v1/currenciesNot applicable without a bookmaker account.

Migrating existing code

A typical migration touches three places: the authentication layer, the base URL and path constants, and the response parser. Everything else, including your scheduling loop and your since cursor handling, usually survives intact.

The order we suggest is the following.

  1. Sign up for a key and make a single request by hand, following the get-started steps. Confirm the sport id you need and look at one real response before touching code.
  2. Replace Basic auth with the x-api-key header and remove any IP allow-list logic.
  3. Swap the endpoint paths using the mapping table, and translate sport ids.
  4. Adjust the parser to the flatter event list. Keep your period and handicap conventions.
  5. Re-check your polling interval against the plan you chose. Plans differ in rate limit, from 20 requests per minute on the trial and Stream tiers to 10 or 30 requests per second on Pro and Scale. The pricing page explains which plan fits which workload.
  6. If you were polling to catch line moves, consider replacing that loop with the drop buffer or the SSE stream. The polling versus push guide weighs the options.

Working code in Python and Node.js, including the delta loop and a drop stream, is on pinnacleapi.dev/python and pinnacleapi.dev/nodejs. The condensed version of this mapping, with a cut-over checklist, is in the free migration kit.

To try the replacement endpoints against a real key, sign up for a free pinnodds trial. No card and no Pinnacle account are required.