Skip to main content
TheRundown API provides several endpoints for accessing historical odds data. You can retrieve full price history for charting, compare opening and closing lines, and filter by time range.

Endpoints Overview

EndpointDescription
GET /api/v2/events/{eventID}/markets/historyFull price history across all markets for an event
GET /api/v2/events/{eventID}/markets/{marketID}/historyPrice history for a specific market (ideal for charting)
GET /api/v2/events/{eventID}/openersOpening lines for a single event
GET /api/v2/events/{eventID}/closingClosing lines for a single event
GET /api/v2/sports/{sportID}/openers/{date}Opening lines for all events in a sport on a date
GET /api/v2/sports/{sportID}/closing/{date}Closing lines for all events in a sport on a date

Full Market History

Use the full history endpoint to get every recorded price change for an event across all markets and sportsbooks.
curl "https://therundown.io/api/v2/events/{eventID}/markets/history?\
key=YOUR_API_KEY&affiliate_ids=19,23"

Query Parameters

ParameterTypeDescription
affiliate_idsstringComma-separated sportsbook IDs to include
market_idsstringComma-separated market IDs to filter
fromstringStart time in RFC 3339 format (e.g., 2026-02-10T00:00:00Z)
tostringEnd time in RFC 3339 format (e.g., 2026-02-12T23:59:59Z)

Example Response

{
  "meta": {
    "event_id": "abc123",
    "count": 2
  },
  "history": [
    {
      "id": 98001,
      "market_line_price_id": 50001,
      "event_id": "abc123",
      "sport_id": 4,
      "affiliate_id": 19,
      "market_participant_id": 7001,
      "market_id": 2,
      "line": "-3.5",
      "price": "-110",
      "change_type": "initial",
      "updated_at": "2026-02-10T14:30:00Z"
    },
    {
      "id": 98002,
      "market_line_price_id": 50001,
      "event_id": "abc123",
      "sport_id": 4,
      "affiliate_id": 19,
      "market_participant_id": 7001,
      "market_id": 2,
      "line": "-4",
      "price": "-110",
      "previous_price": "-105",
      "change_type": "price",
      "updated_at": "2026-02-11T09:15:00Z"
    }
  ]
}

Single Market History (Chart Data)

For building a line movement chart, fetch history for a specific market. This returns a chart-optimized response with series grouped by sportsbook (keyed by affiliate ID), where each data point uses shorthand fields: t (timestamp), p (price as a string), and c (closed_at).
# Spread history (market_id=2) for a specific event
curl "https://therundown.io/api/v2/events/{eventID}/markets/2/history?\
key=YOUR_API_KEY&affiliate_ids=19"
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://therundown.io/api/v2"
EVENT_ID = "abc123"

# Fetch spread history from DraftKings (affiliate_id 19)
response = requests.get(
    f"{BASE_URL}/events/{EVENT_ID}/markets/2/history",
    params={
        "key": API_KEY,
        "affiliate_ids": "19",
    }
)

data = response.json()
series = data["series"]  # Map keyed by affiliate ID

print("Affiliate            | Timestamp                  | Price")
print("-" * 65)
for aff_id, aff_series in series.items():
    for point in aff_series["data"]:
        print(f"{aff_series['affiliate_name']:>20} | {point['t']}  | {point['p']}")

Filtering by Time Range

Use from and to parameters in RFC 3339 format to scope history to a specific window. This is useful for showing line movement in the last 24 hours or during a specific period.
# History from the last 24 hours
curl "https://therundown.io/api/v2/events/{eventID}/markets/2/history?\
key=YOUR_API_KEY&affiliate_ids=19\
&from=2026-02-11T00:00:00Z\
&to=2026-02-12T00:00:00Z"
from datetime import datetime, timedelta, timezone

now = datetime.now(timezone.utc)
yesterday = now - timedelta(days=1)

response = requests.get(
    f"{BASE_URL}/events/{EVENT_ID}/markets/2/history",
    params={
        "key": API_KEY,
        "affiliate_ids": "19",
        "from": yesterday.strftime("%Y-%m-%dT%H:%M:%SZ"),
        "to": now.strftime("%Y-%m-%dT%H:%M:%SZ"),
    }
)

data = response.json()
series = data["series"]
total_points = sum(len(s["data"]) for s in series.values())
print(f"Found {total_points} price changes in the last 24 hours")

