Documentation Index
Fetch the complete documentation index at: https://docs.therundown.io/llms.txt
Use this file to discover all available pages before exploring further.
An official Python SDK is coming soon. In the meantime, this guide shows how to use TheRundown API directly with the
requests library for REST calls and websockets for real-time streaming.Installation
pip install requests websockets
Configuration
import os
API_KEY = os.environ.get("THERUNDOWN_API_KEY", "YOUR_API_KEY")
BASE_URL = "https://therundown.io/api/v2"
WS_URL = "wss://therundown.io/api/v2/ws/markets"
HEADERS = {
"X-TheRundown-Key": API_KEY,
}
Getting Sports
import requests
response = requests.get(f"{BASE_URL}/sports", headers=HEADERS)
response.raise_for_status()
sports = response.json()["sports"]
for sport in sports:
print(f"{sport['sport_id']}: {sport['sport_name']}")
Getting Events with Odds
import requests
from datetime import date
sport_id = 4 # NBA
today = date.today().isoformat()
response = requests.get(
f"{BASE_URL}/sports/{sport_id}/events/{today}",
headers=HEADERS,
params={
"market_ids": "1,2,3", # Moneyline, Spread, Total
"affiliate_ids": "19,23", # DraftKings, FanDuel
"main_line": "true",
}
)
response.raise_for_status()
data = response.json()
for event in data["events"]:
away = event["teams"][0]["name"]
home = event["teams"][1]["name"]
print(f"\n{away} @ {home}")
for market in event.get("markets", []):
print(f" {market['name']}:")
for participant in market["participants"]:
for line in participant["lines"]:
for aff_id, price in line["prices"].items():
p = price["price"]
display = "N/A" if p == 0.0001 else f"{p:+d}" if p > 0 else str(int(p))
line_val = f" ({line['value']})" if line.get("value") else ""
print(f" {participant['name']}{line_val}: {display} @ {aff_id}")
Filtering by Affiliate
# Only DraftKings lines
response = requests.get(
f"{BASE_URL}/sports/4/events/{date.today()}",
headers=HEADERS,
params={
"market_ids": "1,2,3",
"affiliate_ids": "19", # DraftKings only
"main_line": "true",
}
)
Getting Player Props
# NBA player points, rebounds, assists, 3PT
response = requests.get(
f"{BASE_URL}/sports/4/events/{date.today()}",
headers=HEADERS,
params={
"market_ids": "29,35,38,39", # Points, Rebounds, 3PT, Assists
"affiliate_ids": "19",
}
)
response.raise_for_status()
for event in response.json()["events"]:
print(f"\n{event['teams'][0]['name']} @ {event['teams'][1]['name']}")
for market in event.get("markets", []):
print(f" {market['name']}:")
for participant in market["participants"]:
for line in participant["lines"]:
price = line["prices"].get("19", {}).get("price", "N/A")
print(f" {participant['name']}: {line.get('value')} ({price})")
Historical Odds
event_id = "abc123"
# Full market history
response = requests.get(
f"{BASE_URL}/events/{event_id}/markets/history",
headers=HEADERS,
params={"affiliate_ids": "19"},
)
history = response.json()["history"]
for entry in history:
print(f"{entry['updated_at']}: line={entry['line']} price={entry['price']} ({entry['change_type']})")
# Opening lines
openers = requests.get(
f"{BASE_URL}/events/{event_id}/openers",
headers=HEADERS,
params={"market_ids": "1,2,3"},
).json()
# Closing lines
closing = requests.get(
f"{BASE_URL}/events/{event_id}/closing",
headers=HEADERS,
params={"market_ids": "1,2,3"},
).json()
WebSocket Streaming
import asyncio
import json
import websockets
async def stream_odds(sport_ids="4", market_ids="1,2,3"):
url = (
f"{WS_URL}?key={API_KEY}"
f"&sport_ids={sport_ids}"
f"&market_ids={market_ids}"
)
async with websockets.connect(url) as ws:
print("Connected to WebSocket")
async for message in ws:
msg = json.loads(message)
if msg.get("meta", {}).get("type") == "heartbeat":
continue
d = msg["data"]
print(
f"Update: event={d['event_id']} market={d['market_id']}"
f" aff={d['affiliate_id']} price={d['price']}"
)
asyncio.run(stream_odds())
WebSocket with Reconnection
import asyncio
import json
import random
import websockets
async def stream_with_reconnect(sport_ids="4", market_ids="1,2,3"):
url = (
f"{WS_URL}?key={API_KEY}"
f"&sport_ids={sport_ids}"
f"&market_ids={market_ids}"
)
reconnect_delay = 1.0
max_delay = 30.0
while True:
try:
async with websockets.connect(url) as ws:
print("WebSocket connected")
reconnect_delay = 1.0
async for message in ws:
msg = json.loads(message)
if msg.get("meta", {}).get("type") == "heartbeat":
continue
# Process update
d = msg["data"]
print(f"Update: event={d['event_id']} market={d['market_id']} price={d['price']}")
except (websockets.ConnectionClosed, ConnectionError) as e:
jitter = random.uniform(0, 1)
delay = min(reconnect_delay + jitter, max_delay)
print(f"Disconnected ({e}). Reconnecting in {delay:.1f}s...")
await asyncio.sleep(delay)
reconnect_delay = min(reconnect_delay * 2, max_delay)
asyncio.run(stream_with_reconnect())
Error Handling
import requests
import time
def api_get(path, params=None, max_retries=3):
"""Make an API request with retry logic for rate limits."""
for attempt in range(max_retries):
response = requests.get(
f"{BASE_URL}{path}",
headers=HEADERS,
params=params,
)
if response.status_code == 200:
return response.json()
if response.status_code == 429:
wait = (2 ** attempt) + random.uniform(0, 1)
print(f"Rate limited. Retrying in {wait:.1f}s...")
time.sleep(wait)
continue
response.raise_for_status()
raise Exception("Max retries exceeded")
# Usage
data = api_get(
f"/sports/4/events/{date.today()}",
params={"market_ids": "1,2,3"},
)
Next Steps
Getting Live Odds
Detailed guide on fetching odds
WebSocket Streaming
Real-time data streaming guide
Authentication
All authentication methods
Rate Limits
Rate limit details and best practices