# How to pull sports betting odds from an API

> A developer's guide to TheRundown's odds API: the events-to-prices data model, first requests in curl and Python, and the free vs. paid plans.

Published 2026-10-05. Updated 2026-10-05. Canonical: https://therundown.io/blog/sports-betting-odds-api

TheRundown's odds API returns live and historical sportsbook prices as structured JSON, organized from each sports event down to the exact price each book is offering. This matters because odds live in a hierarchy — one event can carry dozens of markets, and each market has a price per sportsbook that changes throughout the day — so a useful client has to model that hierarchy, not just fetch a flat list of numbers. This guide covers the data model, authentication, a first request in curl and Python, how to pick sports, markets, and books by ID, and how plans differ on freshness and coverage.

## The data model: events, markets, participants, lines, prices

Every response follows the same nesting, from broadest to most specific:

- **Event** — a single game or match (for example, one NFL game on a given Sunday).
- **Market** — a type of bet on that event (moneyline, spread, total, or a player prop).
- **Participant** — one side of the market (a team, or a player for a prop).
- **Line** — the specific number attached to a participant (a spread of −3.5, a total of 44.5).
- **Price** — what a given sportsbook is charging for that line, keyed by sportsbook (affiliate) ID. Each price object includes `price` (American odds, such as −110 or +150) and `updated_at`, the timestamp of the last change.

Walking down that chain — event, then markets, then participants, then lines, then prices — is the core loop of almost any integration, whether you are building an odds table, a line-shopping tool, or an alert on price moves.

## Authenticating requests

The base URL is `https://therundown.io/api/v2`. Every request needs your API key in the `X-TheRundown-Key` header:

```bash
curl -s "https://therundown.io/api/v2/affiliates" \
  -H "X-TheRundown-Key: $THERUNDOWN_API_KEY"
```

Get a free key on the [odds API page](/api). Keep it in an environment variable (`THERUNDOWN_API_KEY` in the examples below) rather than committing it to source control.

## Your first request

Fetching a slate of odds is normally a two-step process: find a date that has games, then pull that date's events with the markets and books you want.

### Step 1: find dates with games

Game schedules are not evenly spaced, so start by asking which dates have games. For the NFL, pass all three season types together as `sport_ids` — regular season is `2`, preseason is `25`, and playoffs is `26`. Add `exclude_canceled=true` so a day whose only events are canceled does not count as the next game date:

```bash
curl -s "https://therundown.io/api/v2/sports/dates?sport_ids=2,25,26&format=epoch&exclude_canceled=true" \
  -H "X-TheRundown-Key: $THERUNDOWN_API_KEY"
```

### Step 2: pull the slate

Take one of the dates from that response and request the events for it, narrowed to the markets and sportsbooks you care about. This example asks for moneyline, spread, and total (`market_ids=1,2,3`) from DraftKings, BetMGM, and FanDuel (`affiliate_ids=19,22,23`), limited to the main line with `main_line=true`:

```bash
curl -s "https://therundown.io/api/v2/sports/2/events/2026-10-12?market_ids=1,2,3&affiliate_ids=19,22,23&main_line=true" \
  -H "X-TheRundown-Key: $THERUNDOWN_API_KEY"
```

Replace `2026-10-12` with a date returned by the first call.

### Doing it in Python

The same two calls with `requests`: pick the soonest upcoming date across the three NFL season types, pull that slate, and walk the nested response.

```python
import os
from datetime import datetime, timezone

import requests

api = "https://therundown.io/api/v2"
headers = {"X-TheRundown-Key": os.environ["THERUNDOWN_API_KEY"]}

# Step 1: the next NFL game date (regular season, preseason, or playoffs)
dates = requests.get(
    f"{api}/sports/dates",
    params={"sport_ids": "2,25,26", "format": "epoch", "exclude_canceled": "true"},
    headers=headers,
    timeout=30,
).json()
now = datetime.now(timezone.utc).timestamp()
upcoming = [
    (sport_id, stamp)
    for sport_id, body in dates.items()
    for stamp in body.get("dates") or []
    if stamp > now
]
sport_id, stamp = min(upcoming, key=lambda row: row[1], default=("2", now))
date = datetime.fromtimestamp(stamp, timezone.utc).date().isoformat()

# Step 2: that slate's moneyline, spread, and total from three books
slate = requests.get(
    f"{api}/sports/{sport_id}/events/{date}",
    params={"market_ids": "1,2,3", "affiliate_ids": "19,22,23", "main_line": "true"},
    headers=headers,
    timeout=30,
).json()

# Walk the data model: events, markets, participants, lines, prices
for event in slate.get("events") or []:
    for market in event["markets"]:
        for participant in market["participants"]:
            for line in participant["lines"]:
                for affiliate_id, price in line["prices"].items():
                    print(event["event_id"], market["market_id"], participant["name"],
                          affiliate_id, price["price"], price["updated_at"])
```

