---
title: "Get bet intelligence for an event"
method: GET
path: "/v1/events/{event_id}/intelligence"
tags: ["events"]
---

# Get bet intelligence for an event

`GET /v1/events/{event_id}/intelligence`

## Request

- Base URL: `https://lumify.ai`
- URL: `https://lumify.ai/v1/events/{event_id}/intelligence`
- Auth: HTTP bearer

## Path parameters

- `event_id` integer, required: Lumify event ID

## Query parameters

- `bookmaker` string, nullable: Ignored. Intelligence always reports the book the assessment was priced against. Accepted values (pinnacle, fanduel, draftkings, betmgm, caesars, bet365, circa, westgate, wynn, south_point, stations, hardrock, betonline, betr, betrivers, lowvig, bovada) are kept for compatibility and do not change market.price or fair_price.

## Response `200`

Predictive bet intelligence: vig-stripped probability, fair_price, Price overlay (fair / edges_by_book / best), and main-line ev (Beta),         plus forecasts[] — forecasted wagers from the model (same objects as GET /v1/intelligence/forecasts; player props on MLB/NFL/NCAAF/NBA/NCAAB/NHL, tennis moneyline/spreads/totals). bets[] is live for MLB, tennis, soccer (MLS + big-five), NFL, and NCAAF. forecasts[] covers MLB, NFL, NCAAF, NBA, NCAAB, NHL, and tennis (can populate when available is false). Today bets[] is fair-price + line-shopping (edge/tier null; has_recommend false). The bookmaker query is ignored — prices are the book the assessment was priced against. Match-level tokens (OVER, UNDER, ML_DRAW) have null player/team attribution. Free only when available is false and forecasts is empty. Field catalog: https://lumify.ai/docs/reference#event-intelligence

