Skip to main content
Polling the full events endpoint every few seconds is expensive, burns data points, and can trip your per-second throttle if you scale it across many sports or books. This guide covers how to keep data fresh without paying for or requesting far more than you need.

Why Polling Efficiency Matters

TheRundown usage is not just about request count. The cost of a polling loop depends on:
  • how many sportsbooks you request
  • how many markets you include
  • whether you pull full event payloads or only deltas
  • how often you refresh
A naive loop that fetches full event snapshots every few seconds can waste both data points and burst budget. Delta endpoints solve this by returning only what changed since your last request.

Shrink Every Response First

Before you tune polling intervals, make each response smaller.
curl -H "X-TheRundown-Key: YOUR_API_KEY" \
  "https://therundown.io/api/v2/sports/4/events/2026-02-26?market_ids=1,2,3&affiliate_ids=19,23&main_line=true&offset=300"
Use these levers aggressively:
  • market_ids: biggest control for response size
  • affiliate_ids: only request the books you actually surface
  • main_line=true: skip alternate lines if your product only shows the primary market
  • event-specific endpoints: if you only care about a handful of games, do not fetch the full slate
  • hide_closed_markets=1: useful during market discovery to avoid off-board clutter

Delta Endpoint Bootstrap Flow

The pattern for using delta endpoints has three stages:

1. Fetch the full snapshot

Start by loading the complete event data for the sport and date you need. This gives you the initial state and the first delta cursor.
curl "https://therundown.io/api/v2/sports/4/events/2026-02-26?key=YOUR_API_KEY&market_ids=1,2,3&affiliate_ids=19,23&main_line=true&offset=300"
The response includes meta.delta_last_id — save this value.

2. Poll with the delta cursor

On each subsequent poll, pass your saved cursor to the delta endpoint. It returns only events or prices that changed since that cursor. Event delta — returns full event objects that changed:
curl "https://therundown.io/api/v2/delta?key=YOUR_API_KEY&last_id=PREVIOUS_DELTA_LAST_ID&sport_id=4"
Market delta — returns individual price changes (most efficient):
curl "https://therundown.io/api/v2/markets/delta?key=YOUR_API_KEY&last_id=0&sport_id=4&market_ids=1,2,3"

3. Merge updates into local state

Each delta response contains the full updated object — replace (do not partially merge) the corresponding entry in your local cache. Update your cursor to the new delta_last_id from the response.

Choosing Between Event and Market Delta

EndpointReturnsBest for
GET /api/v2/deltaFull event objects (scores, status, markets)Apps that need score updates alongside odds
GET /api/v2/markets/deltaIndividual price changes onlyOdds-focused apps where you track scores separately
The market delta is usually the cheapest option because it returns only the specific prices that changed, rather than the entire event object. Match your polling frequency to your use case. Faster polling uses more data points and increases the chance of hitting your burst limit if you parallelize heavily.
Use CaseIntervalEndpointNotes
Live odds screen5–10sMarket deltaFastest practical interval for REST
Pre-match odds monitoring30–60sMarket deltaLines move slowly before game time
Live scores15–30sEvent deltaScore updates come in bursts during play
Pre-match schedules5 minFull eventsSchedules rarely change close to game time
Historical/closing linesOn demandOpeners/closingFetch once after the event starts or ends
For sub-second updates, use the WebSocket endpoint on a WebSocket-enabled tier instead of polling. WebSocket traffic does not increment the HTTP request counter, but pushed messages are still metered as data points.

Cache TTL Recommendations

Not all data changes at the same rate. Cache aggressively for reference data and use shorter TTLs for live data.
Data TypeRecommended TTLEndpoint
Sports list24 hoursGET /api/v2/sports
Affiliates list24 hoursGET /api/v2/affiliates
Teams6 hoursGET /api/v2/sports/{id}/teams
Market definitions6 hoursGET /api/v2/markets
Events (pre-match)5 minutesGET /api/v2/sports/{id}/events/{date}
Events (live)Use deltaGET /api/v2/delta or GET /api/v2/markets/delta
Market pricesReal-timeDelta endpoint or WebSocket

