How Lumify forecasts wagers

A model prediction, not a beat-the-market claim — no OOS/independence gate, unlike main-line ev. Player-prop rate model on MLB / NFL / NCAAF / NBA / NCAAB / NHL; tennis main-line — moneyline from ranking Bradley-Terry, game handicap and total games from a Normal-approx games model. A sibling of predictive bets[], not a replacement. Inspector endpoints stay on the API reference. This page is the how and the field catalog.

API key Sign in, or get an instant trial key — no signup required.

Three intelligence surfaces

  • Predictive bets[] — vig-stripped probability / fair_price plus Price overlay on MLB, tennis, soccer (MLS + big-five), NFL, and NCAAF. Walkthrough: /docs/understanding-odds.
  • Main-line ev (Beta) — the same sharp-fair gap packaged as ev_pct + Kelly on moneyline, spreads, and totals. Scan: GET /intelligence/ev.
  • forecasts[] — this page. A probability-based prediction, not a beat-the-market claim. Player props: MLB, NFL, NCAAF, NBA, NCAAB, NHL. Tennis main-line — moneyline (ML_P1/ML_P2) from ranking gap, game handicap (SPREAD_P1/SPREAD_P2) and total games (OVER/UNDER) from a Normal-approx games model — not tennis bets[]. Can populate when available is still false. Do not treat available: false as “no intelligence JSON.”

How the model works

  • Start from the player's recent counting-stat rate (typically last 10 games), shrunk toward a prior so a 3-game heater does not dominate. Prior weight is 12 — sufficiency is n / (n + 12).
  • Treat that rate as λ in a Poisson and score it against the posted Over/Under main. The model always picks the more likely side when a strictly-matched two-way main is in range.
  • One-sided longshots (|price| ≥ 1000) and rate-certain low-count lines (p_hit ≥ 0.95 on counting markets) are dropped so ladder rows do not fill the board. Yardage markets skip that Poisson cut.
  • Rank the slate by conviction — distance from a coin flip, times how much of the rate is this player's own boxes, times an optional research multiplier. Cap: 3 wagers per event / 25 on the sport slate.
  • Optional Deep Research overlay may nudge p_hit by at most ±0.03. The chosen side never flips.

GET /intelligence/forecasts returns only the selected: true rows (the daily board). GET /events/{id}/intelligence forecasts[] includes the rest of that event's catalog with selected: false.

Forecastable markets vs settleable inventory

Forecasts score a 1:1 counting subset of the player-props catalog. Combos, anytime TD, double-double / triple-double, and hockey points are settleable on /docs/player-props but are not selected onto the daily board.

SportForecastable markets (1:1)On player-props, not forecasted
MLBstrikeouts_pitcher, hits, rbis, runs, strikeouts_batter, hits_allowed, earned_runs, outs_recordedhome_runs, stolen_bases, total_bases, hits_runs_rbis
NFL / NCAAFpassing_yards, rushing_yards, receiving_yards, receptionspassing_tds, rushing_tds, touchdowns
NBA / NCAABpoints, rebounds, assists, steals, blocks, threes_madepts_rebs, pts_asts, rebs_asts, pts_rebs_asts, double_double, triple_double
NHLgoals, hockey_assists, shots_on_goalhockey_points
TennisMoneyline (ML_P1 / ML_P2) from ranking Bradley-Terry; game handicap (SPREAD_P1 / SPREAD_P2) and total games (OVER / UNDER) from a Normal-approx games model fit on historical set/game scores — soft-book game-unit lines only, never Pinnacle's set-unit total

Field catalog

Player-prop rows: bet_type is null, and player / player_id / side are populated. Tennis moneyline rows set bet_type to ML_P1 or ML_P2, player_role to p1/p2, and leave side / line null. Tennis spread rows set bet_type to SPREAD_P1/SPREAD_P2 with player / player_role / line populated. Tennis total-games rows set bet_type to OVER/UNDER with line populated and player / player_id / player_role null — the total is match-level, not about either player.

Top-level (daily board)

FieldTypeDescription
sportstringSport slug this slate was scored for.
datestringUTC slate date (YYYY-MM-DD).
model_versionstringScorer version used for every wager on this page (e.g. forecast-v0).
reliabilitystringDefault badge on this slate. v0 ships emerging; each wager repeats the same field. Cells promote as a scored history accumulates — there is no numeric threshold published yet.
wagersarraySelected forecasted wagers, highest conviction first.
totalintegerCount of wagers on this page.

Wager fields

