Skip to main content
Futures (outrights) are markets on the outcome of an entire competition — who wins the Super Bowl, the Stanley Cup, or this week’s PGA Tour event — rather than a single game. TheRundown serves them through a dedicated V2 endpoint, GET /api/v2/sports/{sportID}/futures, using the same market → participants → lines → prices shape as game odds.
Futures are in early access. The endpoint requires an Ultra plan or higher on API keys, and coverage is expanding — see what’s covered today. Requests on lower tiers return a 403 with an upgrade_url (see Errors).

Competitions Are Intervals, Not Games

A futures event represents a competition — a span of time, not a point on the calendar. That changes three things compared to game events:
  • Two dates instead of one. event_date is when the competition starts (opening kickoff of the NFL season, Thursday’s first tee time), and settle_by is the settlement horizon — when the market must have graded (Super Bowl Sunday, the tournament’s final round). An NBA championship board opens in October and settles in June.
  • A stable event_id for the whole competition. The event_id is an opaque hash that stays constant from the day the board opens until settlement. Cache it — it is the public handle for the competition across snapshots and the delta feed.
  • No teams, no score. A competition has no away/home sides, so futures events carry no teams array and no score block. The human-readable identity lives in schedule.event_name (e.g. "NFL Super Bowl Winner (2026 Season)").
Here is a real (trimmed) NFL championship event:
Season-long team competitions currently report event_status: "STATUS_SCHEDULED" for the life of the board — live in-progress status for team seasons is not yet populated on event_status, so do not build logic on it. Golf tournaments do transition (STATUS_SCHEDULEDSTATUS_IN_PROGRESSSTATUS_FINAL) because each competition spans only a few days. For a season board’s live standing, read the progress block on the single-competition endpoint instead — its phase/entries update throughout the season even while event_status stays STATUS_SCHEDULED.

Reading the Board

Each market is a grid of participants × sportsbooks. Every participant (a team, or a golfer — golfers use TYPE_TEAM like UFC fighters) carries one line whose prices object is keyed by affiliate ID. Prices are American odds, so championship longshots run large: +50000 is a real price on a 500/1 team.
To render an odds board, walk markets[].participants[] and read each participant’s lines[0].prices:
A few field-level notes:
  • Snapshot price values are numbers (e.g. 1000 for +1000). The markets delta feed serializes price and previous_price as strings, so normalize them deliberately when applying deltas. Treat snapshot value 0.0001 as off the board, as everywhere else in the API — see Sentinel Values.
  • A price with closed_at set is no longer offered by that book (the golfer missed the cut, the book pulled the number). It is included so you can show the last traded price; filter on closed_at absence for a live board.
  • Join on participants[].id, not name — it is the stable team/golfer identifier.

The Date Window: Interval Overlap

Because competitions are intervals, from/to filter by overlap, not by start date. An event is returned when its [event_date, settle_by] span intersects your window: settle_by >= from and event_date <= to. Two behaviors worth internalizing:
  • from=today is not “starts today”. It means “has not finished yet” — that is what makes the default listing “active boards” work.
  • include_settled=true also lifts the default from=now. Settled competitions’ intervals ended in the past, so a default from of now would hide exactly the history you asked for. With include_settled=true you get settled markets, terminal events, and an unbounded window start — constrain it with explicit from/to if you only want a slice.
Date-only values (YYYY-MM-DD) are interpreted in the timezone given by offset (minutes from UTC, e.g. 300 for US Central) — the same convention as the game endpoints.

Paging with Cursors

Futures paging is keyset-based — there is no skip/page-number parameter. When more results exist, the response carries meta.next_cursor; pass it back verbatim as cursor. A response without next_cursor is the last page.
The token is opaque — never parse or construct one. Ordering is deterministic: soonest-to-resolve first (settle_by, then event_date, then event_id), so the first page is always the boards closest to settlement. limit defaults to 50 and is capped at 200.

