Futures and Outrights Data: Building Championship and Award Boards

How futures and outright boards are shaped in odds data, how to join entrants across books, measure board-level margin, build a championship or award board, and archive it.

A futures board looks simple on a sportsbook: a list of teams or players with a price next to each. As data, it behaves very differently from a game line. A board can have dozens of entrants instead of two or three, it stays open for months, every book may list a slightly different set of entrants, and the prices across the whole board carry far more margin than a moneyline. If you build a championship tracker, an MVP board or a golf outright screen on the same assumptions you use for game odds, the numbers will look wrong in subtle ways.

This guide covers how futures and outrights are shaped in the PreciseAPI feed, how to line entrants up across books, how to measure and remove board-level margin, how to build and refresh a board without wasting credits, and how to keep your own history. It is a data guide: it describes how prices are structured, not which entrant to back.

What counts as a futures market

A futures market is settled by something that happens over a season or a tournament rather than in a single game: a league championship, a conference or division title, a season award, or a tournament winner. Golf outrights are the same idea on a shorter timescale, with one board per event and a large field of players. The glossary entry for futures has the short definition.

In the catalog, these markets live in the futures group under the market key outright, and they are served by their own endpoint, /v1/futures, rather than by /v1/odds. That separation is deliberate. Game markets hang off an event id; a futures board hangs off a league. The markets=all shortcut on the odds endpoints therefore covers every key for the league except outright.

Which leagues have boards

Futures are available for 12 of the 17 leagues in the catalog:

SportLeagues with futures
FootballNFL, NCAAF, CFL
BasketballNBA, WNBA, NCAAB
Baseball and hockeyMLB, NHL
SoccerSoccer (EPL, La Liga, Serie A, Bundesliga, Ligue 1, MLS, UCL)
GolfPGA
EsportsLeague of Legends, CS2

Tennis, UFC, Valorant, Dota 2 and Call of Duty have no futures boards. The free GET /v1/leagues endpoint returns a has_futures flag for every league, so check it at startup instead of hard-coding the list. League hubs such as NBA, NFL and PGA show what each league offers.

The shape of a futures response

One request returns every board for the leagues you ask for, with each source's price for every entrant:

curl "https://api.preciseapi.com/v1/futures?league=nba&books=draftkings,fanduel,pinnacle&format=american" \
  -H "Authorization: Bearer $PRECISEAPI_KEY"

The response is a list of boards. Trimmed, with illustrative values:

{
  "data": [
    {
      "id": "fut_...",
      "league": "nba",
      "key": "championship",
      "name": "NBA Championship 2026-27",
      "updated_at": "2026-10-11T14:02:11.000Z",
      "bookmakers": [
        {
          "id": "draftkings",
          "name": "DraftKings",
          "outcomes": [
            { "id": "sel_...", "name": "Team A", "participant_id": "...", "price": 300 },
            { "id": "sel_...", "name": "Team B", "participant_id": "...", "price": 450 }
          ]
        }
      ]
    }
  ],
  "meta": { "credits_used": 2 }
}

A few properties matter for everything that follows:

A call costs 2 credits whatever the number of leagues, and futures are included on every plan, the free sandbox among them. You can comma-separate leagues, league=nfl,nba,mlb,nhl, to fetch four sports' boards in one call. The sportsbooks reference lists every source id you can pass to books= (or its alias bookmakers=).

Joining entrants across books

The point of a futures board is comparison: one team's title price at every book, side by side. Two practical issues come up.

First, books do not always list the same entrants. A long-odds team may be on one book's board and missing from another's, or a book may stop quoting an entrant that has been eliminated before others do. Build your rows from the union of entrants across books and leave a cell empty when a book has no price, rather than assuming every book lists everyone.

Second, join on ids, never on names. Team names on futures boards come in many variants, and player names on award boards are worse. The outcome id is shared across books for the same entrant on the same board, so it is the natural row key. Fall back to participant_id when you need to join a futures entrant to the rest of your data, such as a team's game odds or a player's props. If an entrant arrives without a participant_id, keep it on the board via its outcome id and treat it as unmapped rather than matching it by name. The normalization post explains how ids are assigned across the feed.

