Home/Docs/Python

Python sports odds API guide

Last updated 2026-10-30

Use requests: send GET https://api.bettingdataapi.com/odds/ with sport_key and your key in the x-api-key header, then read data. No SDK is required. The example below runs as-is with a free key.

Install and authenticate

pip install requests pandas
export BETTING_DATA_API_KEY=YOUR_API_KEY

Fetch NBA moneylines

# pip install requests
import os
import requests

API_KEY = os.environ["BETTING_DATA_API_KEY"]   # keep keys out of source code
BASE = "https://api.bettingdataapi.com"

resp = requests.get(
    f"{BASE}/odds/",
    headers={"x-api-key": API_KEY},
    params={"sport_key": "basketball_nba", "markets": "h2h"},
    timeout=10,
)
resp.raise_for_status()
body = resp.json()

for event in body["data"]:
    print(event["home_team"], "vs", event["away_team"], event["start_time"])
    for book in event.get("books", []):
        prices = [(o["name"], o["price"]) for o in book["outcomes"]]
        print("  ", book["book"], book["market"], prices)

If the league has no upcoming games (between seasons) the data array is empty; try another sport_key from GET /sports/.

Handle quota and errors

import time
import requests

def get_json(path, api_key, params=None, attempts=3):
    """GET with handling for 429 (quota or temporary block) and network errors."""
    for attempt in range(attempts):
        try:
            r = requests.get(f"https://api.bettingdataapi.com{path}", headers={"x-api-key": api_key},
                             params=params or {}, timeout=10)
        except requests.RequestException:
            time.sleep(2 ** attempt)
            continue
        if r.status_code == 429:
            wait = int(r.headers.get("Retry-After", "60"))
            # A daily-quota 429 can mean hours until 00:00 UTC. Do not spin.
            raise RuntimeError(f"Rate limited; retry after {wait} s: {r.json().get('detail')}")
        if r.status_code >= 400:
            raise RuntimeError(f"HTTP {r.status_code}: {r.json().get('detail')}")
        print("remaining today:", r.headers.get("X-RateLimit-Remaining"))
        return r.json()
    raise RuntimeError("network error after retries")

Best price per outcome with pandas

import pandas as pd

body = get_json("/odds/", API_KEY, {"sport_key": "basketball_nba", "markets": "h2h"})
rows = [
    {
        "event_id": e["event_id"], "start_time": e["start_time"],
        "home": e["home_team"], "away": e["away_team"],
        "book": b["book"], "outcome": o["name"], "price": o["price"],
    }
    for e in body["data"] for b in e.get("books", []) for o in b["outcomes"]
]
df = pd.DataFrame(rows)
best = df.loc[df.groupby(["event_id", "outcome"])["price"].idxmax()]
print(best[["home", "away", "outcome", "book", "price"]])

Or let the API do it: GET /best-lines/?sport_key=basketball_nba.

Historical data

Business plan. Cursor pagination example: historical odds in Python.

Next

Try it with a free key

25 requests per day, NFL, NBA and MLB moneylines, no credit card.

Get a free API key