Keeping Prices Fresh: Snapshot → Delta

Futures price changes flow through the same /api/v2/markets/delta feed as game odds, and the futures snapshot hands you the bootstrap cursor directly in meta.delta_last_id.
Futures market IDs are not in the delta feed’s default market set. If you poll /api/v2/markets/delta without market_ids, you will receive game-market changes only and silently miss every futures move. Always pass the futures IDs explicitly, e.g. market_ids=1141.
The recipe:
  1. SnapshotGET /api/v2/sports/{sportID}/futures, store the board, save meta.delta_last_id.
  2. PollGET /api/v2/markets/delta?market_ids=1141&last_id=<saved>. Apply each delta row to your board, then save the response’s meta.delta_last_id for the next poll.
  3. Chain the cursor every poll, even when deltas is empty. The returned watermark advances to the head of the feed regardless of whether any rows matched your filter — an empty response is cheap and keeps your cursor inside the validity window.
Delta rows for futures look exactly like game-market deltas. Unlike numeric snapshot prices, their price and previous_price values are decimal strings:
Match rows to your cached board by (event_id, market_id, participant_id, affiliate_id). A complete worked loop:
Delta cursors do not have a fixed wall-clock lifetime. A cursor is rejected with an HTTP 400 when it falls too far behind the current head; the guard is based on intervening update volume across the platform. On a 400, re-snapshot the futures endpoint and resume from its fresh meta.delta_last_id. Poll every 30 seconds to a few minutes and chain the returned cursor on every response. Empty responses are nearly free and advance your cursor to the head of the stream.

Streaming Futures over WebSocket

Futures also stream natively on the multiplexed WebSocket. The dedicated futures channel carries price updates for competition boards only — game odds never appear on it — and supports the same snapshot → delta bootstrap as the REST recipe above, over one connection:
After the subscribed ack, the server replays the REST futures listing as one snapshot frame per sport — the same {meta, events} body as GET /api/v2/sports/{sportID}/futures, including each board’s settlement state as of the snapshot — then sends snapshot_complete and begins live market_price deltas. The snapshot_complete frame carries delta_last_id, so you can fall back to REST delta polling at any point without a gap. All filters (sport_ids, event_ids, market_ids, affiliate_ids) are optional for live frames — an unfiltered futures subscription streams every futures move on the platform. Snapshot requests are stricter because they replay the sport-scoped REST endpoints:
  • snapshot: true requires positive sport_ids, with no date — boards are long-lived intervals, not dated fixtures.
  • Adding event_ids narrows the snapshot to specific boards (via the single-competition endpoint) and requires exactly one sport in sport_ids.
  • An active subscription can re-snapshot at any time with { "action": "snapshot", "id": "golf-futures" }. The recovery variant { "action": "resync", "id": "golf-futures" } does the same and additionally confirms with a resync_ack frame once the fresh snapshot is delivered and live deltas resume — use it when you suspect you missed frames.
Entitlement matches REST: Ultra plan or higher for API keys, Pro or higher for web sessions. Subscribing without it returns an error frame with code forbidden; a transient futures_unavailable means the server is still warming its competition index — retry shortly.

Futures on the markets channel

A markets subscription stays game-only by default — the WebSocket twin of the delta feed’s default market set. Competition frames flow on it only when the subscription opts in explicitly, by naming future-class market_ids (e.g. [1141]) or competition event_ids in its filters; sport-scoped filters alone never opt in. The opt-in affects live frames only: markets snapshots (sport_ids plus date) never include competition boards. If you want board state plus deltas, use the futures channel; if you only need futures moves merged into an existing game-odds stream, add the market IDs to your filters.

Futures Market IDs

market_ids on the futures endpoint is intersected with the futures market set — passing game-market IDs there yields events with empty markets arrays (the event list itself still returns). In the other direction, remember that these IDs must be passed explicitly on /api/v2/markets/delta.