Board-level margin

On a two-way market the implied probabilities of both sides sum to a little over 1. On a futures board you sum across every entrant, and the excess is usually much larger, because the book applies a margin to dozens of prices at once and has months of uncertainty to price.

Here is a complete illustrative eight-entrant board:

EntrantPriceImpliedFair (multiplicative)Fair priceFair (power)Fair price
A+1500.40000.3496+1860.3705+170
B+3000.25000.2185+3580.2226+349
C+5000.16670.1457+5860.1434+597
D+8000.11110.0971+9300.0924+982
E+10000.09090.0795+11580.0744+1245
F+15000.06250.0546+17300.0495+1918
G+25000.03850.0336+28750.0293+3316
H+40000.02440.0213+45910.0179+5496
Total1.14401.00001.0000

The implied probabilities sum to 1.1440: 14.40% overround, or a hold of 1 - 1 / 1.1440 = 12.59%. The hold comparison post explains why futures sit at the top of the margin range and how to chart hold by market type.

The two fair columns show why the de-vig method matters more here than on a game line. The multiplicative method spreads the margin in proportion to each entrant's probability. The power method (exponent k = 1.0837 on this board) assigns more of it to the longshots, so the favorite's fair price moves from +186 to +170 and the last entrant's from +4591 to +5496. On a board this wide, those are not rounding differences. The no-vig fair odds guide walks through each method, including Shin, which is commonly used for outrights; pick one, label it on the board, and keep it consistent across boards.

Only de-vig complete boards

Hold and fair probabilities assume you have every entrant. If a book lists 30 teams and your feed shows 28, the sum understates the margin and every fair probability comes out slightly too high. Before computing either, check that each book's entrant count matches the union for the board, and skip or flag books with gaps. Golf is the hardest case: fields are large, and a field or "any other player" option, where a book offers one, has to be included in the sum for the board to be complete.

Building the board

A useful futures board has one row per entrant, one column per book, the best available price highlighted, and a reference probability alongside. /v1/best-lines does that comparison for event markets, but it does not cover futures, so the best-price step happens in your code. It is short:

const API = 'https://api.preciseapi.com/v1';
const headers = { Authorization: `Bearer ${process.env.PRECISEAPI_KEY}` };

async function get(path) {
  const res = await fetch(`${API}${path}`, { headers });
  if (!res.ok) throw new Error((await res.json()).error.message);
  return (await res.json()).data;
}

// Reference books: sources tagged "sharp" in the catalog (free call).
const sources = await get('/sportsbooks?type=sportsbook');
const SHARP = new Set(sources.filter((s) => s.tags.includes('sharp')).map((s) => s.id));

const boards = await get('/futures?league=nba,nfl&format=decimal');

for (const board of boards) {
  const rows = new Map(); // outcome id -> { name, prices: { book: decimal } }
  for (const book of board.bookmakers) {
    for (const o of book.outcomes) {
      const row = rows.get(o.id) ?? { name: o.name, participant: o.participant_id, prices: {} };
      row.prices[book.id] = o.price;
      rows.set(o.id, row);
    }
  }

  // De-vig each complete sharp board multiplicatively, then average per entrant.
  const fair = new Map();
  for (const book of board.bookmakers.filter((b) => SHARP.has(b.id))) {
    if (book.outcomes.length < rows.size) continue; // incomplete board
    const sum = book.outcomes.reduce((s, o) => s + 1 / o.price, 0);
    for (const o of book.outcomes) {
      const list = fair.get(o.id) ?? [];
      list.push(1 / o.price / sum);
      fair.set(o.id, list);
    }
  }

  console.log(`${board.name} (updated ${board.updated_at})`);
  for (const [id, row] of rows) {
    const [bestBook, best] = Object.entries(row.prices).sort((a, b) => b[1] - a[1])[0];
    const ref = fair.get(id);
    const refP = ref ? ref.reduce((a, b) => a + b, 0) / ref.length : null;
    console.log(`  ${row.name.padEnd(24)} best ${best.toFixed(2)} @ ${bestBook.padEnd(12)} books ${Object.keys(row.prices).length}` +
      (refP ? `  ref ${(refP * 100).toFixed(1)}%` : ''));
  }
}