Opening Lines

The openers endpoints return the first price posted by each sportsbook for each market. The response uses the same V2 events structure (with markets, participants, lines, and prices).
curl "https://therundown.io/api/v2/sports/4/openers/2026-02-12?\
key=YOUR_API_KEY&market_ids=1,2,3&affiliate_ids=19,23&offset=300"

Closing Lines

The closing endpoint returns the final price posted before game time. The response uses the same V2 events structure as openers. Closing lines are widely considered the most efficient odds and are useful for evaluating betting performance.
curl "https://therundown.io/api/v2/sports/4/closing/2026-02-12?\
key=YOUR_API_KEY&market_ids=1,2,3&affiliate_ids=19,23&offset=300"

Building a Line Movement Chart

Here is a complete example that fetches spread history and formats the data for a charting library. The chart endpoint returns series as a map keyed by affiliate ID, with each entry containing an affiliate_name and data array of {t, p, c} points.
import requests
from datetime import datetime, timezone

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://therundown.io/api/v2"
EVENT_ID = "abc123"

# Fetch spread history for multiple books
response = requests.get(
    f"{BASE_URL}/events/{EVENT_ID}/markets/2/history",
    params={
        "key": API_KEY,
        "affiliate_ids": "19,23",
    }
)
data = response.json()
series = data["series"]  # Map keyed by affiliate ID (string)

# Print chart data — series is already grouped by sportsbook
for aff_id, aff_series in series.items():
    book_name = aff_series["affiliate_name"]
    print(f"\n{book_name} (affiliate {aff_id}) Spread Movement:")
    for point in aff_series["data"]:
        closed = " [CLOSED]" if point.get("c") else ""
        print(f"  {point['t']}: price={point['p']}{closed}")

# To use with matplotlib:
# import matplotlib.pyplot as plt
# import matplotlib.dates as mdates
#
# fig, ax = plt.subplots(figsize=(12, 6))
# for aff_id, aff_series in series.items():
#     dates = [datetime.fromisoformat(p["t"].replace("Z", "+00:00")) for p in aff_series["data"]]
#     prices = [float(p["p"]) for p in aff_series["data"]]
#     ax.step(dates, prices, where="post", label=aff_series["affiliate_name"])
# ax.set_xlabel("Time")
# ax.set_ylabel("Price")
# ax.legend()
# plt.title("Spread Price Movement")
# plt.show()

Comparing Openers to Current Lines

A common use case is showing how far a line has moved from its opener. Fetch both the opener and current odds, then compute the difference. Both endpoints return the same V2 events structure with markets > participants > lines > prices.
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://therundown.io/api/v2"
EVENT_ID = "abc123"

# Fetch opener and current data
opener_resp = requests.get(
    f"{BASE_URL}/events/{EVENT_ID}/openers",
    params={"key": API_KEY, "market_ids": "2", "affiliate_ids": "19"}
)

current_resp = requests.get(
    f"{BASE_URL}/events/{EVENT_ID}",
    params={"key": API_KEY, "market_ids": "2", "affiliate_ids": "19"}
)

# Both return { "events": [ { "markets": [...] } ] }
opener_data = opener_resp.json()
current_data = current_resp.json()

def extract_prices(data):
    """Extract participant prices from V2 events response."""
    results = {}
    for event in data.get("events", []):
        for market in event.get("markets", []):
            for participant in market["participants"]:
                for line in participant["lines"]:
                    for aff_id, price_obj in line["prices"].items():
                        key = (participant["id"], participant["name"])
                        results[key] = {
                            "value": line["value"],
                            "price": price_obj["price"],
                            "is_main_line": price_obj["is_main_line"],
                        }
    return results

opener_prices = extract_prices(opener_data)
current_prices = extract_prices(current_data)

print("Opening vs Current Spread:")
for (pid, name), opener in opener_prices.items():
    current = current_prices.get((pid, name))
    if current:
        print(f"  {name}: opened {opener['value']} ({opener['price']}) -> now {current['value']} ({current['price']})")

Next Steps

Getting Live Odds

Fetch current odds for today’s games

Player Props

Historical data for prop markets too

Market IDs

Full list of market types

Sportsbook IDs

All tracked sportsbooks