Sports Coverage

Futures are live for the following sports. The number of sportsbooks pricing each board varies by sport while early access expands — check the prices keys on a live board rather than assuming a fixed set: Team sports run one championship competition per season. Golf runs a competition per tournament, so expect a rolling list of upcoming events rather than a single board. F1 carries the two season championships only — no per-race markets.

Settlement Lifecycle

A board’s life is open → trade → settle. The settlement object tracks it per market, keyed by market ID:
  • A fresh board’s settlement is empty ({}) — a market with no entry has not entered grading. Entries appear as the competition nears resolution, carrying a pre-grading status: an in-progress golf tournament shows { "1141": { "status": "pending" } }.
  • Once graded, the entry becomes "status": "settled" with settled_at, and — for winner-shaped markets — winning_line (the winner’s canonical name) and winning_participant_id. Entry markets like Top 10 or Make The Cut grade per participant, so they settle without a single winning_line.
  • "settled" is the only terminal value. Treat any other status as “grading in progress” — the vocabulary may grow.
A real settled golf competition:
Settlement changes visibility:
  • A settled market disappears from the default listing (its prices and settlement entry are removed per market).
  • An event where every requested market has settled — or whose status is terminal (final/canceled/abandoned) — disappears entirely.
  • include_settled=true restores all of it, including the graded settlement blocks, which is how you fetch results after the fact.

Fetching One Competition

Every entry in a futures listing carries an event_id. Fetch that one competition directly with GET /api/v2/sports/{sportID}/futures/{eventID} — the same event shape as the listing, plus up to three optional detail-only keys covered below: progress, leaders, and player_leaders.
This endpoint always serves the competition, even after it settles. The listing hides settled markets and terminal events by default, but a detail fetch is a deep link to a competition you already hold the ID for, and it keeps working after settlement — graded results stay visible in settlement. There is no include_settled parameter here. An unknown event_id, an ID from a different sport, or a game (non-competition) event ID returns a 404.

Competition Stats (Progress)

Some competitions carry a live, non-odds status document — a leaderboard or a standings table — alongside the price board. It rides in the optional progress key on the single-competition endpoint above; the listing endpoint does not carry it.
progress is omitted entirely (never null) when no progress document exists yet for the competition. “Priced, no progress” is the normal state for a fresh team-championship board — not a degraded response — so check for the key’s presence rather than assuming it is always there.
Every progress document shares one envelope:
  • kind picks the shape of context and entries below. Two kinds are live today: stroke_play_leaderboard (golf) and league_standings (team-sport championships).
  • phase is the same across every kind: status uses the same vocabulary as event_status, label is a ready-to-display phrase (never raw upstream text), and current/total are null when there is no meaningful position — a standings table between games has a total but no current.
  • entries[].participant_id is always the SAME participant ID space markets[].participants[].id uses. Joining a progress row directly to a price is the whole point of the block.

stroke_play_leaderboard (golf)

A round-3 leaderboard for the same 3M Open shown earlier in Settlement Lifecycle — Jackson Koivun leads here and goes on to win:
context is round-level state shared by every golfer: cut_score and cut_count (once the cut is made), purse, and the current round/round_state. Each entries[] row is one golfer: position ("1"; ties render like "T2" — check tied), score_to_par/today relative to par, thru (holes completed this round, "F" once finished, or an ISO-8601 tee time before the round starts), status when a golfer is cut or withdraws (active/cut/wd), total_strokes, movement (position change since the prior update), and country.

league_standings (team-sport championships)

A mid-season NFL standings snapshot, on the same event as the moneyline board at the top of this guide:
Core fields (participant_id, name, rank, wins, losses, ties, win_pct, points) are always present; sport-specific fields — conference, division, group_rank, seed, games_behind, streak, clinch, points_for, points_against, home_record, away_record, last_ten, and (soccer) position, goal_difference, goals_for, goals_against — appear only when applicable. rank is league-wide, not scoped to a conference or division.

