pinnacle odds api / rest / sse / websocket
Pinnacle odds API: live and prematch odds as JSON
GET/kit/v1/markets?sport_id=2
header x-portal-apikey: <your key>
application/json200 OK
Live and prematch Pinnacle odds from the book sharp bettors treat as the reference line, served as JSON by the Pinnacle odds API. Poll a snapshot, have the drops pushed to you, or take every raw frame.
Create a free key$0 · 100 requests a day · 20 a minute · no card
Paid plans start at $99 a month. Compare plans
{
"sport_name": "Tennis",
"last": 141,
"events": [{
"event_id": 1628594960,
"league_name": "ATP Tour",
"home": "Novak Djokovic",
"away": "Carlos Alcaraz",
"starts": "2026-04-17T12:00:00Z",
"periods": { "num_0": {
"money_line": {
"home": 1.95,
"away": 1.90 },
"spreads": { "-0.5": {
"hdp": -0.5, "home": 2.06,
"away": 1.82, "max": 500 } }
} }
}]
}
loop[3 s on the free key, 0.1 s on poll]
GET/kit/v1/markets?sport_id=2&since=141
only what changed200 OK
Send back last as since and only the moves come back
Every response carries a last cursor. Pass it as since on the next call and the feed answers with just the events that changed after it. A quiet market returns a short payload; a busy one returns exactly the prices that moved.
The free key allows 20 calls a minute and 100 a day. poll allows 10 a second with no daily cap, and bulk 30.
{
"sport_name": "Tennis",
"last": 157,
"events": [{
"event_id": 1628594960,
"periods": { "num_0": {
"money_line": {
"home": 1.87,
"away": 1.99 }
} }
}]
}
Recent prematch tennis drops as the REST drops endpoint describes them, newest first, cached by this site's host. The drops stream below pushes moves like these as they happen, under its own field names.
The pushed stream comes with push, poll + push and bulk.
Get a key and read the dropsRetry-After: 41429 rate_limited
Past the limit the feed answers 429 with a Retry-After header in seconds. Sleep that long, then repeat the call with the same since. The cursor has not moved, so no change is skipped.
{
"error": "rate_limited",
"window": "minute",
"limit": 20,
"retry_after_ms": 41052
}
GET/odds-drop?min_drop=5
header Accept: text/event-stream, key as ?key= or header
stream opendata: {"type": "connected"}
a price fell 5.59%data: [ alert ]
Or keep one connection open and let the drops come to you
The drops stream pushes Pinnacle price falls as they are detected: /odds-drop for live markets, /odds-drop-prematch before the start. min_drop sets the smallest fall worth an alert: pass it explicitly, from 1% up. The documented example uses 5.
Each alert carries the price before and after the fall and nvp, the no-vig price: Pinnacle's line with its margin removed. Hold a soft book's number against it without making another request.
Included with push, poll + push and bulk.
data: [{
"id": 1629729400,
"sport": "Basketball",
"league": "Australia - NBL1 Women",
"home": "Sunshine Coast Phoenix",
"away": "Cairns Dolphins",
"sect": "Moneyline",
"outcome": "Home",
"period": 4,
"from_price": 2.86,
"to_price": 2.7,
"nvp": 3.04,
"alerted": 1777625196,
...
}]
WSS/ws/feed?key=<your key>
{"type": "subscribe", ...}within 5 s
baseline firstsnapshot
then every updatelive
{"type": "ping", "ts": 1779200030000}
{"type": "pong"}
Or take every frame
The raw WebSocket stream sends a snapshot of each stream you subscribe to, then every update after it. Subscribe within five seconds of connecting, filter by sport or by up to 200 event IDs per stream, and answer each ping with a pong.
If the socket drops, reconnect, subscribe again and rebuild from the fresh snapshot. Missed frames are not replayed.
Add-on for poll, poll + push and bulk: $99 a month.
{
"type": "subscribe",
"streams": ["live", "prematch"],
"sport_ids": [1, 2]
}
what comes down the wire
Thirteen sport IDs, every line Pinnacle prices on them
Each event arrives with its periods, and each period with the money line, the spreads and totals at every handicap Pinnacle offers, team totals and the maximum stake on each line. Specials such as player props come along when you add include_specials=1. Live and prematch are separate calls with the same shape.
- 1Soccerpinnacle 29
- 2Tennispinnacle 33
- 3Basketballpinnacle 4
- 4Hockeypinnacle 19
- 5Footballpinnacle 15
- 6Baseballpinnacle 3
- 7Rugbypinnacle 27, 26
- 8MMApinnacle 22
- 9Boxingpinnacle 6
- 10Volleyball, handballpinnacle 34, 18
- 11Esportspinnacle 12
- 12Golfpinnacle 17
- 13Cricketpinnacle 8
- no archiveThere is no historical odds store. Keep what you need: a loop on
sincewriting to your own table is the history. - read onlyIt is a data feed. Bets are placed with your bookmaker, not through it.
- one bookPinnacle's prices only. Compare them with other books in your own code.
rate limits, drawn
Pinnacle odds API pricing: you pay for how often you can ask
Each strip is ten seconds of requests at the plan's limit. On 20 a minute you can count the ticks. At 10 a second they close into a hatch, at 30 a second nearly a solid bar. Drops arrive on their own line, whenever Pinnacle moves.
-
trialREST, live and prematch
$0100 a day
-
pushdrops, light polling
$99a month
-
pollREST at speed
$99a month
-
poll + pushspeed and drops
$149a month
-
bulk30 a second
$229a month
WebSocket add-on: +$99 a month on poll, poll + push and bulk3 and 6 month terms cost less: full pricing
NEXTyour first request
Start on the free key and upgrade when the loop outgrows it
The key is issued on signup and never expires: no card, and the key is your login. It works on every endpoint above except the streams; for those, request the three-day full demo (SSE + raw WebSocket + 10 a second). The docs list the base URL and every parameter.