Use this file to discover all available pages before exploring further.
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.
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 eventcurl "https://therundown.io/api/v2/events/{eventID}/markets/2/history?\key=YOUR_API_KEY&affiliate_ids=19"
import requestsAPI_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 IDprint("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']}")
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 hourscurl "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, timezonenow = 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")
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).
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.
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 requestsfrom datetime import datetime, timezoneAPI_KEY = "YOUR_API_KEY"BASE_URL = "https://therundown.io/api/v2"EVENT_ID = "abc123"# Fetch spread history for multiple booksresponse = 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 sportsbookfor 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()
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 requestsAPI_KEY = "YOUR_API_KEY"BASE_URL = "https://therundown.io/api/v2"EVENT_ID = "abc123"# Fetch opener and current dataopener_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 resultsopener_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']})")