Leaders: Curated Season-Stat Leaderboards

Two more optional detail-only keys on the single-competition endpoint, leaders and player_leaders, surface a small, hand-verified set of season-stat leaderboards alongside the odds board — team-grain and player-grain respectively. Both share one shape:
  • stat is our own curated display name — never an upstream stat’s raw field or column name. stat_id is our internal identifier, exposed the same way market_id is elsewhere. season_year is the most recent season with data, resolved per request rather than hardcoded.
  • entries holds the top 5 ranked rows. Most stats rank highest-value-first; a few (ERA, goals-against average) rank the lowest value as rank: 1 — check the stat before assuming direction.
leaders (team-grain) is competition-scoped: entries[].participant_id is the SAME participant ID space progress and markets[].participants[].id use. Curated today for NFL, NCAAF, NBA, WNBA, NCAAB, MLB, NHL, MLS, EPL, Ligue 1, Bundesliga, La Liga, and Serie A. Win/loss/tie records and standings points are never sourced here — that is progress’s league_standings job. player_leaders (player-grain) differs in two ways: it is league-wide, not competition-scoped (player season stats carry no team linkage, so entries are the sport’s overall leaders for the labeled season, not just this competition’s two teams), and entries[].participant_id is the player ID space — the same normalized player IDs player-prop market participants use, not the team ID space leaders/progress share. Curated today for NFL, NCAAF, NBA, WNBA, NCAAB, MLB, and NHL; soccer is excluded (no reliable per-player goals/assists season data upstream).
Both leaders and player_leaders are omitted entirely (never an empty array) when the sport has no curated stat set, the board has no resolvable team participant, or no season-stat rows exist yet — the same omission contract as progress.

Common Pitfalls

progress is omitted entirely — never present as null — when no progress document exists yet for that competition. This is normal for a freshly opened board or a sport without a collector yet, not an error. Check leaders/player_leaders and the odds board in the meantime, and poll again later.
Futures market IDs are not in the delta feed’s default set. Pass them explicitly: market_ids=1141 (add the golf and award IDs if you track them). This is the single most common futures integration bug.
Same rule as the delta feed: a markets subscription is game-only unless it explicitly names future-class market_ids or competition event_ids — sport-scoped filters alone never opt in. Subscribe to the futures channel for board snapshots plus deltas, or add the futures market IDs to your existing filters.
Your cursor fell too far behind the current head. The guard is based on intervening update volume, not a fixed wall-clock expiry. Re-snapshot the futures endpoint, take the fresh meta.delta_last_id, and resume. To avoid it, poll every 30 seconds to a few minutes and chain the returned cursor on every response — including empty ones, which still advance the watermark to head.
Working as designed: the date window filters by interval overlap, and a season future that started in September still overlaps today because it has not settled. from bounds settle_by (“has not finished”), to bounds event_date (“has started by”).
include_settled=true also lifts the implicit from=now — otherwise settled history (whose intervals ended in the past) would be unreachable. Add explicit from/to bounds to scope the history you want.
Settled markets and terminal events are hidden by default. The board did not disappear — fetch it with include_settled=true to see the graded settlement block, including the winner.
Expected for team-sport season competitions today — live status transitions for season-long boards are not yet populated. Use settle_by and the settlement block, not event_status, to reason about where a season board stands.

Billing

Futures responses are metered as data points like every other odds endpoint — the standard usage headers (X-Datapoints, X-Datapoints-Used, X-Datapoints-Remaining) apply, and your plan’s data delay applies to futures prices as well. Filter with affiliate_ids and market_ids to keep snapshot costs down, and lean on the delta feed for updates. WebSocket futures work the same way: snapshot frames bill exactly like the REST reads they replay, live frames bill per data point, and futures usage appears under its own category in your account’s request log. See Rate Limits and the Efficient Polling guide.