pnclFEED Free key

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

response, trimmedillustrative
{
  "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.

next responseexample delta
{
  "sport_name": "Tennis",
  "last": 157,
  "events": [{
    "event_id": 1628594960,
    "periods": { "num_0": {
      "money_line": {
        "home": 1.87,
        "away": 1.99 }
    } }
  }]
}
[else: over the limit]

Retry-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.

429 bodydocs example
{
  "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.

one alertdocs example
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.

subscribedocs example
{
  "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 since writing 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

    poll
    drops

    $0100 a day

  • pushdrops, light polling

    poll
    drops

    $99a month

  • pollREST at speed

    poll
    drops

    $99a month

  • poll + pushspeed and drops

    poll
    drops

    $149a month

  • bulk30 a second

    poll
    drops

    $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.