FieldTypeDescription
event_idintegerLumify event ID. Present on the daily board; omitted on GET /intelligence forecasts[] (the event is the path).
player / player_idstring or null / integer or nullDisplay name and Lumify ID. Bound by exact / Jr-stripped name match to the priced line. Join player_id to GET /v1/players/{id}. Null on a main-line row with no player attribution (match-level bet_type like OVER/UNDER/ML_DRAW).
bet_typestring or nullMain-line token. Tennis sets ML_P1/ML_P2 (moneyline), SPREAD_P1/SPREAD_P2 (game handicap), or OVER/UNDER (total games). Null on player-prop rows — that is the discriminator. ML_HOME/ML_AWAY/ML_DRAW (team sports) are reserved.
player_rolestring or nullhome/away for team sports or p1/p2 for head-to-head sports, set only alongside a non-null bet_type. Null on player-prop rows and on match-level main-line tokens.
marketstringPlayer-prop rows: 1:1 counting category from the table above (not the combo / yes-no keys on the settleable catalog). Main-line rows (bet_type set): the main-line family — h2h, spreads, or totals.
linenumber or nullPosted line the model was scored against. Player-prop and totals main-line rows: Over/Under number. spreads main-line rows: the spread number. Null on h2h/moneyline rows.
sidestring or nullPlayer-prop rows: over or under — the more likely side given the player's shrunken rate versus line. Null on main-line rows — read the picked outcome from bet_type instead.
p_hitnumberModel probability (0–1) that the picked outcome (side on prop rows, bet_type on main-line rows) hits. Prop rows: built from the player's shrunken counting-stat rate (Poisson vs the posted Over/Under). Optional research may nudge a prop's p_hit by at most ±0.03; the chosen side stays the same.
interval[number, number][lo, hi] stated band around p_hit. Wider when sufficiency is low. A stated evidence band, not a statistical confidence interval.
sufficiencynumberEvidence weight on 0–1: n / (n + 12), where n is the recent-form game count (typically L10). A player with 10 recent games has sufficiency ≈ 0.45 — about half the rate is player-observed, half prior. The wager still ships at any sufficiency.
convictionnumberBoard rank key on 0–1: |p_hit − 0.5| × 2 × sufficiency × research. A 0.76 call on a thin sample ranks below a 0.62 call on a long one. Highest conviction first. This is not the same scale as research.conviction.
reliabilitystringBadge on this sport×market cell: emerging, moderate, high, or informational. v0 ships emerging for every wager. Promotion is “as a scored history accumulates,” not a published numeric threshold.
selectedbooleantrue on the daily board (these are the top-conviction rows). On GET /intelligence the array also includes the rest of the event catalog with selected: false.
booksobjectAmerican price for the picked outcome, keyed by bookmaker slug. Posted market price for the side/bet_type the model picked.
driversarraySigned contributions that moved p_hit. Typical prop-row id is player.l10_rate (shrunken L10 counting rate); tennis moneyline uses player.tennis_ranking, tennis spreads use player.tennis_game_margin, tennis totals use match.tennis_total_games. Treat unknown ids as opaque. input is the measured rate/rating behind the driver; effect is the probability-unit shift versus a baseline case on the same line (0.0 on yardage); direction is up / down / neutral.
researchobject or nullOptional Deep Research overlay on high-probability wagers (p_hit ≥ 0.80): {stance, conviction, note}. stance is validate / neutral / invalidate. note is the wager-level why (the fact the model cannot see); validate / invalidate rows always carry one. research.conviction is a qualitative research strength (high / medium / low), not the 0–1 wager conviction rank. Validate nudges p_hit up by at most 0.03 and lifts the rank; invalidate does the reverse. The chosen side stays. null means read p_hit from the rate model alone.

Worked wager

Example wager · forecasts[] · list_forecasts
Total Runs — Ben Rortvedt MLB Under
0.5
−453 DraftKings

The write-up below is this ticket: under 0.5 runs at DraftKings −453.

Ben Rortvedt is priced at runs 0.5. His last-10 rate is 0.27 runs/game (drivers[0].input), so Poisson vs 0.5 makes under the more likely side at p_hit 0.76. Sufficiency 0.45 means that rate is about half player-observed (10 games vs k=12) — the interval is wide because of that. Conviction 0.24 is |0.76 − 0.5| × 2 × 0.45: a strong lean on a modest sample, so it ranks in the middle of the board rather than the top. DraftKings posts −453 on that under — the market price for the side the model picked. research is null, so no news overlay has been applied.

How to read this same object: /docs/understanding-odds#forecasts.

REST + MCP

SurfaceRESTMCPCredits
Daily boardGET /v1/intelligence/forecastslist_forecasts1
Per-event catalogGET /v1/events/{id}/intelligenceforecasts[]get_intelligence1
Live progressGET /v1/events/{id}/player-propsget_player_props1 when lines exist

Playground: #list_forecasts. Recipe: Read a forecasted prop wager. list_forecasts accepts sport=tennis and an optional market filter (h2h, spreads, or totals).