- IntelligenceResponse
  - `event_id` integer, nullable: Lumify event ID this intelligence describes. Present on the standalone endpoint; omitted when inlined under an event via include_intelligence.
  - `available` boolean: False when no predictive `bets[]` have been computed for this event yet. `forecasts[]` can still populate on MLB / NFL / NCAAF / NBA / NCAAB / NHL / tennis. The request is free only when `available` is false and `forecasts` is empty.
  - `odds_source` string, nullable: Bookmaker `bets[].market` prices were sourced from. For predictive intelligence this is the assessment's market_book (not a live `?bookmaker=` overlay).
  - `sport` string, nullable: Sport slug for this event.
  - `league` string, nullable: League slug for this event, if any.
  - `players` object: Home/away (or p1/p2) participant identification, keyed by role: {role: {name, player_id, team_id}}.
  - `has_recommend` boolean, nullable: True when at least one bet meets the recommendation threshold; false when none do; null when intelligence has not been computed for this event. For predictive-framework sports a recommendation requires a non-null `tier` derived from `edge`, so this is false while Edge is not yet published (current MLB/soccer/tennis Stage 1).
  - `match_overview` string, nullable: Natural-language pre-game preview of the matchup — form, context, and what to watch. Written before kickoff by a Search-backed overlay on every event sport (MLB, NFL, NCAAF, NBA, NCAAB, NHL, soccer, tennis); sport-shaped queries so tennis does not invent pitchers. The request path only reads the stored row. Null when the pre-kickoff job has not run or the fixture was not eligible.
  - `rationale` string[], nullable: Event-level factual pre-game matchup chips (injuries, recent form, lineup/availability news — sport-shaped). Written before kickoff; the request path only reads the stored row. Null when not generated.
  - `intelligence_updated_at` string, nullable: ISO-8601 UTC timestamp of the most recent change anywhere in this payload — the maximum of the per-bet `computed_at` values for predictive-framework sports. Because individual markets are only rewritten when they move, use the per-bet `computed_at` to reason about a specific bet rather than this event-level maximum.
  - `bets` BetIntelligence[]: One entry per priced bet token on the predictive intelligence surface. Outcomes of the same market sum to 1.
    - `bet_type` string, nullable: Canonical bet token, e.g. ML_HOME/ML_AWAY/ML_DRAW (soccer), ML_P1/ML_P2 (head-to-head sports), SPREAD_HOME/SPREAD_AWAY, OVER, UNDER.
    - `player_role` string, nullable: 'home'/'away' for team sports or 'p1'/'p2' for head-to-head sports. Null for match-level tokens (OVER, UNDER, ML_DRAW), which are not about either side.
    - `player_id` integer, nullable: Player ID when this bet is about an individual player; null for team bets and match-level tokens (OVER, UNDER, ML_DRAW).
    - `team_id` integer, nullable: Team ID when this bet is about a team; null for individual-player bets and match-level tokens (OVER, UNDER, ML_DRAW). A draw is not a bet on either team, so ML_DRAW carries no team_id — safe to sum exposure by team_id across bets without double-counting the draw.
    - `player_name` string, nullable: Display name of the player or team this bet is about; null for match-level tokens (OVER, UNDER, ML_DRAW). Duplicates `players[player_role].name` for convenience when flattening bets[].
    - `market` object, nullable: Market quote used for this bet: {price: American odds, line: handicap/total line or null for moneyline, book: bookmaker slug when known}. For predictive-framework sports `book` is always populated from the assessment; for legacy sports it may be omitted. Present for every sport.
    - `computed_at` string, nullable: ISO-8601 UTC timestamp of when this bet's numbers last materially changed — not when they were last checked. The publisher re-runs on a schedule but only rewrites a row when the price, line, or probability moves beyond a tolerance, so an older `computed_at` means 'unchanged since', not 'stale'. Values legitimately differ between bets on the same event because each market moves independently.
    - `tier` string, nullable: Recommendation tier: 'very_high', 'strong', 'moderate', or 'avoid'. Null whenever `edge` is null — a tier ranks a bet against its price.
    - `confidence_score` number, nullable: Not published. Use `probability`.
    - `confidence_score_pre_validator` number, nullable: Not published.
    - `coverage` number, nullable: Not published.
    - `signals` object, nullable: Not published.
    - `validator` object, nullable: Not published.
    - `narrative` string, nullable: Pick-defense rationale for a high-confidence main-line side — why THIS token hits, not a match preview or stat recap. Present only when Lumify made a pick on this token (`forecasts[]` row with `selected: true`, matching `bet_type`, and a research note). Null on the opposite side, on coin-flip markets, and when no pick was made.
    - `rationale` string[]: Not published. Event-level context chips live on the top-level `rationale` of IntelligenceResponse.
    - `attribution` string[]: Not published.
    - `probability` number, nullable: Published probability for this outcome, 0-1. Outcomes of the same market (e.g. ML_HOME + ML_DRAW + ML_AWAY) sum to 1. Present on the customer surface for MLB, soccer, and tennis.
    - `interval` number[], nullable: [lo, hi] band around `probability`, 0-1. Read it as 'how much evidence backs this number', not as a statistical confidence interval. A freshly-opened, unmoved line gets a wider band than a heavily-traded one. Thin evidence widens this band rather than removing the response. Present on the customer surface for MLB, soccer, and tennis.
    - `p_model` number, nullable: Internal — omitted from customer payloads (MLB/soccer/tennis). Fitted model probability before blending with the market.
    - `p_market` number, nullable: Internal — omitted from customer payloads (MLB/soccer/tennis). De-vigged market probability before blending; use `probability` / `fair_price` instead.
    - `blend_w` number, nullable: Internal — omitted from customer payloads (MLB/soccer/tennis). Weight on the model when blending with the market.
    - `fair_price` integer, nullable: American-odds fair price implied by `probability` — the vig-free line. Comparing it to `market.price` gives the bookmaker's margin on this side. Predictive-framework sports only.
    - `edge` number, nullable: Expected profit per 1 unit staked at `market.price`, i.e. `probability x decimal_odds - 1`. Positive means the price pays more than the probability justifies. Null when no model-backed edge is published (current MLB/soccer/tennis Stage 1). Present on the customer surface — null today, reserved for future recommend gating.
    - `sufficiency` number, nullable: Internal — omitted from customer payloads (MLB/soccer/tennis). Evidence strength 0-1 used internally to set interval width.
    - `phase` string, nullable: Internal — omitted from customer payloads (MLB/soccer/tennis). Pipeline stage (`quant` / `full`).
    - `model_version` string, nullable: Internal — omitted from customer payloads (MLB/soccer/tennis). Parameter-set identifier for traceability.
    - `drivers` object[]: Internal — omitted from customer payloads (MLB/soccer/tennis). Signed contributions to probability used in the assessment pipeline.
    - `alignment` object, nullable: Internal — omitted from customer payloads (MLB/soccer/tennis). Qualitative-overlay agreement detail.
    - `fair` object, nullable: Sharp-consensus fair price for this outcome: {probability, books, n_books, is_consensus}. `probability` is distinct from `p_market` (the *priced* book's own de-vigged probability) and from `fair_price` (American odds implied by the published `probability`, above) — it is the sharp-book reference a cross-book price gap is measured against (MLS: Pinnacle / `SOCCER_SHARP_BOOKS`; MLB: Pinnacle+Circa / `MLB_SHARP_BOOKS`). `is_consensus` is false whenever `n_books` < 2. Populated for MLS and MLB; null for other leagues until their market plane is wired. Predictive-framework sports only.
    - `edges_by_book` object, nullable: Price gap versus the sharp-reference fair probability (`fair.probability`), keyed by bookmaker — `fair.probability × decimal_odds − 1` at each book's posted price. A line-shopping metric: rank soft books by these gaps (largest gap = furthest above the sharp reference). Populated for MLS (retail soft books for Price — Edge archive stays FanDuel/Hard Rock) and MLB (retail soft books: DK/FD/BetMGM/Caesars/Bet365/Hard Rock/BetOnline — Price surface; Edge allowlist remains independence-cleared DK/FD only). Null for other leagues or markets with no soft quote. Predictive-framework sports only.
    - `best` object, nullable: Highest price-gap book across `edges_by_book`: {book, price, edge, quote_age_seconds}. Same metric as `edges_by_book`: price gap versus a de-vigged sharp reference. On MLB, `best_*` is Tier C / informational line-shopping even when the gap is positive (DK/FD ML and RL/totals are hard-null for Edge). Use `best.book`/`best.price` as the line-shopping target. `quote_age_seconds` is `best.book`'s posted-price age at publish — quotes older than 30 minutes are excluded. Populated for MLS and MLB; null otherwise or when `edges_by_book` is empty. Predictive-framework sports only.
    - `ev` object, nullable: **Beta.** Customer-facing expected-value estimate: {beta: true, book, price, ev_pct, kelly_fraction, quote_age_seconds, n_books}. `ev_pct` is the selected book's price gap × 100 (`fair.probability × decimal − 1`); `kelly_fraction` is the full-Kelly stake, capped at 1.0. Not a new measurement — re-packages the same sharp-fair price gap as `best`/`edges_by_book`. Main-line tokens (moneyline, spreads, totals; tennis totals unpublished). A single sharp book (n=1 Pinnacle) is a valid fair reference; soccer and tennis never have a two-book sharp consensus. Gaps ≤ 0 or above 25% (stale-line artifact) are dropped. When `best` is a suppressed MLB moneyline book (DraftKings/FanDuel proven null, or BetMGM/Bet365/BetOnline unscreened), the next eligible book in `edges_by_book` is used. Spreads/totals do not inherit that suppression. Unverified market-consensus estimate — see docs/internal/sports/PREDICTIVE_CLAIM_LADDER.md.
  - `forecasts` ForecastWager[]: Forecasted Over/Under player-prop wagers for this event from the same rate model as `GET /v1/intelligence/forecasts`. `selected` marks the top-conviction rows that also appear on the daily slate; the rest of the event catalog is included with `selected: false`. Empty when the sport is outside MLB / NFL / NCAAF / NBA / NCAAB / NHL / tennis, or no strictly-matched two-way main is in range (props) / no ranked two-way moneyline (tennis). Same wager object as the slate — see `ForecastWager`.
    - `event_id` integer, nullable: Lumify event ID. Present on the daily slate (`GET /v1/intelligence/forecasts`); omitted on `GET /v1/events/{id}/intelligence` `forecasts[]` (the event is the path).
    - `sport` string, nullable: Sport slug. Slate only.
    - `league` string, nullable: League slug, if any. Slate only.
    - `commence_time` string, nullable: ISO-8601 UTC scheduled start. Slate only.
    - `home_team` string, nullable: Home team display name. Slate only.
    - `away_team` string, nullable: Away team display name. Slate only.
    - `player` string, nullable: Player display name from the priced line. Null on main-line rows with no player attribution (`bet_type` is a match-level token like OVER/UNDER/ML_DRAW).
    - `player_id` integer, nullable: Lumify player ID. Bound by exact / Jr-stripped name match to the priced line. Null on main-line rows with no player attribution.
    - `bet_type` string, nullable: Main-line token when this row is a main-line forecast — `ML_P1`/`ML_P2`/`ML_HOME`/`ML_AWAY`/`ML_DRAW`, `SPREAD_P1`/`SPREAD_P2`/`SPREAD_HOME`/`SPREAD_AWAY`, or `OVER`/`UNDER` (same vocabulary as `bets[].bet_type` and `list_ev`). Null on player-prop rows — that's the discriminator between the two row shapes. Tennis sets `ML_P1`/`ML_P2` (moneyline, ranking Bradley-Terry), `SPREAD_P1`/`SPREAD_P2` (game handicap), and `OVER`/`UNDER` (total games — soft-book game-unit lines only, never Pinnacle's set-unit total). NFL / NCAAF / MLB / soccer set the same tokens from a high-confidence assessment lean (one side per market; coin flips are not emitted as picks).
    - `player_role` string, nullable: `home`/`away` for team sports or `p1`/`p2` for head-to-head sports, set only alongside a non-null `bet_type`. Null for player-prop rows and for match-level main-line tokens (OVER, UNDER, ML_DRAW).
    - `market` string, required: Player-prop rows: prop category — counting stats. MLB: strikeouts_pitcher, hits, rbis, runs, strikeouts_batter, hits_allowed, earned_runs, outs_recorded. NFL/NCAAF: passing_yards, rushing_yards, receiving_yards, receptions, passing_tds, rushing_tds, touchdowns (anytime-TD combo: rushing + receiving + defensive TDs), rush_rec_yards, pass_rush_yards. NBA/NCAAB: points, rebounds, assists, steals, blocks, threes_made. NHL: goals, hockey_assists, shots_on_goal. Main-line rows (when `bet_type` is set): the main-line family — `h2h`, `spreads`, or `totals`.
    - `line` number, nullable: Posted 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.
    - `side` string, nullable: Player-prop rows: `over` or `under` — the more likely side given the player's shrunken rate versus `line`. The model always picks one when the line is in range. Null on main-line rows — read the picked outcome from `bet_type` instead.
    - `p_hit` number, required: Model 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[], required: `[lo, hi]` stated band around `p_hit`. Wider when `sufficiency` is low (thin recent sample). A stated evidence band, not a statistical confidence interval.
    - `sufficiency` number, required: Evidence 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; this field tells you how much of `p_hit` is earned from this player's own boxes.
    - `reliability` string, required: Badge on this sport×market cell: `emerging`, `moderate`, `high`, or `informational`. v0 ships `emerging` for every wager; cells promote as a scored history accumulates.
    - `conviction` number, required: Board rank key on 0–1: |p_hit − 0.5| × 2 × sufficiency × research multiplier. A 0.76 call on a thin sample ranks below a 0.62 call on a long one. Highest conviction first on the daily slate.
    - `model_version` string, required: Scorer version, e.g. `forecast-v0`.
    - `selected` boolean, required: True when this wager is on the daily board (top conviction, up to 3 per event / 25 on the slate). On `GET /intelligence` the array includes both selected rows and the rest of the event catalog.
    - `books` object, required: American price for the picked outcome, keyed by bookmaker slug (e.g. `{draftkings: -453}`). Posted market price for the side/bet_type the model picked — use it to see what books are charging for that outcome.
    - `drivers` ForecastDriver[]: Signed contributions that moved `p_hit`. Read `input` as the measured rate/rating behind the pick and `effect` as how far it lifts (or lowers) the chosen outcome versus a baseline on the same line.
      - `id` string, required: Namespaced driver id. Player-prop rows: typically `player.l10_rate` — the recent-form counting-stat rate that fed the Poisson step (also `player.season_rate` when L10 is too thin). Main-line rows would use a different namespace (e.g. a rating or surface split) once a main-line forecast model ships.
      - `input` number, nullable: Measured rate/rating behind this driver, in the units native to the underlying model (e.g. 0.27 runs/game, 7.4 strikeouts/start for the prop rate model). This is λ before the Poisson vs the posted line on prop rows.
      - `effect` number, required: Signed shift in `p_hit` versus a baseline case on the same line, in probability units. Positive / `direction=up` means this driver lifts the chosen outcome. 0.0 on yardage markets (league means are diluted by backups).
      - `direction` string, required: `up` when `effect` > 0, `down` when `effect` < 0, `neutral` at zero.
    - `research` object, nullable: Optional Deep Research overlay when the background job has written a row for this wager — every wager on the daily board (`selected: true`), plus other high-probability wagers (`p_hit` ≥ 0.80) in the catalog: `{stance, conviction, note}`. `stance` is `validate` / `neutral` / `invalidate`. `note` is the wager-level why (the fact the model cannot see) — on a selected main-line row it is also copied to `bets[].narrative`. Validate / invalidate rows always carry a note. Validate nudges `p_hit` up by at most 0.03 and lifts conviction. Invalidate drops the wager from `forecasts[]` and the daily board — it is not a recommended pick. The chosen `side` stays the same. Null means read `p_hit` from the rate model alone — missing research is fail-open, not a 400.
  - `matchup` object, nullable: Not returned. Use `GET /v1/events/{id}/stats` for pitcher/lineup Data.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/lumify/apis/lumify-sports-intelligence-api.md) · [All operations](https://skmtc.dev/lumify/apis/lumify-sports-intelligence-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lumify/apis/lumify-sports-intelligence-api/revisions/f91ea41a2606?raw)
