Skip to main content
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['line']})" if line.get("line") 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('line')} ({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['timestamp']}: {entry['market_name']} {entry['line']} @ {entry['price']}")

# 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:
            data = json.loads(message)

            if data.get("meta", {}).get("type") == "heartbeat":
                continue

            event_id = data.get("event_id")
            market = data.get("market_name", "Unknown")
            print(f"Update: {event_id} - {market}")

            for participant in data.get("participants", []):
                for line in participant.get("lines", []):
                    for aff_id, price in line.get("prices", {}).items():
                        print(f"  {participant['name']}: {price['price']} ({aff_id})")


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:
                    data = json.loads(message)
                    if data.get("meta", {}).get("type") == "heartbeat":
                        continue

                    # Process update
                    print(f"Update: {data.get('event_id')} - {data.get('market_name')}")

        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