Decimal prices make "best" a simple maximum, and multiplicative de-vigging a one-liner. The reference column is a description of where low-margin books price each entrant at that moment; a gap between a book's price and the reference can just as easily be a stale price or an incomplete board as anything else. The futures odds API page summarizes the endpoint, and the odds screen post covers the UI patterns for highlighting best prices.

Displaying longshots

Futures boards are where American odds become awkward. A one-cent move in probability near 2% is a swing of several hundred points in American odds, and two books at +4000 and +4500 differ by less than half a percentage point of implied probability. Store prices as decimal or probability, sort and compare on those, and render American only for display. If your audience prefers implied probability, format=probability returns it directly.

Refreshing and archiving

Polling cadence

Futures prices move more slowly than game lines. Large moves follow injuries, trades and results, and between those, an occasional refresh is enough. Futures are served over REST only; the WebSocket stream carries event markets.

Because a call costs 2 credits regardless of how many leagues it covers, batch your leagues into one request. Pulling four leagues every five minutes is 288 calls a day, or 576 credits, about 17,280 credits over 30 days. That fits comfortably within the 50,000 monthly credits on Basic. Tighten the interval during periods when you expect movement, such as a trade deadline or the days around a major tournament, and relax it otherwise. The credits and rate limits post has more budgeting patterns, and pricing lists each plan's allowance.

Keep your own history

/v1/history stores timestamped price changes for main full-game moneyline, spread and total markets. Futures are not included, so if you want opening prices, movement charts or a season-long record of a board, archive snapshots yourself. A flat table works:

CREATE TABLE futures_snapshot (
  observed_at     TIMESTAMPTZ NOT NULL,
  board_id        TEXT NOT NULL,     -- data[].id
  league          TEXT NOT NULL,
  board_key       TEXT NOT NULL,     -- data[].key
  book            TEXT NOT NULL,
  outcome_id      TEXT NOT NULL,     -- shared across books for one entrant
  participant_id  TEXT,
  name            TEXT NOT NULL,
  price_decimal   NUMERIC NOT NULL,
  PRIMARY KEY (board_id, book, outcome_id, observed_at)
);

Write a row only when a price changes, and store the board's updated_at alongside your own capture time. That keeps the table small for boards that sit still for days, and it lets you compute board-level hold at any point in the past by summing one book's rows at a timestamp.

Common pitfalls

Frequently asked questions

Which leagues have futures in PreciseAPI?

NFL, NCAAF, CFL, NBA, WNBA, NCAAB, MLB, NHL, soccer, PGA, League of Legends and CS2, 12 of the 17 leagues. GET /v1/leagues returns a has_futures flag for each league, and it is free to call.

How much does a futures request cost?

/v1/futures costs 2 credits per call. The cost does not change with the number of leagues, so league=nfl,nba,mlb costs the same as league=nba. Futures are included on every plan, including the sandbox.

Does /v1/best-lines include futures?

No. Best lines covers event markets such as moneylines, spreads, totals and props. For futures, compute the best price per entrant from the /v1/futures response, which is a few lines of code when you request format=decimal.

Is there line history for futures?

Not through /v1/history, which covers main full-game moneyline, spread and total markets. Archive /v1/futures snapshots yourself if you need opening prices or movement over a season.

Why do the implied probabilities on a board add up to more than 100%?

Each book applies its margin across every entrant, and futures carry larger margins than game lines. Summing the implied probabilities gives the overround; dividing each by the sum, or using another de-vig method, gives fair probabilities. Only do this for complete boards.

How do I match a futures entrant to the same team's game odds?

Use participant_id, which identifies the team or player, rather than the display name. The outcome id is the right key for matching one entrant across books on the same board.