### Install Pinnapi SDK for Python and Node.js Source: https://pinnapi.com/docs Install the official Pinnapi SDK for Python or Node.js. The Node package requires Node.js 18+ and has zero dependencies. ```bash # Python pip install pinnapi # Node.js 18+ npm install pinnapi ``` -------------------------------- ### Fetch /api/drops with Go net/http Source: https://pinnapi.com/docs Build query parameters with url.Values, create an HTTP GET request to /api/drops with the x-portal-apikey header, and decode the JSON response into a struct with Total and Drops fields. The example queries live soccer drops with a 7% minimum drop and 600-second age limit. ```go q := url.Values{} q.Set("mode", "live"); q.Set("sport_id", "1") q.Set("min_drop_pct", "7"); q.Set("max_age_sec", "600") req, _ := http.NewRequest("GET", BASE+"/api/drops?"+q.Encode(), nil) req.Header.Set("x-portal-apikey", KEY) resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() var out struct { Total int `json:"total"` Drops []struct { Home, Market string; From, To, NVP float64 } `json:"drops"` } json.NewDecoder(resp.Body).Decode(&out) ``` -------------------------------- ### GET /kit/v1/prematch/markets Source: https://pinnapi.com/docs Documentation for the GET /kit/v1/prematch/markets endpoint, which retrieves prematch markets for a specified event. For tennis matches, it returns both the match event and its associated (Games) child event by default. ```APIDOC ## GET /kit/v1/prematch/markets ### Description Fetches prematch markets for a given event. For tennis, returns both the match event and its associated (Games) child event by default. ### Method GET ### Endpoint /kit/v1/prematch/markets ### Parameters #### Query Parameters - **event_id** (integer) - Required - The ID of the event to fetch markets for. ### Response #### Success Response (200) - **events** (array) - List of event objects. Each event contains: - **event_id** (integer) - The event's unique identifier. - **parent_id** (integer or null) - For child events, the ID of the parent match event; null for the main match event. - **periods** (object) - Market data keyed by period number (e.g., `num_0`). Contains market types such as `spreads`, `totals`, `team_totals`, etc. #### Response Example { "events": [ { "event_id": 1635918998, "parent_id": null, "periods": { "num_0": { "spreads": { "1.5": {...}, "-1.5": {...} } } } }, { "event_id": 1635954125, "parent_id": 1635918998, "periods": { "num_0": { "spreads": { "4.5": {...}, "5.5": {...} } } } } ] } ``` -------------------------------- ### Prematch fixtures response structure Source: https://pinnapi.com/docs Example JSON response for the prematch fixtures endpoint. ```json { "sport_id": 1, "sport_name": "Soccer", "last": 523864, "last_call": 523864, "events": [ { "event_id": 1629513753, "sport_id": 1, "league_id": 5488, "league_name": "Italy - Serie A", "home": "Cremonese", "away": "Lazio", "starts": "2026-05-04T16:30:00Z", "start_ts": "2026-05-04T16:30:00Z", // alias of starts (back-compat) "event_type": "prematch", "is_have_odds": true, "is_have_periods": true, "periods": { "num_0": { "number": 0, "description": "Game", "money_line": { "home": 2.45, "draw": 3.30, "away": 2.90 }, "spreads": { "-0.5": { "hdp": -0.5, "home": 2.06, "away": 1.82, "max": 500 } }, "totals": { "2.5": { "points": 2.5, "over": 1.90, "under": 1.98, "max": 500 } }, "team_total": { "home": { "points": 1.5, "over": 1.86, "under": 2.00 } }, "meta": { "number": 0, "max_total": 500, "home_score": 0, "away_score": 0 } } // num_1 (1st half), num_2 (2nd half), etc. when offered }, "status": "pending" } ] } ``` -------------------------------- ### Use Pinnapi Python SDK to fetch markets, drops, and stream Source: https://pinnapi.com/docs Python SDK example: create a Client with your API key, fetch live soccer markets, query recent drops, and stream drops above a threshold. Requires the pinnapi package and a free trial key. ```python from pinnapi import Client, SPORTS api = Client("YOUR_KEY") # free trial key at pinnapi.com — no card # live soccer board (moneyline, spreads, totals — every period) events = api.markets(sport_id=SPORTS["soccer"]) # what just dropped? (queryable buffer, no open connection needed) recent = api.drops(mode="live", min_drop_pct=5) # push stream — every drop past 5%, as it happens (Drops / Edge / Scale plans) for drop in api.stream_drops(mode="live", min_drop=5): print(drop["home"], drop["away"], drop["from"], "→", drop["to"]) ``` -------------------------------- ### GET /kit/v1/markets?event_type=live Source: https://pinnapi.com/docs Documentation for the live markets endpoint, focusing on the `state` object structure and top-level clock fields. ```APIDOC ## GET /kit/v1/markets?event_type=live ### Description Retrieves live markets. Live events carry a `state` object holding in-game data, forwarded from Pinnacle exactly as it lands on their MQTT feed. The field names are sport-specific and left untouched. An event with no in-game state returns `state`: `null`. ### Method GET ### Endpoint `/kit/v1/markets?event_type=live` ### Parameters #### Query Parameters - **event_type** (string) - Required - Set to `live` to retrieve live markets. ### Response #### Success Response (200) - **state** (object|null) - In-game data. `null` if no in-game state. Contains top-level fields: `match`, `home`, `away`, `home_stats`, `away_stats`. - **state.match** (object|null) - Overall match-level state (clock / current period). Sport-dependent. `null` means "not published upstream for this match". - **state.home** (object) - Current state for the home participant. - **state.away** (object) - Current state for the away participant. - **state.home_stats** (array) - Array indexed by period, only populated when Pinnacle has published a stat value for that period. - **state.away_stats** (array) - Array indexed by period, only populated when Pinnacle has published a stat value for that period. - **quarter** (integer|null) - Top-level clock field, lifted out of match state for sports where a quarter clock is published (basketball today). `null` elsewhere. - **time_remaining_in_qtr** (string|null) - Top-level clock field, lifted out of match state for sports where a quarter clock is published (basketball today). `null` elsewhere. #### Response Example ```json { "state": { "match": { "quarter": 2, "timeRemainingInQtr": "08:32" }, "home": { "score": 45, "scoreByQuarter": [22, 23] }, "away": { "score": 40, "scoreByQuarter": [20, 20] }, "home_stats": [ { "fieldGoals": 10 } ], "away_stats": [ { "fieldGoals": 8 } ] }, "quarter": 2, "time_remaining_in_qtr": "08:32" } ``` ### Notes - The `state` object is omitted from the `/odds-drop` SSE stream, except for the top-level `quarter` and `time_remaining_in_qtr` fields which are appended to a drop payload only when non-null. - Prematch endpoints (`/kit/v1/prematch/*`) return `state`: `null` for genuine pre-game fixtures, but a match that has already kicked off can linger in the prematch store briefly and carry partial state there (participant `score`, `corners`, `yellowCards`) with `state.match` still `null`. - Field presence varies by sport and by whether Pinnacle has published a value. Assume every field is optional and code defensively. - Coverage varies by sport: tennis, basketball and hockey carry `state.match` on effectively every in-play event; soccer runs lower; esports currently carries none. - For sport-specific fields, see the table in the source documentation. ``` -------------------------------- ### GET /kit/v1/prematch/lines Source: https://pinnapi.com/docs A stripped-down view of one prematch event — just the active prices, with the period tree omitted. Much smaller than `/markets`, which makes it a good fit for tickers and quick reads. ```APIDOC ## GET /kit/v1/prematch/lines ### Description A stripped-down view of one prematch event — just the active prices, with the period tree omitted. Much smaller than `/markets`, which makes it a good fit for tickers and quick reads. ### Method GET ### Endpoint `/kit/v1/prematch/lines` ### Parameters #### Query Parameters - **event_id** (integer) - Required - Pinnacle matchup ID. ### Request Example ``` curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/prematch/lines?event_id=1629513753" ``` ``` -------------------------------- ### wscat CLI client for WebSocket feed Source: https://pinnapi.com/docs Quick CLI client for ad-hoc inspection using wscat. Install globally with npm, then connect to the WebSocket feed and paste a subscribe frame at the prompt. ```bash # npm i -g wscat — quick CLI client for ad-hoc inspection wscat -c "wss://pinnapi.com/ws/feed?key=$API_KEY" # then paste a subscribe frame at the prompt: {"type":"subscribe","streams":["live"],"sport_ids":[1,2]} ``` -------------------------------- ### Use Pinnapi Node.js SDK to fetch markets, drops, and stream Source: https://pinnapi.com/docs Node.js/TypeScript SDK example: create a Client, fetch live soccer markets, query recent drops, and stream drops above a threshold. Requires Node.js 18+ and the pinnapi package. ```javascript import { Client, SPORTS } from "pinnapi"; // or require("pinnapi") const api = new Client("YOUR_KEY"); // free trial key at pinnapi.com — no card // live soccer board (moneyline, spreads, totals — every period) const events = await api.markets({ sportId: SPORTS.soccer }); // what just dropped? (queryable buffer, no open connection needed) const recent = await api.drops({ mode: "live", minDropPct: 5 }); // push stream — every drop past 5%, as it happens (Drops / Edge / Scale plans) for await (const drop of api.streamDrops({ mode: "live", minDrop: 5 })) { console.log(drop.home, drop.away, drop.from, "→", drop.to); } ``` -------------------------------- ### GET /kit/v1/prematch/fixtures Source: https://pinnapi.com/docs Lists all pre-game fixtures for a sport with their complete markets-and-periods tree. Identical in shape to `/kit/v1/markets` — the lone difference is the `event_type` field. ```APIDOC ## GET /kit/v1/prematch/fixtures ### Description Lists all pre-game fixtures for a sport with their complete markets-and-periods tree. Identical in shape to `/kit/v1/markets` — the lone difference is the `event_type` field. ### Method GET ### Endpoint `/kit/v1/prematch/fixtures` ### Parameters #### Query Parameters - **sport_id** (integer) - Required - Dropping-odds sport id. See Sport IDs. - **since** (integer) - Optional - Return only events that changed since this `last` value (incremental polling). - **include_specials** (0 | 1) - Optional - Off by default. Pass `1` to also include special-market events (Player Props, Team Props, Exact Scores, futures) — same shape as on `/kit/v1/markets`: separate events linked by `parent_id` with prices under `special_markets`. ### Request Example ``` curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/prematch/fixtures?sport_id=1" ``` ### Response #### Success Response (200) Same envelope as `/kit/v1/markets`, only `event_type` differs. Each event includes fields such as `event_id`, `sport_id`, `league_id`, `league_name`, `home`, `away`, `starts`, `start_ts`, `event_type`, `is_have_odds`, `is_have_periods`, `periods`, and `status`. #### Response Example ``` { "sport_id": 1, "sport_name": "Soccer", "last": 523864, "last_call": 523864, "events": [ { "event_id": 1629513753, "sport_id": 1, "league_id": 5488, "league_name": "Italy - Serie A", "home": "Cremonese", "away": "Lazio", "starts": "2026-05-04T16:30:00Z", "start_ts": "2026-05-04T16:30:00Z", "event_type": "prematch", "is_have_odds": true, "is_have_periods": true, "periods": { "num_0": { "number": 0, "description": "Game", "money_line": { "home": 2.45, "draw": 3.30, "away": 2.90 }, "spreads": { "-0.5": { "hdp": -0.5, "home": 2.06, "away": 1.82, "max": 500 } }, "totals": { "2.5": { "points": 2.5, "over": 1.90, "under": 1.98, "max": 500 } }, "team_total": { "home": { "points": 1.5, "over": 1.86, "under": 2.00 } }, "meta": { "number": 0, "max_total": 500, "home_score": 0, "away_score": 0 } } }, "status": "pending" } ] } ``` ``` -------------------------------- ### Go: HTTP client for /odds-drop-prematch SSE Source: https://pinnapi.com/docs Performs a GET request to the prematch feed and scans the response body line by line, skipping non-data lines. Expects the same drop array shape as /odds-drop. ```go req, _ := http.NewRequest("GET", BASE+"/odds-drop-prematch?key="+API_KEY, nil) resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() scanner := bufio.NewScanner(resp.Body) scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024) for scanner.Scan() { line := scanner.Text() if !strings.HasPrefix(line, "data: ") { continue } // parse JSON array of drops, same shape as /odds-drop } ``` -------------------------------- ### SSE stream framing example Source: https://pinnapi.com/docs Example of the raw SSE stream framing: a connected event followed by a data line containing an array of drop objects. Shows the field names and sample values. ```text data: {"type": "connected", "id": "d648beb8-bde8-..."} data: [{"home": "Sunshine Coast Phoenix", "away": "Cairns Dolphins", "league": "Australia - NBL1 Women", "from_price": 2.86, "to_price": 2.7, "outcome": "Home", "period": 4, "sect": "Moneyline", "id": 1629729400, "sport": "Basketball", "interval": 25, "alerted": 1777625196, "sport_id": 3, "nvp": 3.04, "starts": 1777624200, ...}] ``` -------------------------------- ### Example /api/drops response Source: https://pinnapi.com/docs Example JSON response from the /api/drops endpoint. It shows a single drop object with fields such as event_id, sport_name, league, home/away teams, market, period, side, points, from/to prices, drop_pct, age_s, and is_live, plus a meta object containing mode, events_in_store, and tracked_outcomes. ```json # Response { "total": 42, "drops": [ { "event_id": 1629725918, "sport_name": "Soccer", "league": "Australia - NPL Victoria", "home": "Bentleigh Greens", "away": "St Albans Saints", "market": "spread", "period": 0, "side": "home", "points": -0.5, "from": 2.37, "to": 2.25, "drop_pct": 5.06, "age_s": 12, "is_live": false } ], "meta": { "mode": "prematch", "events_in_store": 2552, "tracked_outcomes": 122035 } } ``` -------------------------------- ### GET /kit/v1/prematch/lines Source: https://pinnapi.com/docs Retrieves prematch lines. This endpoint is part of the prematch odds section and follows the common third-party format for compatibility. ```APIDOC ## GET /kit/v1/prematch/lines ### Description Retrieves prematch lines. This endpoint is part of the prematch odds section and follows the common third-party format for compatibility. ### Method GET ### Endpoint /kit/v1/prematch/lines ### Response #### Success Response (200) - **lines** (array) - List of prematch lines. #### Response Example { "lines": [] } ``` -------------------------------- ### GET /kit/v1/details Source: https://pinnapi.com/docs Fetches a single event by its ID, returning the same event shape as the markets endpoint. ```APIDOC ## GET /kit/v1/details ### Description Pulls one event by its ID. The payload matches the per-event shape from `/kit/v1/markets` exactly. ### Method GET ### Endpoint /kit/v1/details ### Parameters #### Query Parameters - **event_id** (integer) - Required - Arcadia matchup ID from a previous `/markets` response. ### Request Example ``` curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/details?event_id=1628594960" ``` ``` -------------------------------- ### Live odds request for /kit/v1/markets Source: https://pinnapi.com/docs Retrieve live market data for sport 2 with the `x-portal-apikey` header. Use the query parameter `event_type=prematch` to get pre-game feed. The response contains events and a `last` value for incremental polling. ```bash curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/markets?sport_id=2&event_type=live" ``` ```javascript const res = await fetch( `${BASE}/kit/v1/markets?sport_id=2&event_type=live`, { headers: { "x-portal-apikey": KEY } } ); const { events, last } = await res.json(); ``` ```python import requests r = requests.get( f"{BASE}/kit/v1/markets", params={"sport_id": 2, "event_type": "live"}, headers={"x-portal-apikey": KEY}, ) data = r.json() ``` ```go package main import ( "encoding/json" "net/http" ) req, _ := http.NewRequest("GET", BASE+"/kit/v1/markets?sport_id=2&event_type=live", nil) req.Header.Set("x-portal-apikey", KEY) resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() var out struct { Events []map[string]interface{} `json:"events"`; Last int64 `json:"last"` } json.NewDecoder(resp.Body).Decode(&out) ``` ```php true, CURLOPT_HTTPHEADER => ["x-portal-apikey: $KEY"], ]); $body = curl_exec($ch); curl_close($ch); $data = json_decode($body, true); ``` -------------------------------- ### GET /kit/v1/prematch/markets Source: https://pinnapi.com/docs Retrieves prematch markets. This endpoint is part of the prematch odds section and follows the common third-party format for compatibility. ```APIDOC ## GET /kit/v1/prematch/markets ### Description Retrieves prematch markets. This endpoint is part of the prematch odds section and follows the common third-party format for compatibility. ### Method GET ### Endpoint /kit/v1/prematch/markets ### Response #### Success Response (200) - **markets** (array) - List of prematch markets. #### Response Example { "markets": [] } ``` -------------------------------- ### GET /kit/v1/prematch/fixtures Source: https://pinnapi.com/docs Retrieves prematch fixtures. This endpoint is part of the prematch odds section and follows the common third-party format for compatibility. ```APIDOC ## GET /kit/v1/prematch/fixtures ### Description Retrieves prematch fixtures. This endpoint is part of the prematch odds section and follows the common third-party format for compatibility. ### Method GET ### Endpoint /kit/v1/prematch/fixtures ### Response #### Success Response (200) - **fixtures** (array) - List of prematch fixtures. #### Response Example { "fixtures": [] } ``` -------------------------------- ### GET /kit/v1/prematch/markets Source: https://pinnapi.com/docs The complete markets payload for one prematch event — every period, plus money line, spread, total and team total. Call it after you've picked a fixture out of `/prematch/fixtures`. ```APIDOC ## GET /kit/v1/prematch/markets ### Description The complete markets payload for one prematch event — every period, plus money line, spread, total and team total. Call it after you've picked a fixture out of `/prematch/fixtures`. ### Method GET ### Endpoint `/kit/v1/prematch/markets` ### Parameters #### Query Parameters - **event_id** (integer) - Required - Pinnacle matchup ID. ### Request Example ``` curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/prematch/markets?event_id=1629513753" ``` ``` -------------------------------- ### 429 Rate Limit Response Example Source: https://pinnapi.com/docs Shows the HTTP response returned when a rate limit is exceeded, including the Retry-After header and JSON error body with window, limit, and retry_after_ms fields. ```http # 429 response when you hit a limit HTTP/1.1 429 Too Many Requests Retry-After: 41 Content-Type: application/json { "error": "rate_limited", "window": "minute", "limit": 20, "retry_after_ms": 41052 } ``` -------------------------------- ### GET /kit/v1/details Source: https://pinnapi.com/docs Retrieves details for live odds. This endpoint is part of the live odds section and follows the common third-party format for compatibility. ```APIDOC ## GET /kit/v1/details ### Description Retrieves details for live odds. This endpoint is part of the live odds section and follows the common third-party format for compatibility. ### Method GET ### Endpoint /kit/v1/details ### Response #### Success Response (200) - **details** (object) - Details of live odds. #### Response Example { "details": {} } ``` -------------------------------- ### GET /ping Public - Liveness check Source: https://pinnapi.com/docs Unauthenticated liveness check that replies 'ok' in plain text. Use for load balancers and uptime monitors that cannot attach an auth header. ```bash curl https://pinnapi.com/ping # ok ``` -------------------------------- ### GET /kit/v1/markets Source: https://pinnapi.com/docs Retrieves a complete snapshot of live or prematch events for a sport, including full market sets. Supports incremental polling and optional special markets. ```APIDOC ## GET /kit/v1/markets ### Description Returns a complete snapshot of all live events for a sport, including full market sets (moneyline, spreads, totals, team totals) across all periods. Defaults to live events; pass `event_type=prematch` to read the pre-game feed. ### Method GET ### Endpoint /kit/v1/markets ### Parameters #### Query Parameters - **sport_id** (integer) - Required - Dropping-odds sport id. See Sport IDs. - **event_type** ("live" | "prematch") - Optional - Defaults to `live`. Pass `prematch` to receive prematch fixtures with the same response envelope. - **since** (integer) - Optional - Return only events that changed since this `last` value (incremental polling). - **is_have_odds** (0 | 1) - Optional - Legacy compat — accepted and ignored. We always return events with odds. - **include_specials** (0 | 1) - Optional - Off by default. Pass `1` to also return special-market events (Player Props, Team Props, Exact Scores, futures). ### Request Example ``` curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/markets?sport_id=2&event_type=live" ``` ### Response #### Success Response (200) - **sport_id** (integer) - Sport ID. - **sport_name** (string) - Sport name. - **last** (integer) - Last update timestamp. - **last_call** (integer) - Last call timestamp. - **events** (array) - Array of event objects. #### Response Example ``` { "sport_id": 2, "sport_name": "Tennis", "last": 141, "last_call": 141, "events": [ { /* see Event object below */ } ] } ``` ``` -------------------------------- ### GET /kit/v1/markets Source: https://pinnapi.com/docs Retrieves the market board for a given sport and event type (e.g., live soccer). Returns moneyline, spreads, and totals for every period. ```APIDOC ## GET /kit/v1/markets ### Description Retrieves the market board for a given sport and event type (e.g., live soccer). Returns moneyline, spreads, and totals for every period. ### Method GET ### Endpoint https://pinnapi.com/kit/v1/markets ### Parameters #### Query Parameters - **sport_id** (integer) - Required - The sport identifier (e.g., 2 for soccer). - **event_type** (string) - Required - The event type (e.g., "live"). ### Request Example ``` curl -H "x-portal-apikey: YOUR_KEY" \ "https://pinnapi.com/kit/v1/markets?sport_id=2&event_type=live" ``` ``` -------------------------------- ### Get event details by event_id Source: https://pinnapi.com/docs Fetch a single event by its `event_id` (Arcadia matchup ID) using the API key header. The returned payload matches the per-event shape from /kit/v1/markets. ```bash curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/details?event_id=1628594960" ``` -------------------------------- ### GET /kit/v1/prematch/markets tennis event response Source: https://pinnapi.com/docs Shows the response from /kit/v1/prematch/markets for a tennis event, returning both the match (parent_id: null) with set handicap spreads and the (Games) child event (parent_id: match id) with game handicap spreads. Both rows come by default on this endpoint, /kit/v1/details, and /kit/v1/prematch/markets. ```http GET /kit/v1/prematch/markets?event_id=1635918998 { "events": [ { "event_id": 1635918998, "parent_id": null, "periods": { "num_0": { "spreads": { "1.5": {...}, "-1.5": {...} } } } // set handicap }, { "event_id": 1635954125, "parent_id": 1635918998, "periods": { "num_0": { "spreads": { "4.5": {...}, "5.5": {...} } } } // game handicap } ] } ``` -------------------------------- ### Fetch prematch fixtures with Go Source: https://pinnapi.com/docs Retrieve pre-game fixtures using the standard net/http library. ```go req, _ := http.NewRequest("GET", BASE+"/kit/v1/prematch/fixtures?sport_id=1", nil) req.Header.Set("x-portal-apikey", KEY) resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close() var out struct { Events []map[string]interface{} `json:"events"` } json.NewDecoder(resp.Body).Decode(&out) // out.Events[i] has periods, money_line, spreads, totals, team_total, etc. ``` -------------------------------- ### Fetch prematch lines for an event Source: https://pinnapi.com/docs Retrieve a stripped-down view of active prices for a specific prematch event. ```bash curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/prematch/lines?event_id=1629513753" ``` -------------------------------- ### GET /health Source: https://pinnapi.com/docs Health check endpoint. Returns the status of the API. ```APIDOC ## GET /health ### Description Health check endpoint. Returns the status of the API. ### Method GET ### Endpoint /health ### Response #### Success Response (200) - **status** (string) - The health status. #### Response Example { "status": "ok" } ``` -------------------------------- ### GET /ping Source: https://pinnapi.com/docs Ping endpoint. Returns a simple response to verify connectivity. ```APIDOC ## GET /ping ### Description Ping endpoint. Returns a simple response to verify connectivity. ### Method GET ### Endpoint /ping ### Response #### Success Response (200) - **pong** (string) - The response message. #### Response Example { "pong": "pong" } ``` -------------------------------- ### Fetch prematch fixtures with Python Source: https://pinnapi.com/docs Retrieve and filter pre-game fixtures using the requests library. ```python import requests r = requests.get( f"{BASE}/kit/v1/prematch/fixtures", params={"sport_id": 1}, headers={"x-portal-apikey": KEY}, ) events = r.json()["events"] with_odds = [e for e in events if e.get("is_have_odds") and e.get("periods", {}).get("num_0")] ``` -------------------------------- ### GET /odds-drop-prematch Source: https://pinnapi.com/docs Streams odds drops from the prematch feed only, with optional threshold and stability filters. ```APIDOC ## GET /odds-drop-prematch ### Description Streams odds drops from the prematch feed only, using the same authentication and data shape as `/odds-drop`. Useful for trading upcoming-fixture line moves without in-play chatter. ### Method GET ### Endpoint `/odds-drop-prematch` ### Parameters #### Query Parameters - **key** (string) - Required - API key or token for authentication. - **min_drop** (number) - Optional - Overrides the default 5% drop threshold. Floor is 1%. Composes with `recheck`. - **recheck** (integer) - Optional - Number of seconds to hold each drop before re-checking the current Pinnacle price. Only emits if the drop is still valid. Omit or pass `0` for instant feed. ### Request Example ``` curl -N "https://pinnapi.com/odds-drop-prematch?key=$API_KEY" ``` ### Response #### Success Response (200) - **type** (string) - Always `"error"` for trial keys, with `error` field set to `"plan_lacks_sse"`. - **data** (array) - Array of drop objects, each containing fields like `sport`, `home`, `from_price`, `to_price`, and optionally `rechecked_ms` when `recheck` is used. #### Response Example ``` {"type":"error","error":"plan_lacks_sse"} ``` ### Notes - One connection per account; live and prematch each count as one SSE slot. - Prematch lines move slowly; expect < 1 drop/sec on a typical day. - `recheck` is only available on this endpoint; it is silently ignored on `/odds-drop`. ``` -------------------------------- ### GET /health Source: https://pinnapi.com/docs Health check endpoint requiring an API key, returning live status of both feeds. ```APIDOC ## GET /health ### Description A live health read on both feeds — handy to wire into dashboards or alerting. ### Method GET ### Endpoint /health ### Authentication API key ### Response #### Success Response (200) - **status** (string) - The health status, e.g., "healthy". - **source** (string) - The active feed source: ws | rest | none. - **events_in_store** (integer) - Number of events currently in store. - **version** (integer) - Version number. - **ws_messages** (integer) - Count of WebSocket messages received. - **rest_polls** (integer) - Count of REST polls performed. - **uptime_s** (integer) - Uptime in seconds. - **prematch** (object) - Prematch feed details. - **enabled** (boolean) - Whether prematch is enabled. - **events_in_store** (integer) - Number of prematch events in store. - **rest_polls** (integer) - Count of prematch REST polls. - **source** (string) - Prematch feed source. - **drops** (string) - Drop status, e.g., "on". #### Response Example ```json { "status": "healthy", "source": "ws", "events_in_store": 1554, "version": 297592, "ws_messages": 595184, "rest_polls": 0, "uptime_s": 11938, "prematch": { "enabled": true, "events_in_store": 2552, "rest_polls": 132, "source": "rest", "drops": "on" } } ``` ``` -------------------------------- ### Fetch prematch fixtures with cURL Source: https://pinnapi.com/docs Retrieve all pre-game fixtures for a specific sport using the cURL command line tool. ```bash curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/prematch/fixtures?sport_id=1" ``` -------------------------------- ### GET /ping Source: https://pinnapi.com/docs Unauthenticated liveness check returning plain text 'ok' for load balancers and uptime monitors. ```APIDOC ## GET /ping ### Description An unauthenticated liveness check that simply replies `ok` in plain text — built for load balancers and uptime monitors that can't attach an auth header. ### Method GET ### Endpoint /ping ### Authentication Public (no authentication required) ### Response #### Success Response (200) - Plain text response: `ok` #### Response Example ``` ok ``` #### Request Example ```bash curl https://pinnapi.com/ping ``` ``` -------------------------------- ### Authenticate with x-portal-apikey header or key query parameter Source: https://pinnapi.com/docs Shows the two recommended ways to authenticate with the Pinnapi API: using the x-portal-apikey header (recommended) or the key query parameter. The header method matches legacy third-party APIs, while the query string is useful for browsers or one-offs. ```bash # Header (recommended) curl -H "x-portal-apikey: YOUR_KEY" \ "https://pinnapi.com/kit/v1/markets?sport_id=2&event_type=live" # Query string curl "https://pinnapi.com/kit/v1/markets?sport_id=2&event_type=live&key=YOUR_KEY" ``` -------------------------------- ### GET /api/drops Source: https://pinnapi.com/docs Retrieves dropping odds data. This endpoint is part of the dropping odds section and is available as a $99/mo add-on. ```APIDOC ## GET /api/drops ### Description Retrieves dropping odds data. This endpoint is part of the dropping odds section and is available as a $99/mo add-on. ### Method GET ### Endpoint /api/drops ### Response #### Success Response (200) - **drops** (array) - List of dropping odds events. #### Response Example { "drops": [] } ``` -------------------------------- ### Event object JSON example Source: https://pinnapi.com/docs Example event object returned by the Pinnacle API. The top-level `last` is a store sequence counter (not a time) and is the value to pass as `since=`; the per-event `last` is Unix seconds recorded when the response was serialised and is identical for every event in one response. `parent_id` is null for a normal match and links special-market rows (e.g. tennis `(Games)` events) back to the parent event. ```json { "event_id": 1628594960, "sport_id": 1, "league_id": 2037, "league_name": "China - Super League", "starts": "2026-04-17T12:00:00Z", "last": 1776430365, "home": "Yunnan Yukun", "away": "Tianjin Jinmen Tiger", "event_type": "live", "live_status_id": 1, "parent_id": 1628594613, "is_have_odds": true, "is_have_periods": true, "periods": { "num_0": { "number": 0, "description": "Game", "money_line": { "home": 2.450, "draw": 3.300, "away": 2.900 }, "spreads": { "-0.5": { "hdp": -0.5, "home": 2.060, "away": 1.820, "max": 500 } }, "totals": { "2.5": { "points": 2.5, "over": 1.900, "under": 1.980, "max": 500 } }, "team_total": { "home": { "points": 1.5, "over": 1.860, "under": 2.000 } }, "team_totals": { "home": { "0.5": { "points": 0.5, "over": 1.200, "under": 4.500, "max": 100 }, "1.5": { "points": 1.5, "over": 1.860, "under": 2.000, "max": 100 }, "2.5": { "points": 2.5, "over": 3.200, "under": 1.400, "max": 100 } }, "away": { /* same shape */ } }, "meta": { "number": 0, "max_total": 500, "home_score": 0, "away_score": 1 } }, "num_1": { /* first half */ } }, "state": { "match": { "state": 1, "minutes": 23 }, "home": { "score": 1, "redCards": 0, "yellowCards": 1, "corners": 3 }, "away": { "score": 0, "redCards": 0, "yellowCards": 2, "corners": 5 }, "home_stats": [{ "period": 0, "score": 1, "redCards": 0 }, { "period": 1 }], "away_stats": [{ "period": 0, "score": 0, "redCards": 0 }, { "period": 1 }] } } ``` -------------------------------- ### Fetch prematch fixtures with PHP Source: https://pinnapi.com/docs Retrieve and filter pre-game fixtures using cURL and json_decode. ```php true, CURLOPT_HTTPHEADER => ["x-portal-apikey: $KEY"], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); $with_odds = array_filter($data["events"], fn($e) => ($e["is_have_odds"] ?? false) && isset($e["periods"]["num_0"])); ``` -------------------------------- ### GET /kit/v1/markets Source: https://pinnapi.com/docs Retrieves live odds markets. This endpoint is part of the live odds section and follows the common third-party format for compatibility. ```APIDOC ## GET /kit/v1/markets ### Description Retrieves live odds markets. This endpoint is part of the live odds section and follows the common third-party format for compatibility. ### Method GET ### Endpoint /kit/v1/markets ### Response #### Success Response (200) - **markets** (array) - List of live markets. #### Response Example { "markets": [] } ``` -------------------------------- ### Fetch prematch markets for an event Source: https://pinnapi.com/docs Retrieve the complete market payload for a specific prematch event using its event_id. ```bash curl -H "x-portal-apikey: $KEY" \ "https://pinnapi.com/kit/v1/prematch/markets?event_id=1629513753" ``` -------------------------------- ### Fetch prematch fixtures with Node.js Source: https://pinnapi.com/docs Retrieve and filter pre-game fixtures that have odds available using the fetch API. ```javascript const r = await fetch( `${BASE}/kit/v1/prematch/fixtures?sport_id=1`, { headers: { "x-portal-apikey": KEY } } ); const { events } = await r.json(); const withOdds = events.filter(e => e.is_have_odds && e.periods?.num_0); ``` -------------------------------- ### PHP: cURL streaming for /odds-drop-prematch Source: https://pinnapi.com/docs Uses the same WRITEFUNCTION pattern as /odds-drop, only changing the URL. The full streaming reader is referenced from the /odds-drop PHP example. ```php