Staleness Guards

Your delta cursor can become stale if you stop polling for an extended period. When this happens, the delta endpoint may return an error or skip events that changed while you were away. How to detect stale data:
  • Track the updated_at timestamp on your cached events. If the newest update is more than 5 minutes old during a live game window, your data may be stale.
  • If a delta response returns an empty result but you know games are in progress, your cursor may have expired.
  • If you receive an error response from the delta endpoint, re-bootstrap from a full snapshot.
How to recover:
  1. Discard your current delta cursor
  2. Fetch a fresh full snapshot from the events endpoint
  3. Extract the new delta_last_id and resume polling

Watch Your Usage Headers

Every production poller should log and monitor:
  • X-Datapoints
  • X-Datapoints-Used
  • X-Datapoints-Remaining
  • X-Datapoints-Reset
  • X-Rate-Limit
That gives you the feedback loop to tune filters and polling intervals before users start hitting limits.

Code Example: Python Polling Loop

This example fetches a full snapshot, then polls the market delta endpoint with automatic fallback to a full refresh when the cursor goes stale.
import requests
import time

API_KEY = "YOUR_API_KEY"
BASE = "https://therundown.io/api/v2"
SPORT_ID = 4
MARKET_IDS = "1,2,3"
AFFILIATE_IDS = "19,23"
POLL_INTERVAL = 5  # seconds

# Local cache: event_id -> event data
events = {}

def fetch_full_snapshot():
    """Load the full event list and return the delta cursor."""
    resp = requests.get(
        f"{BASE}/sports/{SPORT_ID}/events/2026-02-26",
        headers={"X-TheRundown-Key": API_KEY},
        params={
            "market_ids": MARKET_IDS,
            "affiliate_ids": AFFILIATE_IDS,
            "main_line": "true",
            "offset": "300",
        }
    )
    data = resp.json()

    for event in data.get("events", []):
        events[event["event_id"]] = event

    cursor = data.get("meta", {}).get("delta_last_id", "0")
    print(f"Loaded {len(events)} events, cursor={cursor}")
    return cursor

def poll_market_delta(last_id):
    """Fetch price changes since last_id. Returns new cursor."""
    resp = requests.get(
        f"{BASE}/markets/delta",
        headers={"X-TheRundown-Key": API_KEY},
        params={
            "last_id": last_id,
            "sport_id": SPORT_ID,
            "market_ids": MARKET_IDS,
        }
    )

    if resp.status_code != 200:
        print(f"Delta error {resp.status_code}, re-bootstrapping...")
        return None  # Signal to re-bootstrap

    data = resp.json()
    changes = data.get("deltas", [])

    for change in changes:
        eid = change.get("event_id")
        print(
            f"Price change: {eid} {change.get('market_name')} "
            f"{change.get('participant_name')} -> {change.get('price')}"
        )

    new_cursor = data.get("meta", {}).get("delta_last_id", last_id)
    return new_cursor

# Bootstrap
cursor = fetch_full_snapshot()

# Poll loop
while True:
    time.sleep(POLL_INTERVAL)
    result = poll_market_delta(cursor)

    if result is None:
        # Cursor went stale, re-bootstrap
        cursor = fetch_full_snapshot()
    else:
        cursor = result

WebSocket vs. Polling Decision Guide

FactorREST PollingWebSocket
Latency5–60s depending on intervalSub-second
Usage impactConsumes data points and counts toward HTTP burst limitConsumes data points but does not increment the HTTP request counter
Implementation complexitySimple HTTP requestsRequires connection management, reconnection logic
Data freshnessAs fresh as your poll intervalReal-time
ReliabilityEach request is independentMust handle disconnects and reconnections
Best forPre-match monitoring, low-frequency updatesLive odds screens, real-time dashboards
Many production applications use both: WebSocket for live windows, with delta polling as a fallback when the socket disconnects or for lower-tier keys that do not have WebSocket access. See the Building an Odds Screen guide for this pattern in practice.