## Choosing sports, markets, and sportsbooks by ID

Requests filter by numeric IDs rather than names. The common ones:

**Sport IDs**

| ID  | Sport   |
| --- | ------- |
| 1   | NCAAF   |
| 2   | NFL     |
| 3   | MLB     |
| 4   | NBA     |
| 5   | NCAAB   |
| 6   | NHL     |
| 7   | UFC/MMA |
| 8   | WNBA    |
| 10  | MLS     |
| 11  | EPL     |

**Market IDs**

| ID  | Market          |
| --- | --------------- |
| 1   | Moneyline       |
| 2   | Spread          |
| 3   | Total           |
| 29  | Player points   |
| 35  | Player rebounds |
| 39  | Player assists  |
| 94  | Team totals     |

**Sportsbook (affiliate) IDs**

| ID  | Sportsbook |
| --- | ---------- |
| 3   | Pinnacle   |
| 19  | DraftKings |
| 22  | BetMGM     |
| 23  | FanDuel    |
| 25  | Kalshi     |
| 26  | Polymarket |

These six are the ones you will reach for most, but the API currently covers 25 sportsbooks. Get the full, current list with `GET https://therundown.io/api/v2/affiliates` — no key required.

## Keeping prices fresh: polling vs. WebSocket

REST works on every plan, within its data-point allowance. Prices on each plan trail the market by a fixed delay: five minutes on Free, 60 seconds on Starter, and 30 seconds on Pro. Polling more often shows changes sooner, but never closer to real time than that delay, and every response counts against your data points (the `X-Datapoints` response header shows how many a request used).

Ultra and the plans above it add a WebSocket feed that pushes price changes as they happen, with one concurrent connection on Ultra. If you need true real-time odds — a live betting product, a trading or hedging tool, a price-move alerting system — the WebSocket feed on Ultra and up is the right tool. If your use case is slower, such as a daily odds table or an overnight research pipeline, polling REST within your plan's delay is simpler and is all you need.

## Free vs. paid plans

Prices and limits below are current as of October 2026; see [API pricing](/pricing/api) for the live numbers.

| Plan    | Price       | Data points                | Delay     | History | WebSocket         | Notes                                                                               |
| ------- | ----------- | -------------------------- | --------- | ------- | ----------------- | ----------------------------------------------------------------------------------- |
| Free    | $0, no card | 20,000/day (200,000/month) | 5 min     | —       | No                | Pre-match moneyline, spread, total from DraftKings, FanDuel, BetMGM only            |
| Starter | $49/month   | 25,000,000/month           | 60 sec    | 7 days  | No                | Every published book, market, and period; internal/personal use                     |
| Pro     | $149/month  | 125,000,000/month          | 30 sec    | 30 days | No                | Adds value/+EV calculations, opening and closing lines, commercial end-user display |
| Ultra   | $399/month  | 500,000,000/month          | Real-time | 90 days | Yes, 1 connection | Adds futures                                                                        |

Above Ultra, the Super ($649/month), Mega ($999/month), and $2,499/month tiers add more concurrent WebSocket connections and longer history, and Enterprise is custom-priced for higher volume. See [API pricing](/pricing/api) for the exact figures on each.

## Where to go next

- Get a free key on the [odds API page](/api), then follow the [quickstart](/docs/quickstart).
- Compare plans on [API pricing](/pricing/api).
- League guides: the [NFL odds API](/nfl-odds-api), [NBA odds API](/nba-odds-api), and [MLB odds API](/mlb-odds-api).
- Player markets: the [player props API](/player-props-api).
- Sharp and prediction-market prices: the [Pinnacle odds API](/pinnacle-odds-api) and [Kalshi odds API](/kalshi-odds-api).
- Building an AI agent: [Build with AI](/build-with-ai) and the [sports odds API for AI agents](/blog/sports-odds-api-for-ai-agents).

## Questions

### What does TheRundown's odds API return?

Structured JSON for each event: its markets (moneyline, spread, total, player props, and more), each market's participants, each participant's lines, and each line's prices by sportsbook, with the American odds and an update timestamp.

### How do I authenticate requests?

Send your key in the X-TheRundown-Key header on every request to https://therundown.io/api/v2. Store it in an environment variable instead of hardcoding it in source.

### How fresh are the odds I get back?

It depends on your plan: a 5-minute delay on Free, 60 seconds on Starter, 30 seconds on Pro, and real-time delivery over WebSocket on Ultra and up.

### Does the free plan include player props?

No. Free covers pre-match moneyline, spread, and total lines from DraftKings, FanDuel, and BetMGM. Starter and up include every published book, market, and period.

### Can I display the odds to my own users?

Pro and up permit commercial end-user display. Starter is for internal or personal use only. See [API pricing](/pricing/api) for current terms.

### How do I see every sportsbook the API covers?

Call GET https://therundown.io/api/v2/affiliates, which lists all currently supported books and does not require a key.
