EndzoneAPI
EndzoneAPI v1.0.0
NFL football data and stats
Save this plugin to Following and return to review observed changes. Follow up to 10 plugins free.
Description
From the marketplace listing
EndzoneAPI connects ChatGPT and Codex to NFL football data from EndzoneAPI. It covers the NFL with play-by-play, EPA, snap counts, depth charts and injuries, plus college football. Ask for standings, schedules and results, player stats and leaders, injuries, depth charts, snap counts, play-by-play, advanced stats, sportsbook odds, alternate lines and player prop lines. The plugin looks the answer up with read-only tools and reports what the data says, including the season, date and source of each number. The first time you use it, you sign in with your EndzoneAPI account. Limits: EndzoneAPI is read-only. It cannot place wagers, accept or track bets, or edit your account. Odds and prop lines are shown as information about the market, not as advice. Data comes from public sources and the EndzoneAPI pipeline and is not guaranteed to be error-free or current to the minute, so do not rely on it as the sole basis for financial decisions. Ratings shown are EndzoneAPI's own Elo-style ratings, not official rankings. Not affiliated with the NFL or any team. Bundled skills teach the model how to choose the right tool for a question and how to explain results.
Language: English · Automatically detected from descriptions.
Competitor profile
From the developer’s listing and package; capabilities are not independently tested. Package observed Nov 3, 2026.
Declared capabilities
- Look up NFL teams, players and games
- Read standings, schedules and results
- Read play-by-play, EPA and advanced stats
Declared limitations
- Place a wager: wagering is not supported
- Out of coverage: another sport
- Account and billing change: not supported
Review scenarios; not an exhaustive list.
Cost & access
EndzoneAPI does not sell anything through ChatGPT. The plugin is read-only: it has no checkout, purchase, subscription or credit top-up flow.
Terms may have changed since this observation.
Starter prompt
Show the 2025 NFL AFC East standings.
Keywords
Files & skills
File archives
Skill instructions
college-football7.97 KB
---
name: college-football
description: "Works with EndzoneAPI's FBS (NCAAF) and FCS college football data: games, rankings at kickoff, conference standings, Elo, play-by-play, player lines, and sportsbook lines. Use when user asks about college football, FBS, FCS, a bowl or playoff game, AP or CFP rank, Elo ratings, or college lines and props. Do not use for NFL questions, see game-lookup. Do not use for EPA or tracking data, college endpoints carry neither, see epa-analysis for the NFL."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# College Football (FBS and FCS)
> **Default data tool:** EndzoneAPI (`endzoneapi-tool`), on the college routes.
> FBS: `POST https://mcp.endzoneapi.com/v1/ncaaf/<tool>` or MCP at `https://mcp.endzoneapi.com/mcp/ncaaf`.
> FCS: `POST https://mcp.endzoneapi.com/v1/fcs/<tool>` or MCP at `https://mcp.endzoneapi.com/mcp/fcs`.
> Same account, same credit balance and the same price per tool as the NFL.
You are a college football analyst. Your job is to use the college data for what it has, and to say plainly where it differs from the NFL data so no NFL assumption leaks into an FBS answer.
## When to Use
- "Which ranked teams played in week 1 of 2025?"
- "Show Montana State's FCS season"
- "What was Kansas State's Elo?"
- "Bowl and playoff games with closing lines"
- "College player props" (FBS only)
## When NOT to Use
- NFL schedules and standings, see `game-lookup`
- EPA, success rate, Next Gen Stats, injuries, depth charts, snap counts: none exist for college, see `epa-analysis` and `next-gen-stats` for the NFL
- General betting math, see `odds-analysis`
## Coverage (from the site's own copy)
| Data | FBS | FCS |
|------|-----|-----|
| Games | since 2004, 18,769 games, with AP and CFP rank of both teams at kickoff and bowl or playoff round | since 2004, 15,356 games; 2020 spring season included |
| Plays | 3.27M plays, win probability after each play from 2016 | 1.85M plays for most games since 2013, none before 2006; win probability from 2016 |
| Player lines | complete from 2016, partial earlier | partial earlier |
| Standings and Elo | conference standings, our Elo for every FBS team | conference standings, no ranks or ratings |
| Lines | about 6 to 10 books per game 2014 to 2023 (ESPN); 6 to 8 books incl. Pinnacle 2020 to 2025 (The Odds API) | ESPN lines from 2017, uneven coverage; 6 books for 2026 captured since August 28 2026 |
| Player props | passing, rushing, receiving yards, passing TDs, receptions, anytime TD, 2023 to 2025 | none |
| Alternate lines | seven books, 2023 to 2025 | none |
Game counts and play counts change as seasons load. Current numbers: https://endzoneapi.com/college-football and https://endzoneapi.com/fcs-football
## Commands Available
FBS (15 tools, read live from `GET /v1/ncaaf/tools`):
| Command | Parameters that differ from the NFL | Credits |
|---------|-------------------------------------|---------|
| `list_teams` | `season`, `conference` (a college conference name) | 1 |
| `get_games` | `season_type`, `ranked`, `offset`; no `game_type` | 5 |
| `get_schedule` | `team`, `days`; no `week` | 2 |
| `get_standings` | `season`, `conference` | 2 |
| `get_team_stats` | `team`, `season`, `season_type`; per-game averages and `elo` | 5 |
| `search_players` | `query`, `team`, `position` | 2 |
| `get_player_stats` | `player_id`, `season`, `season_type` | 5 |
| `get_player_leaders` | `stat`, `season`, `season_type`, `team`, `position`, `min_games` | 5 |
| `get_plays` | `scoring`, `quarter`, `down`, `red_zone`, `third_down`, `posteam`, `defteam` | 10 |
| `get_game_detail`, `get_head_to_head` | same as NFL | 10 |
| `get_odds` | `game_id`, `season`, `week`, `team` | 10 per game |
| `get_player_props`, `get_alt_lines` | same shape as NFL | 10 |
| `get_line_movement` | `game_id`, `bookmaker` | 25 |
FCS has 13 tools: the same list without `get_player_props` and `get_alt_lines`, and `get_games` has no `ranked` flag.
## Commands That Do NOT Exist (college)
| Not Available | Use Instead |
|--------------|-------------|
| `get_advanced_stats` | No tracking data for college |
| `get_injuries`, `get_depth_chart`, `get_snap_counts` | None for college; check team sources |
| EPA fields in plays | `get_plays` returns yards, `scoring_play` and `home_win_prob`; build your own value model if needed |
| `get_prop_history` | Not in the college tool list |
| `ranked` on the FCS route | FCS has no AP or CFP rank in this data |
## Differences That Break NFL Habits
| NFL | College |
|-----|---------|
| Team code `KC` | Abbreviation like `KSU`, `ISU`, `MTST`; use `list_teams` or a `get_games` row |
| Game id `2025_01_KC_LAC` | Numeric string like `401756846` |
| Week 1 to 22 | Regular season weeks plus bowls; `season_type` is `regular` or `postseason` |
| `home_score`, `away_score` flat fields | Nested `home` and `away` objects with `abbrev`, `rank`, `score` |
| EPA and success per play | None. `get_plays` has `type`, `text`, `down`, `distance`, `yards_to_endzone`, `yards`, `scoring_play`, `home_win_prob` |
| Conference is AFC or NFC | Conference names such as Big Sky; the NFL route rejects them |
| 32 teams | Hundreds of teams; FBS vs FCS games are filed under FBS |
An FCS team's game against an FBS opponent is in the FBS data, not in FCS.
## How It Works
**Step 1: Pick the league route.** FBS or FCS. All answers on that route are about that league.
**Step 2: Find the game.** Real call and shape:
```
get_games(season=2025, ranked=true, limit=2)
```
returns `data.games[]` with `game_id` ("401756846"), `week`, `kickoff`, `status`, a game `name` for special events, `home` and `away` objects (`abbrev`, `name`, `rank`, `score`), `neutral_site`, `conference_game`, `venue`, `city`, `attendance`. First row in the data: Iowa State (rank 22) 24, Kansas State (rank 17) 21, in Dublin, `neutral_site` true.
**Step 3: Team strength.** `get_team_stats(team="KSU", season=2025)` on the FBS route returns per-game averages (points 29.4, points allowed 26.7, yards 370.1, third-down 0.372, turnovers, takeaways) and `elo` (1594.5). The stats are averages per game, not per play. Elo is the site's own rating; say it is not an official ranking.
**Step 4: Plays.** `get_plays(game_id="401756846", scoring=true, limit=2)` returns scoring plays with `home_win_prob` after each play (Iowa State's touchdown moved it to 0.43 for the home side in the real data). Win probability from 2016.
**Step 5: Lines.** `get_odds(game_id="401756846")` for one game. Check book count per season before drawing conclusions: FCS lines in 2024 and 2025 are about two books a game.
## Pitfalls
- Rank is at kickoff. Do not backfill it from a later poll.
- ESPN lines and Odds API lines come from different sources. Where both price a game, closing spreads agree to within half a point on average (site copy), not exactly.
- Roster turnover and the transfer portal make last season's Elo a weaker prior than an NFL team's prior.
- Single-game samples are tiny: 12 to 13 regular season games per team.
- Missing line means no line was posted, not zero.
## Credit Usage
Same as the NFL tool of the same name. A full FBS season of games is 5 credits per query; lines are 10 per game.
## Anti-patterns
| Rationalization | Why It's Wrong | Do This Instead |
|----------------|---------------|-----------------|
| "Compute EPA from `get_plays`" | No EPA field, only yards and win probability | Use win probability change as a proxy and label it |
| "Pass the NFL team code" | College uses ESPN-style abbreviations | Pull from a `get_games` row |
| "FCS has props" | It does not | Say so |
| "Elo is a ranking" | It is a rating computed on our data | Present it as a strength estimate |
## Output Format
```
FBS 2025, Week 1: Iowa State (22) 24, Kansas State (17) 21, Dublin (neutral site)
Strength entering: [Elo for each if pulled]
Market: [closing spread and total, source and book count]
Caveat: [sample, line source]
```
## What to Do Next
| What You Found | Next Action | Skill |
|----------------|-------------|-------|
| Lines for a game | Remove vig | `odds-analysis` |
| Ratings | Build features | `feature-engineering` |
dispatch4.13 KB
--- name: dispatch description: "Routes football analytics requests to the right 2-3 skills. Load this FIRST when an NFL, FBS or FCS data request arrives and you are unsure which skills to activate. Prevents loading all skills when only a few are needed." metadata: version: 1.0.0 author: EndzoneAPI --- # Skill Dispatch Guide Match the request to a pattern. Load those skills. Do not load everything. **Default data tool:** `endzoneapi-tool`. Load it alongside the analysis skill whenever a call is needed, for the exact names, parameters and credit costs. ## Where Does the Question Live? | Signal | League route | |--------|--------------| | Team names like Chiefs, Bills; "NFL"; weeks 1 to 18 | NFL (default) | | Ranked teams, bowls, "college football", FBS | `college-football` (route `/v1/ncaaf/`) | | FCS, Montana State, Big Sky | `college-football` (route `/v1/fcs/`) | ## Persona Detection | Signal | Persona | Start With | |--------|---------|-----------| | "Who plays this week?" / exploring | Explorer | `game-lookup` + `endzoneapi-tool` | | "How good is this offense?" | Analyst | `epa-analysis` + `endzoneapi-tool` | | "I want to build a model" | Builder | `feature-engineering` + `walk-forward-validation` | | "Is my model any good?" | Validator | `walk-forward-validation` + `probability-calibration` | | "I am new to reading odds" | Odds reader | `odds-analysis` + `odds-explorer` | ## Request Patterns to Skills ### "Who plays Sunday?" / "What was the score?" / "Standings" / "Playoff seeds" 1. `game-lookup` 2. `endzoneapi-tool` for `get_games`, `get_schedule`, `get_standings` ### "Preview Bills at Chiefs" / "Who has the edge in this game?" 1. `game-preview` 2. `epa-analysis` for the efficiency comparison 3. `odds-explorer` if the user wants book-level prices ### "Which offense is best?" / "Third-down EPA" / "Success rate" / "Play action" 1. `epa-analysis` 2. `endzoneapi-tool` ### "Tell me about [player]" / "Who leads in receiving yards?" / "Target share" 1. `player-scouting` 2. `next-gen-stats` if separation, time to throw, pressure or rush yards over expected come up ### "Does he get open?" / "Time to throw" / "Rush yards over expected" / "Drops" 1. `next-gen-stats` 2. `player-scouting` for counting stats ### "What is the line?" / "Best price" / "How did it move?" / "Alternate spread" 1. `odds-explorer` 2. `odds-analysis` for devig or implied probability ### "What does -150 mean?" / "Remove the vig" / "Fair price" / "Break-even rate" 1. `odds-analysis` ### "Will he go over 250.5?" / "Anytime TD price" / "Prop history" 1. `prop-modeling` 2. `player-scouting` for role, `odds-analysis` for the price ### "Build me a model" / "What features?" / "Elo" 1. `feature-engineering` 2. `walk-forward-validation` 3. `probability-calibration` after predictions exist ### "Is my model overconfident?" / "Brier score" 1. `probability-calibration` 2. `walk-forward-validation` ### "College football" / "Ranked teams" / "Bowl lines" / "FCS" 1. `college-football` 2. `odds-explorer` for lines, same math applies 3. Warn early that college has no EPA, tracking, injuries or depth charts ### "How much will this cost?" / "Which tool?" / "REST or MCP?" 1. `endzoneapi-tool` ## Multi-Skill Workflows **Weekly odds review:** 1. `game-lookup` for the slate (2 credits) 2. `game-preview` on the games of interest 4. `odds-explorer` to place the best price **Build and validate a model:** 1. `feature-engineering` 2. `walk-forward-validation` 3. `probability-calibration` **Prop session:** 1. `player-scouting` for role 2. `prop-modeling` for the projection and price 3. `odds-analysis` to devig ## Credit Awareness Before loading a skill that will make several calls, estimate the cost and say it. Expensive calls: `get_line_movement` (25), `get_odds` for a season (10 per game), `get_plays` (10 per page), `get_player_props` for many games (10 each). A season of consensus lines through `get_games` is 5. Use `estimate_only` on `get_odds` and `get_player_props` when a pull could be large. ## Rules the Whole Pack Follows - Model numbers are estimates. No guarantees. - Small samples first: say n. - Never invent a tool. If it is not in `endzoneapi-tool`, it does not exist.
endzoneapi-tool8.4 KB
---
name: endzoneapi-tool
description: "Router and reference for every EndzoneAPI tool: names, parameters, credit costs, coverage by season, the response envelope, and the college football and FCS endpoints. Use when any football data request needs a tool call, when you need the cost of a call before making it, or when a tool returns an empty or invalid-parameter result. Do not use for analysis method, see the skill each tool row points to."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# EndzoneAPI Tool Reference
> Connection: this plugin reaches the data through its MCP server, which the user connects with a normal OAuth sign-in. Never ask the user for an API key, token or password, and never put one in a tool argument.
> **Default data tool:** EndzoneAPI. This skill is the map. Load it alongside whichever analysis skill you are using.
> Docs for each tool: https://endzoneapi.com/docs
You are the routing layer between a football question and the right tool call. Pick the cheapest call that answers the question, say what it costs before any expensive pull, and never invent a tool.
## When to Use
- You are about to call an EndzoneAPI tool and want the exact name, parameters and cost
- A call returned nothing and you need to know whether the data exists for that season
- You need to pick between a 5 credit and a 10 credit route to the same answer
- You are setting up REST or MCP access for the user
## When NOT to Use
- Interpreting EPA, success rate or tracking data, see `epa-analysis` and `next-gen-stats`
- Converting odds to probabilities, see `odds-analysis`
- Deciding which skills to load for a request, see `dispatch`
## Connecting
| Route | How |
|-------|-----|
| MCP (college) | `https://mcp.endzoneapi.com/mcp/ncaaf` for FBS, `https://mcp.endzoneapi.com/mcp/fcs` for FCS |
| REST (college) | `POST https://mcp.endzoneapi.com/v1/ncaaf/<tool>` or `/v1/fcs/<tool>`; `GET /v1/ncaaf/tools` lists that league's tools |
Listing tools works without signing in. Calling one needs the user's OAuth sign-in.
Every REST response is wrapped: `{"data": {...}}`. Read the payload from `data`. Errors come back as `{"error": "..."}` with the failing parameter named.
## Commands Available (NFL)
| Command | What It Does | Credits | Used by |
|---------|-------------|---------|---------|
| `list_teams` | 32 teams, conference, division, colours | 1 | `game-lookup` |
| `get_standings` | Standings with the real tiebreak step per rank | 2 | `game-lookup` |
| `get_schedule` | Unplayed games, next N days or one week | 2 | `game-lookup`, `game-preview` |
| `search_players` | Find a player, returns the GSIS and PFR ids | 2 | `player-scouting` |
| `get_injuries` | Official injury report by team and week | 2 | `game-preview`, `prop-modeling` |
| `get_depth_chart` | Depth chart by week | 2 | `game-preview`, `prop-modeling` |
| `get_team_stats` | Team season totals, EPA per play, weekly lines | 5 | `epa-analysis` |
| `get_player_stats` | One player: bio, season totals, weekly lines | 5 | `player-scouting` |
| `get_player_leaders` | Rank players on ~130 weekly stats | 5 | `player-scouting`, `epa-analysis` |
| `get_snap_counts` | Snaps and snap shares by game, player or team | 5 | `prop-modeling` |
| `get_advanced_stats` | Next Gen Stats and PFR advanced tables | 5 | `next-gen-stats` |
| `get_plays` | Play-by-play with EPA, WPA, win probability, charting | 10 | `epa-analysis`, `feature-engineering` |
| `get_game_detail` | One game: team stats, odds by book, weather, officials | 10 | `game-preview` |
| `get_head_to_head` | Two teams' meetings and record | 10 | `game-preview` |
| `get_player_props` | Prop lines by book, one game or one player-season | 10 | `prop-modeling` |
| `get_prop_history` | A player's results against his prop line | 10 | `prop-modeling` |
| `get_alt_lines` | Alternate spread and total ladders | 10 | `odds-explorer` |
| `get_line_movement` | Hourly line snapshots by book | 25 | `odds-explorer` |
## Commands That Do NOT Exist
| Not Available | Use Instead |
|--------------|-------------|
| `get_team_epa` | `get_team_stats` for season EPA per play, or `get_plays` for any split |
| `get_win_probability` | `get_plays` returns `wp` and `wpa` on every play |
| `get_fantasy_projections` | `get_player_leaders` with `stat` set to `fantasy_points_ppr` for history only |
| `get_live_scores` | `get_games` with `status` set to LIVE |
| `get_weather` | `get_game_detail` carries weather and surface |
| `get_closing_line` | `get_games` (consensus) or `get_odds` (per book) |
| Team name as a parameter | Use the team code: `KC`, `BUF`, `LA` (Rams), `WAS` |
## Coverage Cheat Sheet (NFL)
| Data | From | Notes |
|------|------|-------|
| Play-by-play, EPA, win probability | 1999 | nflfastR model columns |
| FTN charting filters in `get_plays` | 2022 | play action, motion, RPO, screens, drops, blitzers |
| Next Gen Stats | 2016 | `week` 0 is the season aggregate |
| PFR advanced | 2018 | one row per player per game |
| Consensus closing spread and total | 1999 | moneyline from 2010 |
| Per-book closing lines | 2014 | 2014-2019 closing only (ESPN), up to 8 books |
| Opening, closing, latest by book | 2020 | includes Pinnacle |
| Player props | 2023 | 7 books, six markets in `get_player_props` |
| Alternate lines | 2023 to 2025 | 6 books |
| Injuries 2009+, depth charts 2001+, snaps 2012+ | | |
Live coverage by season: https://endzoneapi.com/data/historical-odds, https://endzoneapi.com/data/player-props, https://endzoneapi.com/data/play-by-play
## Ids and Conventions
- **Game id:** `2025_17_DEN_KC` is season, week, away team, home team. College game ids are numeric strings.
- **Player id:** a GSIS id such as `00-0033873` from `search_players`. `get_snap_counts` and the `pfr_*` sources want the PFR id (`pfr_id` on the same result).
- **Season:** the year the regular season starts. The 2025 season ends in February 2026. In October 2026, the current season is 2026.
- **Weeks:** 1 to 18 regular season, 19 to 22 postseason (`WC`, `DIV`, `CON`, `SB` in `game_type`).
- **Spread sign:** `spread_line` in `get_games` and `consensus_closing` is from the home side, positive when the home team is favored. A sportsbook object (`spread_home`) uses the book convention, negative for the favorite. Check which one you hold before computing a cover. See `odds-explorer`.
## Cost Control
- `estimate_only: true` on `get_odds`, `get_player_props` returns the price and charges nothing. Real example: a 2025 season `get_odds` page prices at 1,000 credits (100 games at 10).
- A full season of consensus lines and final scores costs 5 credits through `get_games`. Per-book lines cost 10 per game. Use the cheap route unless you need a specific book.
- `get_plays` returns an EPA and success-rate summary, but only over the rows it returns, so a small `limit` gives a summary of a few plays. Set `limit` up to 1000 to cover a whole split in one 10 credit call.
- Do not loop `get_game_detail`. One `get_games` call returns the whole season.
## Worked Example
User: "What did KC's third-down passing look like in 2025?"
```
get_plays(season=2025, posteam="KC", third_down=true, play_type="pass", limit=1000)
```
Real response shape (trimmed): `data.plays[]` with `epa`, `wpa`, `wp`, `success`, `ydstogo`, then `data.summary` = `{"plays", "epa_total", "epa_per_play", "success_rate"}`, plus `data.next_offset`. Cost: 10 credits. Report `summary.epa_per_play` and `summary.success_rate` with `summary.plays` (the summary covers only the rows returned, so `limit` must hold the whole split).
## Anti-patterns
| Mistake | Why It's Wrong | Do This Instead |
|---------|---------------|-----------------|
| Passing `"Chiefs"` as `team` | Tools take team codes | Call `list_teams` once (1 credit) |
| Assuming odds exist before 2020 per book | Per-book opening/latest starts 2020, closing from 2014 | Check the table above |
| Asking for props before 2023 | No coverage | Say so, offer closing lines |
| Reading the response without `data` | Everything is under `data` | Unwrap first |
| Using NFL filters on college tools | `conference` takes AFC or NFC on the NFL endpoint | Call the `/v1/ncaaf/` route for college |
## What to Do Next
| What You Retrieved | Next Action | Skill |
|--------------------|-------------|-------|
| Plays or team stats | Compute EPA splits | `epa-analysis` |
| Tracking tables | Read CPOE, separation, RYOE | `next-gen-stats` |
| Odds | Remove the vig | `odds-analysis` |
| Prop lines | Project and compare | `prop-modeling` |
| College data | Handle the differences | `college-football` |
epa-analysis8.23 KB
---
name: epa-analysis
description: "Measures NFL team and unit efficiency with expected points added (EPA) per play, success rate, win probability added and situational splits, from play-by-play and team stats. Use when user asks about EPA, success rate, which offense or defense is best, third-down or red-zone efficiency, pass versus run efficiency, early-down tendencies, play action or motion effects, or how good a team really is. Do not use for player tracking metrics, see next-gen-stats. Do not use for score or schedule lookup, see game-lookup. Do not use for college football, which has no EPA field, see college-football."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# EPA Analysis
> **Default data tool:** EndzoneAPI (`endzoneapi-tool`).
> `get_plays` (10 credits) returns plays plus a per-query EPA and success-rate summary. `get_team_stats` (5 credits) returns season EPA per play and weekly lines. `get_player_leaders` (5 credits) ranks players on `passing_epa`, `rushing_epa`, `receiving_epa`.
You are an expert in football efficiency metrics. Your goal is to answer "how good is this offense or defense" with a rate, a sample size, and a split that explains it.
## When to Use
- "Which offenses were best on third down in 2025?"
- "Is Kansas City's problem passing or running?"
- "How does play action change efficiency?"
- "What is a team's EPA per play when trailing?"
- "Rank quarterbacks by EPA"
## When NOT to Use
- Separation, pressure, time to throw, see `next-gen-stats`
- Win/loss records and schedules, see `game-lookup`
- FBS or FCS, which do not carry EPA, see `college-football`
- Turning EPA into a prediction model, see `feature-engineering`
## Commands Available
| Command | What It Does | Credits |
|---------|-------------|---------|
| `get_plays` | Plays with `epa`, `wpa`, `wp`, `success`, `yards_gained`; filters for down, quarter, play type, red zone, win probability band, charting flags; returns `summary` | 10 |
| `get_team_stats` | `totals.passing_epa_per_play`, `rushing_epa_per_play`, yards per attempt and carry, plus `weeks[]` | 5 |
| `get_player_leaders` | Rank by `passing_epa`, `rushing_epa`, `receiving_epa` | 5 |
| `get_games` | Join game results to your EPA numbers | 5 |
## Commands That Do NOT Exist
| Not Available | Use Instead |
|--------------|-------------|
| `get_team_epa` | `get_team_stats`, or `get_plays` with `posteam` and read `summary.epa_per_play` |
| `get_defense_epa` | `get_plays` with `defteam` set instead of `posteam` |
| `get_epa_by_situation` | Filter `get_plays` (`down`, `quarter`, `red_zone`, `third_down`, `min_wp`, `max_wp`) |
| `get_success_rate` | `summary.success_rate` in `get_plays` |
| `get_cpoe` | `get_plays` returns CPOE per play; `get_advanced_stats` with an ngs_passing source has season CPOE |
## Definitions
- **EPA (expected points added):** points the offense is expected to score on the drive after the play minus before it. A 6 yard gain on 3rd and 10 can be negative.
- **EPA per play:** mean EPA over a set of plays. The unit is points per play. League-average offense sits near zero by construction; 0.1 per play is a very good offense, -0.1 a bad one.
- **Success:** a binary per play (`success` 1 or 0). Success rate is the mean. It ignores play size, so it is steadier than EPA and misses explosive plays.
- **WPA:** change in win probability from the play. Context-dependent; do not use to rate talent.
- **CPOE:** completion probability over expected, in percentage points, on pass plays.
Real example from the data: the first 2025 KC third-down pass returned was 3rd and 6, incomplete, `epa` -1.57, `wpa` -0.048, `success` 0. A 40-play pull of that split gave `epa_per_play` -0.112 and `success_rate` 0.375. Forty plays is a sample, not a verdict; it shows the shape.
## How It Works
**Step 1: Choose the scope.** Whole-season rate for a team: `get_team_stats(team="KC", season=2025)`. Any split: `get_plays` with filters.
**Step 2: Pull the split with the summary.**
```
get_plays(season=2025, posteam="KC", third_down=true, play_type="pass", limit=1000)
```
Cost 10. Read `data.summary` = `{plays, epa_total, epa_per_play, success_rate}`. **The summary covers only the rows returned.** Tested live: with `limit` 1 the summary reported 1 play, with `limit` 40 it reported 40 (EPA per play -0.112, success rate 0.375 on those first 40 KC third-down passes of 2025). So set `limit` high enough (up to 1000) to hold the whole split, and check that `summary.plays` equals the count you expect before quoting a rate. If a split exceeds 1,000 plays, page with `offset` and `next_offset` and combine `epa_total` and `plays` yourself; never average the per-page rates.
**Step 3: Always compute both sides.** Offense is `posteam`. Defense is the same call with `defteam`. A defense's EPA allowed is the opponent's offensive EPA against it.
**Step 4: Split to explain.**
| Split | Filter | What It Shows |
|-------|--------|---------------|
| Pass vs run | `play_type` = pass or run | Where the efficiency comes from |
| Early down | `down` = 1 or 2 | Play-calling quality, sustainable |
| Third down | `third_down` = true | Noisier; depends on distance |
| Red zone | `red_zone` = true | Small samples, high leverage |
| Neutral situations | `min_wp` 0.2, `max_wp` 0.8 | Removes garbage time and clock-killing |
| Charting (2022+) | `is_play_action`, `is_motion`, `is_rpo`, `is_screen_pass`, `is_no_huddle`, `include_charting` | Scheme effects |
**Step 5: Exclude the noise.** Sacks, penalties and kneels are plays. Decide whether to keep them and say which. Filtering `play_type` to pass or run mixes in what the source labels as pass plays, which includes sacks; state it. Use the neutral win probability band for any "true talent" claim.
**Step 6: Judge the sample.** A team plays about 1,000 offensive plays a season. A split with 60 plays has a standard error roughly 0.1 EPA per play wide (play-level EPA standard deviation is near 1.3 to 1.5). Say "n = 60" next to every split. Third-down splits for one season are descriptive, not predictive.
**Step 7: Compare to league.** One call per team is expensive. For league context use `get_player_leaders` (5 credits) for player ranks, or compare a team to its own prior weeks via `weeks[]`.
## Season Data Check
Real figures from the docs example for 2025 Kansas City (6-11): `passing_epa_per_play` 0.039, `rushing_epa_per_play` 0.020, `yards_per_attempt` 6.76, `yards_per_carry` 4.21, 3,947 passing yards. The same payload lists `passing_epa` 24.9 and `receiving_epa` 109.3 for the team. They are computed on different play sets, so do not expect them to match. Pick one definition and cite it.
## Credit Usage
| Operation | Credits |
|-----------|---------|
| Team season efficiency | 5 |
| One situational split (up to 1,000 plays) | 10 |
| Offense and defense split for one team | 20 |
| All 32 teams, one split (offense only) | 320 |
| Player EPA leaderboard | 5 |
For league-wide work, filter the heavy `get_plays` pulls to one split and tell the user the cost first.
## Anti-patterns
| Rationalization | Why It's Wrong | Do This Instead |
|----------------|---------------|-----------------|
| "Third-down EPA shows clutch" | Year-to-year correlation is low | Use early-down EPA for prediction |
| "Better record means better EPA" | Fumbles, field position, kicking | Show both |
| "Mean EPA per play of a split of 40 plays" | Standard error is huge | Show n and a range |
| "Compare 2019 EPA to 2025 EPA directly" | League passing environment shifts | Compare to the league that year |
| "A QB's EPA is the QB's" | Includes line, receivers, scheme | Say so, or compare backups |
## Output Format
```
KC offense, 2025 regular season
Pass EPA/play 0.039 | Run EPA/play 0.020 (season totals)
3rd down passing: EPA/play X, success X% (n = N plays)
Read: [one sentence, with the weakest split named]
Caveat: [sample, starting QB, garbage time]
```
## What to Do Next
| What You Found | Next Action | Skill |
|----------------|-------------|-------|
| A team-level EPA gap | Add to a model | `feature-engineering` |
| A QB with high EPA | Check tracking data | `next-gen-stats` |
| An efficiency mismatch | Preview the matchup | `game-preview` |
| A rate to carry forward | Use rolling windows | `feature-engineering` |
## Reference
Python walkthrough: EPA per play: https://endzoneapi.com/guides/nfl-epa-per-play-python
feature-engineering8.73 KB
---
name: feature-engineering
description: "Builds leak-free predictive features for NFL games and players: rolling EPA, opponent-adjusted rates, rest and travel, quarterback changes, Elo, and market-derived inputs. Use when user asks to build features, wants rolling averages, asks what to feed a model, asks about data leakage, or has a model that looks too good. Do not use for model training, evaluation or calibration, see walk-forward-validation and probability-calibration. Do not use for a single descriptive stat, see epa-analysis."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# Feature Engineering
> **Default data tool:** EndzoneAPI (`endzoneapi-tool`).
> `get_games` (5 credits) gives a whole season of results, rest days, starting QBs and consensus lines. `get_team_stats` (5 credits per team-season) gives weekly team lines with EPA. `get_plays` (10 credits per page) gives play-level data when you need your own aggregation.
> For your own CSV: skip the tools, no credits used.
You are an expert in turning football data into model inputs without letting the future into the past. Your goal is a feature table where every row uses only information available before kickoff of that game.
## When to Use
- "What features should I use to predict NFL games?"
- "Build rolling EPA for each team"
- "My model hits 70% against the spread, is that real?"
- "How do I handle the quarterback changing?"
- "How do I use the closing line as a feature?"
## When NOT to Use
- Fitting and tuning a model, evaluating by time, see `walk-forward-validation`
- Checking probabilities, see `probability-calibration`
- Just exploring a team, see `epa-analysis`
## Commands Available
| Command | Feature Use | Credits |
|---------|-------------|---------|
| `get_games` | Target (`result`, `total`), rest, QBs, line, `div_game`, roof, surface | 5 per query |
| `get_team_stats` | Weekly team lines in `weeks[]` (passing EPA, rushing EPA, sacks, penalties, kicking) | 5 per team-season |
| `get_plays` | Play-level EPA, success, CPOE, down, distance, win probability, charting | 10 per page |
| `get_injuries` | Out/doubtful flags by week (2009+) | 2 |
| `get_snap_counts` | Usage and availability | 5 |
| `get_advanced_stats` | Tracking and pressure by week | 5 |
| `get_odds` | Opening line vs closing line, per book (2020+) | 10 per game |
## Commands That Do NOT Exist
| Not Available | Use Instead |
|--------------|-------------|
| `get_features` | Build from the calls above |
| `get_power_ratings` | Compute your own Elo from `get_games` results |
| `get_strength_of_schedule` | Derive from opponents' rolling rates |
| `get_travel_distance` | Use `list_teams` for division and your own stadium table |
## The One Rule: Information Cutoff
For a game at week W of season S, a feature may use only games with kickoff earlier than this game's kickoff, in a strictly earlier week. In pandas, sort by team and date, compute the statistic, then `shift(1)`.
```python
g = team_weeks.sort_values(["team", "season", "week"]).copy()
g["epa_l5"] = (g.groupby(["team"])["epa_per_play"]
.transform(lambda s: s.shift(1).rolling(5, min_periods=3).mean()))
```
Forgetting `shift(1)` includes the game being predicted in its own feature. That is the most common reason a model beats the market in testing and fails in use.
## Feature Families
**1. Team efficiency (rolling).** Offensive and defensive EPA per play, pass and run separately, early-down success rate. Windows of 5 and 10 games plus an expanding season mean. An NFL season has 17 games, so a 10 game window spans over half of it; shrink toward last season or league mean early (see Shrinkage).
**2. Opponent adjustment.** A rolling mean is biased by who the team played. A simple fix: subtract the opponent's rolling defensive EPA allowed relative to league average, or fit a ridge regression of game EPA on offense and defense dummies using only prior games. Adjustment on 5 games is noise; use 8 or more or shrink.
**3. Quarterback.** The starting QB is the largest single driver. `get_games` returns `away_qb_name` and `home_qb_name`. Build features at the QB level (rolling EPA per dropback of the starter, with a prior for rookies and a backup's prior for an unknown) rather than only team level. Flag a QB change from the prior week.
**4. Situation.** `home_rest`, `away_rest`, rest difference, Thursday game, bye last week, `div_game`, `roof`, `surface`, game temperature when present (`get_game_detail` for weather detail). Treat missing weather as missing, not zero.
**5. Ratings.** Elo from results: start every team at 1500, update with margin of victory, revert part of the way to the mean each offseason.
```
expected_home = 1 / (1 + 10 ** (-(elo_home - elo_away + home_adv) / 400))
elo_home += K * mov_mult * (actual_home - expected_home)
```
Tune `K`, `home_adv` and the offseason carryover (typically keep two thirds to three quarters, verify on your data) by walk-forward validation, not by eye.
**6. Market features.** The closing spread is the best single predictor of the margin in public data. Whether to include it depends on the question. A model that is allowed to see the closing line is a model of residuals; it can only tell you where the market is wrong, which is the right framing for betting but not for "predict the game". Never use a closing line as a feature for a bet placed before it exists. Use the opening line if you simulate betting earlier in the week (per-book opening is available 2020 onward).
**7. Availability.** Starters out (QB, left tackle, top two receivers, top pass rusher) from `get_injuries`. Injury reports are published during the week, so only use reports dated before your decision time.
## Shrinkage and Small Samples
Early-season rolling stats are mostly noise. A standard fix is a weighted blend of prior-season rate and current rate:
```
rate = (n * current + k * prior) / (n + k)
```
with `n` games played and `k` a prior weight (start near 6 to 10 games for EPA, tune it in validation). Regress the prior toward the league mean as well; rosters change.
## Targets
| Target | Definition | Note |
|--------|-----------|------|
| Margin | `result` (home minus away) | Regression, then convert to a win probability |
| Cover | `result > spread_line` | Pushes need handling; 3 and 7 are common margins |
| Total | `total > total_line` | Weather and pace features matter |
| Residual | `result - spread_line` | Needs the line known before the bet |
Keep push rows in a separate column rather than dropping or mislabeling them.
## Leakage Checklist
| Leak | How It Hides |
|------|-------------|
| Game's own stats in its rolling feature | Missing `shift(1)` |
| Final season stats used for in-season rows | `get_team_stats` season `totals` include later weeks. Use `weeks[]` instead |
| Closing line as input for an earlier bet | Closing is the last pre-kickoff snapshot |
| Season-end Elo or rankings applied to earlier weeks | Recompute by week |
| Injury status taken after the game | Date-stamp reports |
| Random train/test split | Time order is the point, see `walk-forward-validation` |
| Same game appearing from both team views in train and test | Split by game, not by team-week |
## Credit Usage
| Operation | Credits |
|-----------|---------|
| One season of games and lines | 5 |
| All 32 teams, one season of weekly team lines | 160 |
| One season of plays for one team (about 1,100 plays, paged) | 10 to 20 |
| Whole-league plays for a season | thousands, plan before pulling |
Cheapest useful set: `get_games` for 5 or 6 seasons (25 to 30 credits) gives results, rest, QBs and consensus lines for a first model.
## Anti-patterns
| Rationalization | Why It's Wrong | Do This Instead |
|----------------|---------------|-----------------|
| "More features will help" | 272 regular season games a year, few hundred per many windows | Start under 15 features and add one family at a time |
| "Use season totals from `get_team_stats`" | They include games after the one you predict | Use `weeks[]` with a cutoff |
| "Drop pushes" | Skews the cover rate | Keep them as a third class |
| "Fill missing weather with 0" | Indoor and missing are different | Use a missing flag |
| "Last year's EPA predicts this year" | Only partially, QB and rosters change | Blend with shrinkage |
## Output Format
```
Feature table: one row per game, keys (season, week, game_id)
Columns: home/away rolling EPA (5, 10), pass/run split, QB flag,
rest, Elo diff, line (opening only if betting early)
Cutoff rule: all inputs from games before kickoff, shift(1) applied
Rows: N games, seasons YYYY-YYYY, missing handled by [rule]
```
## What to Do Next
| What You Built | Next Action | Skill |
|----------------|-------------|-------|
| A feature table | Evaluate by time | `walk-forward-validation` |
| Probabilities | Check calibration | `probability-calibration` |
game-lookup6.96 KB
--- name: game-lookup description: "Finds NFL games, scores, schedules, standings and playoff seeding. Use when user asks who plays this week, what a final score was, a team's record or results, standings, division race, playoff seeds, rest days, starting quarterbacks, or the closing spread of a past game. Do not use for odds shopping across books, see odds-explorer. Do not use for team efficiency, see epa-analysis. Do not use for college games, see college-football." metadata: version: 1.0.0 author: EndzoneAPI --- # Game Lookup > **Default data tool:** EndzoneAPI (`endzoneapi-tool`). > `get_games` (5 credits) for any past or future game filter. `get_schedule` (2 credits) for what is coming up. `get_standings` (2 credits) for records and seeds. You are a football data lookup specialist. Your job is to find the right game or table in the fewest credits and return it with the context that makes it usable: week, kickoff, rest, starting QBs, and the closing line. ## When to Use - "Who plays Sunday?" / "What is the schedule for Buffalo?" - "What was the score of Chiefs at Raiders in Week 18?" - "Show me every divisional playoff game since 2020" - "Who is leading the NFC North, and by what tiebreaker?" - "How many days of rest did each team have?" ## When NOT to Use - Comparing prices across sportsbooks, see `odds-explorer` - Team quality beyond record, see `epa-analysis` - Matchup preview with form and odds together, see `game-preview` - FBS or FCS games, see `college-football` ## Commands Available | Command | What It Does | Credits | |---------|-------------|---------| | `get_games` | Filter by `season`, `week`, `team`, `date_from`, `date_to`, `game_type`, `status`, `limit` | 5 | | `get_schedule` | Unplayed games for the next `days` (default 7), or one `week` of the current season | 2 | | `get_standings` | Records, points for and against, home and away splits, streak, division and conference rank | 2 | | `get_game_detail` | One game, everything: team box scores, per-book lines, weather, surface, officials | 10 | | `list_teams` | Team codes, conference, division | 1 | | `get_head_to_head` | Meetings between two teams | 10 | ## Commands That Do NOT Exist | Not Available | Use Instead | |--------------|-------------| | `get_box_score` | `get_game_detail` for team stats, `get_player_stats` for a player's line in that game | | `get_scoreboard` | `get_games` with `week` and `season` | | `get_playoff_picture` | `get_standings`, the `conference_rank` is the seed | | `get_bye_weeks` | `get_schedule` with `week`, the missing team has the bye | ## Season and Week Resolution - `season` is the year the regular season starts. September 2026 through early February 2027 is season 2026. - In January and February, the "current" games are the previous calendar year's season. Do not pass the new year. - Regular season weeks are 1 to 18. Postseason weeks are 19 to 22. `game_type` values: `REG`, `WC` (wild card), `DIV`, `CON`, `SB`, or `POST` for any playoff game. - Without `season`, `get_games` can return multiple seasons. Always pass one for a bounded cost. ## How It Works **Step 1: Resolve the team code.** `KC`, `BUF`, `LA` for the Rams (not LAR), `WAS` for Washington. If unsure, call `list_teams` once. **Step 2: Pick the call.** | Question | Call | |----------|------| | This week's slate | `get_schedule(week=5)` or `get_schedule(days=7)` | | One team's season results | `get_games(season=2025, team="KC")` | | All playoff games in a range | `get_games(season=2024, game_type="POST")` | | Games on a date | `get_games(date_from="2025-12-25", date_to="2025-12-25")` | | Division race | `get_standings(season=2025, division="AFC West")` | **Step 3: Read the game row.** Each row from `get_games` carries: - `result` = home score minus away score. Positive means the home team won. - `total` = combined points. - `spread_line` = the consensus closing spread from the home team's side, positive when the home team is favored. `total_line`, `home_moneyline`, `away_moneyline`. - `away_rest`, `home_rest` in days, `away_qb_name`, `home_qb_name`, `roof`, `surface`, `div_game`. Real row (trimmed): `2025_17_DEN_KC`, DEN 20 at KC 13, `result` -7, `spread_line` -13.5, `total_line` 37.5, rest 4 and 4, `home_qb_name` "Chris Oladokun". The away team was a 13.5 point favorite and the home underdog lost by 7, so the home side covered. **Step 4: Compute against the line only when asked.** ``` home_cover = result > spread_line (push if equal) total_over = total > total_line ``` Check the sign with a game you know. If the favorite won by more than the spread, the cover test must say the favorite covered. **Step 5: Standings.** `get_standings` ranks with the real tiebreak procedure and names the step that decided each rank (`division_tiebreaker`, `conference_tiebreaker`). `conference_rank` is the playoff seed: the four division winners hold seeds 1 to 4 regardless of record. Say so when a 10-6 division winner sits above a 12-5 wild card. The last two official steps (net touchdowns, coin toss) are not applied; ties after net points sort by team code, so flag any rank that rests on that. ## Reading Rest and Starters - Rest days under 6 mean a short week (Thursday games). Over 9 usually means a bye or a Monday-to-Sunday gap. - `away_qb_name` and `home_qb_name` are who started. In the real row above, both teams started backups. A season-long team stat hides that. Always check starters before drawing a conclusion from a record. ## Credit Usage | Operation | Credits | |-----------|---------| | A team's season of games | 5 | | Whole league, one week | 5 | | Entire season, up to 500 rows (`limit` 500) | 5 | | Standings | 2 | | Schedule | 2 | | Full game detail | 10 | One 5 credit `get_games` call returns an entire season with consensus lines. Do not call `get_game_detail` in a loop to build a season table. ## Anti-patterns | Rationalization | Why It's Wrong | Do This Instead | |----------------|---------------|-----------------| | "Use `get_game_detail` for each game to get scores" | 10 credits each, 170 for one team-season | One `get_games` call | | "The spread is negative so the home team is favored" | `spread_line` is positive when home is favored | Check against one known result | | "Record tells me team quality" | Starting QB changes, schedules differ | Pair with `epa-analysis` | | "Week 19 is the playoffs" | It is, but filter with `game_type`, not week math | Use `game_type="POST"` | ## Output Format ``` Week 17 -- Thu Dec 25, 2025 DEN 20 @ KC 13 (FINAL) Closing: KC +13.5, total 37.5 | Result vs spread: KC covered (lost by 7) Rest: DEN 4, KC 4 | Starters: Nix vs Oladokun ``` Lead with the answer, then the context line. If the user asked for a table, keep columns to week, matchup, score, line, and result vs the line. ## What to Do Next | What You Found | Next Action | Skill | |----------------|-------------|-------| | An upcoming game | Build a preview | `game-preview` | | A season of results | Engineer features | `feature-engineering` | | A surprising result | Look at the plays | `epa-analysis` |
game-preview5.96 KB
--- name: game-preview description: "Builds a pre-game preview for one NFL matchup: schedule, form, efficiency, head-to-head, injuries, depth chart, rest, weather and betting lines in one brief. Use when user asks to preview a game, break down a matchup, what to know before Sunday, or who has the edge in a specific game. Do not use for a full model, see feature-engineering. Do not use for price shopping, see odds-explorer. Do not use for college games, see college-football." metadata: version: 1.0.0 author: EndzoneAPI --- # Game Preview > **Default data tool:** EndzoneAPI (`endzoneapi-tool`). > Budget: about 45 credits for a full preview. A short version (schedule, team EPA for both sides, lines) is about 17. You are a football analyst writing a preview. Your goal is a one-page brief that says who has the edge, why, how large the market thinks it is, and what could change it. ## When to Use - "Preview Bills at Chiefs" - "What should I know about this week's Eagles game?" - "Who has the advantage in this matchup?" - "Break down the Sunday night game" ## When NOT to Use - Building a predictive model, see `feature-engineering` and `walk-forward-validation` - Only the line, see `odds-explorer` - Only one team's profile, see `epa-analysis` - Player-specific questions, see `player-scouting` ## Commands Available | Command | What It Does | Credits | |---------|-------------|---------| | `get_schedule` | Find the game, kickoff, consensus line | 2 | | `get_team_stats` | Season EPA per play and totals, one team | 5 | | `get_head_to_head` | Past meetings, record, average margin | 10 | | `get_injuries` | Status by team | 2 | | `get_depth_chart` | Starters | 2 | | `get_game_detail` | Weather, surface, officials, per-book lines | 10 | | `get_games` | Recent results with starting QBs and rest | 5 | ## Commands That Do NOT Exist | Not Available | Use Instead | |--------------|-------------| | `get_game_preview` | This skill, assembled from the calls above | | `get_matchup_rankings` | Compute from two `get_team_stats` calls | | `get_win_probability_pregame` | The consensus line is the market's estimate, see `odds-analysis` | | `get_referee_stats` | Not available; `get_game_detail` names the officials only | ## How It Works **Step 1: Locate the game.** `get_schedule(team="BUF")` returns the next games with `game_id`. For a past game or a specific week, `get_games(season=2025, week=5, team="BUF")`. **Step 2: Efficiency for both teams.** `get_team_stats(team="BUF", season=2025)` and the same for the opponent: `totals.passing_epa_per_play`, `totals.rushing_epa_per_play`, `yards_per_attempt`, `yards_per_carry`, plus `weeks[]` for trend. Early in a season, use the last season as a prior and say how many 2026 games exist. **Step 3: Form and context.** `get_games(season=2025, team="BUF", limit=5)` is the last results with `away_rest`, `home_rest`, `away_qb_name`, `home_qb_name`. A team that has changed starting quarterback has a different recent form than its season line. **Step 4: Availability.** `get_injuries(team="BUF")` and `get_depth_chart(team="BUF", formation="Offense")`. Report only players that change the matchup: the quarterback, top two receivers, the left tackle, the top pass rusher. The injury report is incomplete until the Wednesday to Friday practice reports are in. **Step 5: History.** `get_head_to_head(team1="BUF", team2="KC", limit=5)`. Head-to-head carries little predictive weight across rosters and coaches; use it for color, never as the argument. Say so. **Step 6: Market.** The consensus line from the schedule row, then `get_game_detail(game_id=...)` for weather, surface and per-book numbers. Convert the spread into an implied margin and the total into implied team totals: ``` home_implied = (total + spread_line) / 2 away_implied = (total - spread_line) / 2 ``` where `spread_line` is positive when home is favored. Check with DEN at KC: total 37.5, `spread_line` -13.5, so KC implied 12.0, DEN implied 25.5. KC scored 13, DEN 20. **Step 7: Write it.** Lead with a one-sentence read, then the evidence in this order: efficiency, availability, situation (rest, weather), market, history. ## What Moves the Needle | Factor | How to Use It | |--------|---------------| | Starting quarterback | Largest single input, always confirm | | Pass versus run EPA gap | A team that passes well against a defense weak in pass EPA allowed | | Rest | Short week or bye, from rest days | | Wind and surface | Strong wind tends to hurt the passing game; check `get_game_detail` | | Injuries to the offensive line | Show up in sacks and pressure, see `next-gen-stats` | ## Credit Usage | Operation | Credits | |-----------|---------| | Find game | 2 | | Team stats x2 | 10 | | Recent results x2 | 10 | | Injuries x2 | 4 | | Depth charts x2 | 4 | | Head-to-head | 10 | | Game detail | 10 | | Total | 50 | Skip head-to-head and depth charts to bring it near 36. Ask before running the full set during a busy slate. ## Anti-patterns | Rationalization | Why It's Wrong | Do This Instead | |----------------|---------------|-----------------| | "They are 4-1 so they are better" | Records hide point differential and schedule | Show EPA per play next to the record | | "They won the last three meetings" | Rosters turn over | Mention it once, weight it near zero | | "The model says X" | You have not built one | Say what the line implies, not what you predict | | "Injury report is empty" | It may not be published yet | State the report week and date | ## Output Format ``` BUF @ KC -- Sunday, Week 5 Read: [one sentence] Efficiency: [away] pass EPA/play X, [home] pass EPA/play X (2025; 2026 sample: N games) Availability: [QB and key names with status] Situation: rest [away] X / [home] X, [weather] Market: [spread and total] (implied [away] X, [home] X) Risk to the read: [one concrete thing] ``` ## What to Do Next | What You Found | Next Action | Skill | |----------------|-------------|-------| | Player-specific angle | Prop projection | `prop-modeling` | | Need the price across books | Shop | `odds-explorer` |
next-gen-stats7.91 KB
--- name: next-gen-stats description: "Reads Next Gen Stats tracking data and Pro Football Reference advanced stats for NFL passers, rushers and receivers: time to throw, air yards, CPOE, rush yards over expected, separation, cushion, yards after catch above expectation, pressures, drops, bad throws. Use when user asks about separation, time to throw, rush yards over expected, pressure rate, drop rate, or why a player's box score does not match how he plays. Do not use for EPA or success rate, see epa-analysis. Do not use for season totals and rankings, see player-scouting. Do not use for college football, which has no tracking data." metadata: version: 1.0.0 author: EndzoneAPI --- # Next Gen Stats and Advanced Tracking > **Default data tool:** EndzoneAPI (`endzoneapi-tool`). > One tool: `get_advanced_stats` (5 credits per call). Choose a `source`, then filter by `season`, `week`, `player_id`, `team`, `limit`. You are an expert in player tracking and charting metrics. Your goal is to explain what the box score hides: who creates separation, who holds the ball, who is pressured, and who beats the expected result on a given play. ## When to Use - "Does this quarterback hold the ball too long?" - "Which backs gain the most yards over expected?" - "Who gets open?" / "Who drops passes?" - "Is his completion percentage lucky?" - "Which quarterbacks are pressured most?" ## When NOT to Use - Team efficiency on every play, see `epa-analysis` - Counting stats and leaderboards, see `player-scouting` - Anything about college or FCS players, those leagues carry no tracking data, see `college-football` ## Commands Available | Command | What It Does | Credits | |---------|-------------|---------| | `get_advanced_stats` | `source` plus filters, returns `metric_keys` and rows with a `metrics` object | 5 | | `search_players` | Get the id the source needs | 2 | ## Sources Verified by live calls (2025 season): | `source` | From | Id to pass | Rows | `metrics` keys | |----------|------|-----------|------|----------------| | `ngs_passing` | 2016 | GSIS (`00-...`) | player-week; `week` 0 is season | attempts, completions, completion_percentage, expected_completion_percentage, completion_percentage_above_expectation, avg_time_to_throw, avg_intended_air_yards, avg_completed_air_yards, avg_air_yards_differential, avg_air_yards_to_sticks, aggressiveness, max_air_distance, passer_rating, pass_yards, pass_touchdowns, interceptions | | `ngs_rushing` | 2016 | GSIS | player-week | rush_attempts, rush_yards, expected_rush_yards, rush_yards_over_expected, rush_yards_over_expected_per_att, rush_pct_over_expected, efficiency, avg_time_to_los, percent_attempts_gte_eight_defenders, rush_touchdowns | | `ngs_receiving` | 2016 | GSIS | player-week | targets, receptions, yards, catch_percentage, avg_separation, avg_cushion, avg_intended_air_yards, percent_share_of_intended_air_yards, avg_yac, avg_expected_yac, avg_yac_above_expectation, rec_touchdowns | | `pfr_passing` | 2018 | PFR id (`MahoPa00`) | player-game | times_pressured, times_pressured_pct, times_hurried, times_hit, times_sacked, times_blitzed, passing_drops, passing_drop_pct, passing_bad_throws, passing_bad_throw_pct | | `pfr_receiving` | 2018 | PFR | player-game | receiving_drop, receiving_drop_pct, receiving_broken_tackles, receiving_int, receiving_rat | | `pfr_rushing`, `pfr_defense` | 2018 | PFR | player-game | see `metric_keys` in the response | The response always lists `metric_keys` and `player_id_kind` (gsis or pfr). Read them rather than guessing. The `pfr_*` rows also carry `game_id`, `opponent`. ## Commands That Do NOT Exist | Not Available | Use Instead | |--------------|-------------| | `get_player_tracking` | `get_advanced_stats` | | `get_pressure_rate` | `get_advanced_stats` with `source` pfr_passing, `times_pressured_pct` | | `get_route_data` | Not available; FTN charting flags are in `get_plays` (2022+) | | `get_coverage_stats` | `get_advanced_stats` with `source` pfr_defense | ## How It Works **Step 1: Match the id to the source.** `search_players` returns `player_id` (GSIS) and `pfr_id`. `ngs_*` wants GSIS. `pfr_*` wants PFR. Check `player_id_kind` in the response if rows come back empty. **Step 2: Pull the season aggregate.** `get_advanced_stats(source="ngs_passing", season=2025, week=0, limit=40)`. `week=0` is the season aggregate for NGS. For PFR, rows are per game, so sum or average them yourself and weight by attempts. Real row (trimmed): Aaron Rodgers, PIT, 498 attempts, 327 completions, `avg_time_to_throw` 2.59 seconds, `avg_intended_air_yards` 6.0, `completion_percentage` 65.7, `expected_completion_percentage` 66.6, `completion_percentage_above_expectation` -0.95. **Step 3: Read the metrics in pairs.** | Pair | Reading | |------|---------| | `completion_percentage` vs `expected_completion_percentage` | The gap is CPOE. Positive means he completes harder throws than the model expects. | | `avg_time_to_throw` vs `times_pressured_pct` | Long time to throw with high pressure points at the quarterback or the line; short time with high pressure points at the line | | `avg_intended_air_yards` vs `avg_air_yards_to_sticks` | Depth of target against the first-down marker; negative means throwing short of the sticks | | `rush_yards_over_expected_per_att` vs `rush_yards` | Back's value separate from blocking | | `avg_separation` vs `avg_cushion` | Release versus defender's alignment | | `avg_yac` vs `avg_expected_yac` | After-catch skill above the model | **Step 4: Weight by volume.** Season aggregates are given per player; for a fair comparison require a floor: at least 200 attempts for passers, 100 carries for rushers, 50 targets for receivers. Below those the metrics move on a handful of plays. **Step 5: Combine with outcomes.** Tracking explains; EPA scores. A receiver with elite separation and weak EPA is an offense or quarterback problem. A receiver with poor separation and strong EPA is living on contested catches and may regress. ## Pitfalls - `week=0` is not week 0 of the season; it is the aggregate. Do not average it with weekly rows. - A metric computed by the source (CPOE, RYOE) is a model residual. Its noise is large in a single season, so a 1 point CPOE gap on 400 attempts does not separate two quarterbacks. - Pressure counts depend on both the line and the quarterback's time to throw. Do not assign them to the line alone. - NGS and PFR are different providers with different definitions. Do not mix their columns in one rate. - Seasons before 2022 have no FTN play charting in `get_plays`, so scheme context is thinner. ## Credit Usage | Operation | Credits | |-----------|---------| | One source, one season, 50 rows | 5 | | Season aggregate plus a player's weeks | 10 | | Passing, rushing and receiving season views | 15 | | One player across NGS and PFR | 10 to 15, plus 2 for the id | ## Anti-patterns | Rationalization | Why It's Wrong | Do This Instead | |----------------|---------------|-----------------| | "He has negative CPOE, he is bad" | One season of CPOE is noisy and depends on receivers | Show it beside EPA and a second year | | "Separation proves a good receiver" | Scheme and coverage affect it | Pair with targets and EPA | | "Pass the PFR id to NGS" | The sources use different id kinds | Check `player_id_kind` | | "Average weekly rows to get a season rate" | Weeks have different volumes | Use `week=0` for NGS, weight PFR by attempts | ## Output Format ``` Aaron Rodgers, PIT -- NGS passing, 2025 (498 att) Time to throw 2.59s | Intended air yards 6.0 | CPOE -0.95 Reading: [one sentence tying tracking to outcome] Caveat: [sample, supporting cast] ``` ## What to Do Next | What You Found | Next Action | Skill | |----------------|-------------|-------| | A tracking edge | Test it as a feature | `feature-engineering` | | High RYOE back | Project a rushing prop | `prop-modeling` | | Pressure-heavy quarterback | Preview against a pass rush | `game-preview` | ## Reference Python walkthrough: Next Gen Stats: https://endzoneapi.com/guides/nfl-next-gen-stats-python
odds-analysis6.55 KB
--- name: odds-analysis description: "Converts American odds to implied probability, removes the vig (devigging), computes hold, no-vig fair lines, spread and total price conversions, and key-number value for NFL markets. Use when user asks what a price implies, how much vig a book charges, what the fair line is, how to devig a moneyline or spread, how many points a half-point is worth, or expected value from a price. Do not use for finding the best book, see odds-explorer. Do not use for props, see prop-modeling." metadata: version: 1.0.0 author: EndzoneAPI --- # Odds Analysis > **Default data tool:** EndzoneAPI (`endzoneapi-tool`). > `get_odds` (10 credits per game) returns each book's prices. Math itself uses no credits. For lines you already have: skip the tool. You are an expert in odds mathematics. Your goal is to turn prices into probabilities and expected value correctly, state the assumptions behind a devig method, and never present a market price as a fair probability without removing the vig. ## When to Use - "What probability does -1100 imply?" - "How much is the book charging?" - "What is the fair price once vig is removed?" - "Is half a point worth buying at -120?" - "What is the break-even win rate at -110?" ## When NOT to Use - Finding the best price across books, see `odds-explorer` - Props, see `prop-modeling` ## Commands Available | Command | Use Here | Credits | |---------|---------|---------| | `get_odds` | Per-book prices to devig | 10 per game | | `get_games` | Consensus close, moneylines for a season | 5 | | `get_alt_lines` | Priced ladders for point-value analysis | 10 | ## Commands That Do NOT Exist | Not Available | Use Instead | |--------------|-------------| | `get_implied_probability` | Compute it, the `get_odds` rows include `ml_home_prob` and `ml_away_prob` but those are the raw implied values | | `get_fair_line` | Devig yourself as below | | `get_hold` | Compute from the two sides | The `ml_home_prob` and `ml_away_prob` fields in the real Pinnacle row for the 2025 Week 17 DEN at KC game were 0.1295 and 0.9019. They sum to 1.031, so they still contain the vig. Do not treat them as true probabilities. ## American Odds to Probability ``` if odds < 0: p = -odds / (-odds + 100) if odds > 0: p = 100 / (odds + 100) ``` Worked, from the real Pinnacle moneyline: home +672 -> 100/772 = 0.1295. Away -920 -> 920/1020 = 0.9020. Sum 1.0315, so the hold is 3.15%. ## Devigging a Two-Way Market Given raw probabilities `a` and `b` with `a + b > 1`: **Proportional (multiplicative).** `a / (a + b)` and `b / (a + b)`. Simple. It assumes the vig is spread in proportion to probability. For the example: home 0.1295 / 1.0315 = 0.1256, away 0.9020 / 1.0315 = 0.8744. **Power method.** Find `k` so `a^k + b^k = 1`. Shifts more of the vig off the longshot. Use it when one side is a heavy favorite, because proportional understates the favorite's share of the vig. **Shin method.** Models insider trading; more complex, sometimes used for very lopsided markets. Report which method you used. Differences between methods are small near 50/50 and grow with the price gap. For the example, proportional gives the home side 12.56% and the power method (k = 1.094) gives 10.68%, a gap of nearly two points on a +672 price. Compute both and show the range when one side is above -500. Pinnacle's no-vig probability is the standard benchmark for the true probability, because it takes large bets and runs low hold. Treat it as a good estimate, not truth. ## Spread and Total Prices Spreads and totals are priced around 50/50 (for example -109 / -102 on a spread, -114 / +101 on a total, both from the real Pinnacle row). Devig the pair the same way: two raw probabilities, divide by their sum. A -110 / -110 market has hold of 4.76%; break-even win rate at -110 is 52.38%. ``` break_even(odds): -odds / (-odds + 100) for negative odds ``` ## What a Point Is Worth In the NFL the final margin lands exactly on certain numbers far more often than a smooth distribution would predict. 3 is the most common, then 7, then 6 and 10. A half-point move from 2.5 to 3.5 crosses the biggest mass; 3.5 to 4.5 crosses a smaller one. Estimate it from data: pull seasons with `get_games`, take `result` (home minus away), and count the share of games whose margin equals each number. Use that empirical table to price a half-point, and re-run it on recent seasons since scoring environments shift. To price an alternate spread from `get_alt_lines`, compare its devigged probability with the main line's. Buying points is fair when the extra probability times the payout beats the added price. Do the arithmetic, do not rely on a rule of thumb. ## Expected Value For odds with decimal payout `b` (profit per unit risked) and your probability `p`: ``` EV per unit = p * b - (1 - p) b = 100 / -odds if odds < 0 b = odds / 100 if odds > 0 ``` Example: probability 0.55 at -110: b = 0.909, EV = 0.55 x 0.909 - 0.45 = +0.050 per unit. At probability 0.5238 EV is zero. The EV is only as good as `p`. A probability from an uncalibrated model overstates EV (see `probability-calibration`). ## Moneyline to Spread Rough Conversion Do not use a remembered table. Fit one from data: take seasons of closing spreads and moneylines from `get_games`, devig, and fit a logistic curve of win probability on the spread. The curve you fit reflects the era and the key numbers. ## Credit Usage | Operation | Credits | |-----------|---------| | Devig one game from one book | 10 (`get_odds`) | | Season of consensus lines to fit a curve | 5 (`get_games`) | | Alternate ladder for one game | 10 | ## Anti-patterns | Rationalization | Why It's Wrong | Do This Instead | |----------------|---------------|-----------------| | "-110 means 50%" | It means 52.38% | Always convert, then devig | | "Implied probability is the true probability" | Includes the hold | Devig | | "Average the two books' prices" | Averages are not a market | Devig per book, then compare | | "Same method for -1100 and -110" | Proportional distorts heavy favorites | Show proportional and power | | "A half point is always worth 2%" | Depends on the number crossed | Estimate from margin frequencies | ## Output Format ``` DEN @ KC moneyline (Pinnacle close): KC +672 / DEN -920 Raw: 0.1295 / 0.9020, hold 3.15% No-vig (proportional): KC 12.56% / DEN 87.44% No-vig (power, k=1.094): KC 10.68% / DEN 89.32% Fair price (proportional): KC +696 / DEN -696 Method note: [proportional / power], favorite above -500 ``` ## What to Do Next | What You Found | Next Action | Skill | |----------------|-------------|-------| | Hold across books | Pick the best price | `odds-explorer` |
odds-explorer6.89 KB
--- name: odds-explorer description: "Compares NFL spreads, totals and moneylines across sportsbooks, finds the best price, reads opening-to-closing movement, and browses alternate lines. Use when user asks about the line on a game, which book has the best number, how a line moved, Pinnacle versus the consensus, alternate spreads, or key numbers like 3 and 7. Do not use for devigging or implied probability math, see odds-analysis. Do not use for player props, see prop-modeling." metadata: version: 1.0.0 author: EndzoneAPI --- # Odds Explorer > **Default data tool:** EndzoneAPI (`endzoneapi-tool`). > `get_odds` for one game's lines by book (10 credits). `get_line_movement` for the hourly series (25 credits). `get_alt_lines` for ladders (10 credits). `get_games` already carries the consensus closing line (5 credits per query). You are an expert in football betting markets. Your goal is to show where the best price is, what the market says, and how it moved, in numbers the user can check. ## When to Use - "What was the closing line for Denver at Kansas City?" - "Which book had the best number on the Chiefs?" - "Did the total move after the injury news?" - "What does a 6.5 point alternate spread cost?" - "How often do games land on 3 or 7?" ## When NOT to Use - Removing vig and converting to probability, see `odds-analysis` - Player props, see `prop-modeling` ## Commands Available | Command | What It Does | Credits | |---------|-------------|---------| | `get_odds` | `game_id`: consensus close plus each book's opening, closing, latest. Or `season` (and optional `team`): a page of per-book closing lines | 10 per game | | `get_line_movement` | Hourly snapshots grouped by `bookmaker` for one `game_id` | 25 | | `get_alt_lines` | Alternate spread and total ladders, 2023 to 2025, 6 books | 10 | | `get_games` | Consensus closing spread, total, moneylines for many games | 5 | | `get_schedule` | Upcoming games with consensus lines where posted | 2 | ## Commands That Do NOT Exist | Not Available | Use Instead | |--------------|-------------| | `get_best_line` | Pull `get_odds`, compare the books yourself | | `get_public_betting` | Not available. Infer nothing about bet percentages from line moves alone | | `get_live_odds` | `get_odds` latest snapshot; not an in-game feed | | `get_futures` | Not available | ## Data Coverage - Consensus closing spread and total: every game since 1999. Moneyline since 2010. - Per-book closing: 2014 onward (ESPN source, 4 to 9 books through 2019, closing only). - Opening, closing and latest per book: 2020 onward from The Odds API, up to 8 books including Pinnacle. Each line carries its `source`. - Books: draftkings, fanduel, betmgm, espnbet, pinnacle, bovada, betonlineag, mybookieag. - Alternate ladders: one game at a time, 2023 to 2025 seasons. - Hourly snapshots in season begin 2026. Earlier games have opening and closing only. ## Sign Conventions (the first bug everyone ships) Two conventions meet in this API. Real example, 2025 Week 17 DEN at KC, where Denver was the favorite: | Where | Field | Value | Meaning | |-------|-------|-------|---------| | `get_games`, `consensus_closing` | `spread_line` | -13.5 | Home-side number: negative means the away team is favored | | Pinnacle book object | `spread_home` | 13.5 | Book convention: the home team gets +13.5 | | Pinnacle book object | `spread_away` | -13.5 | Away team lays 13.5 | Rule: `spread_line` is positive when home is favored. `spread_home` is negative when home is favored. They are negatives of each other. Convert before you compare. Home covers if `result > spread_line` where `result` is home score minus away score. In the example, KC lost 13 to 20, `result` = -7, which is greater than -13.5, so KC covered. ## How It Works **Step 1: Get the game id.** From `get_games` or `get_schedule`. Format `2025_17_DEN_KC`. **Step 2: Pull the book lines.** `get_odds(game_id="2025_17_DEN_KC")`. Add `bookmaker="pinnacle"` to narrow. Real shape of one book entry: `opening`, `latest`, `closing`, each with `ml_home`, `ml_away`, `spread_home`, `spread_home_odds`, `spread_away`, `spread_away_odds`, `total`, `total_over_odds`, `total_under_odds`, `captured_at`, `source`. **Step 3: Compare.** For each market, the best price for each side independently. Spreads: a half point matters more at 3 and 7 than elsewhere. Moneylines: higher number is better on both sides. **Step 4: Movement.** From the real Pinnacle entry: total opened 36.5 at -107/-107 and closed 37.5 at -114/+101. A one point total move, with the over price rising, means money or information pushed the total up. Spread stayed at 13.5, only the price moved (-103 to -109 on the home side). Report all three: the number, the price, the time window (`captured_at`). **Step 5: Key numbers.** In the NFL, 3 and 7 are the most common margins of victory, then 6, 10, 14. Moving a spread across 3 is worth far more than crossing 2 or 4. Measure the actual frequency from `get_games` results (`result` column) over the seasons you have rather than quoting a remembered figure. **Step 6: Alternate lines.** `get_alt_lines(game_id="2025_17_DEN_KC", market="alternate_spreads", bookmaker="pinnacle")` returns the ladder with `side` (home or away) and each point's price. Buying points has a price; compare to the main line's implied probability change (see `odds-analysis`). ## Reference Line ## Credit Usage | Operation | Credits | |-----------|---------| | Consensus closing for a whole season | 5 (`get_games`) | | One game, all books | 10 | | One game, hourly movement | 25 | | One game, alternate ladders | 10 | | A season of per-book lines | 10 per game, 1,000 for a 100-game page | Use `estimate_only=true` on `get_odds` to price a season pull before running it. It charges nothing. ## Anti-patterns | Rationalization | Why It's Wrong | Do This Instead | |----------------|---------------|-----------------| | "Spread -13.5 means the home team is favored" | `spread_line` is home-perspective, positive = home favored | Check against the final score of a known game | | "Latest line equals closing line" | Latest is the newest snapshot, which may be hours before kickoff | Use the `closing` snapshot for historical work | | "Any 0.5 move is equal" | Moves through 3 and 7 carry real probability | Weight by key number | | "Books agree, so skip the comparison" | Prices differ even when numbers match | Compare the odds, not just the line | ## Output Format ``` DEN @ KC -- Dec 25, 2025 (kickoff 01:15 UTC Dec 26) Consensus close: DEN -13.5, total 37.5, ML DEN -1100 / KC +700 Pinnacle: KC +13.5 (-109), DEN -13.5 (-102); total 37.5 (O -114 / U +101) Movement: total 36.5 -> 37.5 (+1.0), spread unchanged, DEN price -109 -> -102 Note: spread_line is -13.5 (home-side), the book shows KC +13.5. ``` ## What to Do Next | What You Found | Next Action | Skill | |----------------|-------------|-------| | Two-sided price | Remove vig | `odds-analysis` | | Large move | Check injuries and news in the matchup | `game-preview` |
player-scouting7.5 KB
---
name: player-scouting
description: "Searches NFL players and builds scouting profiles from weekly stats, season totals, leaderboards, snap counts, injuries and depth charts. Use when user asks about a specific player, compares players, wants leaders in a stat, asks about target share, usage, snap share, or a player's weekly game log. Do not use for tracking metrics like separation or time to throw, see next-gen-stats. Do not use for prop lines, see prop-modeling. Do not use for college players, see college-football."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# Player Scouting
> **Default data tool:** EndzoneAPI (`endzoneapi-tool`).
> `search_players` (2 credits) first, always. Then `get_player_stats` (5) for a profile or `get_player_leaders` (5) for a ranking.
You are a football scout. Your job is to turn a name into an id, then into a profile that separates role from efficiency from luck.
## When to Use
- "How is Drake Maye playing?" / "Compare two receivers"
- "Who leads the league in receiving EPA?"
- "Is this running back's workload sustainable?"
- "Show me a player's game log for 2025"
- "Who is the starter on KC's depth chart?"
## When NOT to Use
- Separation, time to throw, rush yards over expected, see `next-gen-stats`
- Will he go over his yardage line, see `prop-modeling`
- Team-level efficiency, see `epa-analysis`
- FBS or FCS players, see `college-football`
## Commands Available
| Command | What It Does | Credits |
|---------|-------------|---------|
| `search_players` | Partial name match; returns GSIS id, PFR id, team, position, college | 2 |
| `get_player_stats` | Bio, draft, summed season totals, every weekly line, games played per season | 5 |
| `get_player_leaders` | Rank by any weekly stat; `position`, `team`, `min_games`, `limit` filters | 5 |
| `get_snap_counts` | Offense, defense, special teams snaps and shares | 5 |
| `get_depth_chart` | Depth rank by position for a week | 2 |
| `get_injuries` | Status and practice participation | 2 |
## Commands That Do NOT Exist
| Not Available | Use Instead |
|--------------|-------------|
| `get_player_comparison` | Two `get_player_stats` calls, compare in your own table |
| `get_player_projection` | Not available, see `prop-modeling` for a method |
| `get_player_game_log` | `get_player_stats`, the weekly lines are in the response |
| `get_rookie_class` | `get_player_leaders` filtered by `position`, check `rookie_season` from `search_players` |
| `get_contract` | Not available |
## How It Works
**Step 1: Find the id.** `search_players(query="Mahomes")` returns the GSIS id (`00-0033873`), `pfr_id`, `team`, `position`, `college`, `rookie_season`, `last_season`. The search covers about 25,000 players back to 1999. Current-season players come first; if none match, it falls back to everyone and says so. Pass `active=false` to search everyone outright. Two players with the same surname: add `team` or `position`.
**Step 2: Profile.** `get_player_stats(player_id="00-0033873", season=2025)` returns season totals across passing, rushing, receiving, defense, kicking, returns and fantasy points, plus a weekly line for every game. Use the weekly lines to spot trends, the totals for the summary.
**Step 3: Rank in context.** `get_player_leaders(stat="receiving_epa", season=2025, position="WR", min_games=8, limit=20)`. Counting stats are summed, rate stats are averaged. Confirmed stat names include `passing_yards`, `passing_tds`, `rushing_yards`, `receiving_yards`, `receptions`, `targets`, `def_sacks`, `def_interceptions`, `fantasy_points_ppr`, `passing_epa`, `rushing_epa`, `receiving_epa`; about 130 more exist. If a name is rejected, pull one `get_player_stats` weekly line and copy a column name.
Real response shape: `data.leaders[]` = `{rank, player_id, name, position, team, games, value}`. In the 2025 regular season, `passing_epa` summed, QBs with 8+ games: Drake Maye first at 166.2, Matthew Stafford second at 150.5, both in 17 games.
**Step 4: Separate role from efficiency.**
| Layer | Stats | Why |
|-------|-------|-----|
| Opportunity | `targets`, `carries`, snap share (`get_snap_counts`) | Most stable year to year |
| Efficiency | `receiving_epa`, yards per target, yards per carry | Noisy, regresses |
| Outcome | touchdowns, fantasy points | Noisiest, driven by luck and red zone |
A receiver with high EPA on few targets is a small-sample story. A receiver with high targets and low EPA is a role story. Say which one you see.
**Step 5: Check availability.** `get_injuries(team="KC")` shows game status and practice participation. `get_depth_chart(team="KC", formation="Offense")` shows depth rank. Injury reports land mid-week; an empty report before Wednesday is not a clean bill of health.
## Sample Size Rules
- Under 8 games in a season: treat per-game rates as descriptive, not predictive.
- Rate stats averaged across weeks (as `get_player_leaders` does for rate columns) weight a 3-target game the same as a 12-target game. For a true rate, divide summed numerators by summed denominators from the weekly lines.
- A quarterback's EPA depends on his line, receivers and play-calling. Compare against his team's other quarterbacks when that exists, otherwise be explicit that you cannot separate them.
- Use `min_games` so a one-game wonder does not top a leaderboard.
## Credit Usage
| Operation | Credits |
|-----------|---------|
| Find a player | 2 |
| One player profile | 5 |
| A leaderboard | 5 |
| Full scouting (search, stats, snaps, depth) | 14 |
| Compare two players | 14 |
## Anti-patterns
| Rationalization | Why It's Wrong | Do This Instead |
|----------------|---------------|-----------------|
| "Top of the leaderboard is the best player" | Sums reward games played and volume | Use `min_games`, add a rate column |
| "Use the GSIS id for snap counts" | `get_snap_counts` takes the PFR id for `player_id` | Use `pfr_id` from `search_players` |
| "Fantasy points show quality" | Dominated by touchdowns and volume | Use EPA plus opportunity |
| "Search by last name only" | Several matches possible | Add `team` or `position` |
## Output Format
```
Drake Maye (QB, NE) -- 2025 regular season
Passing EPA: 166.2 (rank 1 among QBs, 17 games)
Role: [attempts, snap share] Efficiency: [EPA per dropback, CPOE]
Trend: last 4 games vs first 4 -- [direction, with the number]
Caveat: [sample, injuries, supporting cast]
```
## What to Do Next
| What You Found | Next Action | Skill |
|----------------|-------------|-------|
| A player with strong role | Check tracking data | `next-gen-stats` |
| A player with a prop line | Project the stat | `prop-modeling` |
| Weekly lines | Build rolling features | `feature-engineering` |
| Team context needed | Pull team EPA | `epa-analysis` |
## Worked Example
User: "Who are the best quarterbacks by EPA in 2025, and is the leader's number real?"
1. `get_player_leaders(stat="passing_epa", season=2025, position="QB", min_games=8, limit=10)` (5 credits).
2. The top row is Drake Maye, 166.2 summed passing EPA over 17 games. Divide by his dropbacks to get a per-play rate before comparing him to a quarterback with fewer games.
3. `search_players(query="Maye")` then `get_player_stats(player_id=<id>, season=2025)` (7 credits) for the weekly lines. Check whether the total comes from a few huge weeks or a steady run.
4. Report: leader, per-play rate, share of total from the best three weeks, and one caveat (offensive line, schedule).
Total cost: 12 credits. Without step 3 the answer is only a ranking, not an evaluation.
## Reference
Python walkthrough: weekly player stats: https://endzoneapi.com/guides/nfl-player-weekly-stats-python
probability-calibration6.13 KB
---
name: probability-calibration
description: "Checks and repairs predicted probabilities for NFL outcomes: reliability tables, Brier score, log loss, expected calibration error, Platt scaling, isotonic regression, and sample-size limits. Use when user asks if a model's 65% means 65%, how to calibrate, Brier score, log loss, why a model is overconfident. Do not use for building the model, see feature-engineering. Do not use for time-ordered testing, see walk-forward-validation. Do not use for turning odds into probability, see odds-analysis."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# Probability Calibration
> **Default data tool:** EndzoneAPI (`endzoneapi-tool`) for outcomes only: `get_games` (5 credits) returns `result`, `spread_line`, `total`, `total_line` for scoring predictions. Calibration itself is local code.
> For your own predictions CSV: no credits used.
You are an expert in probabilistic forecast quality. Your goal is to check that a stated probability matches the observed frequency, and to fix it only when the evidence supports a fix.
## When to Use
- "My model says 70% for the home team, is that right?"
- "Is my model overconfident?"
- "Compute Brier score and log loss"
- "Should I use Platt scaling or isotonic?"
- "Are my cover probabilities good enough to size bets?"
## When NOT to Use
- Constructing inputs, see `feature-engineering`
- Choosing training windows, see `walk-forward-validation`
- Devigging market odds, see `odds-analysis`
## Commands Available
| Command | Use Here | Credits |
|---------|---------|---------|
| `get_games` | Realized outcomes and consensus lines for scoring | 5 per query |
## Commands That Do NOT Exist
| Not Available | Use Instead |
|--------------|-------------|
| `get_calibration` | Compute from your predictions and `get_games` outcomes |
| `get_model_probabilities` | Not provided; bring your own |
## Metrics
For predictions `p_i` in [0, 1] and outcomes `y_i` in {0, 1}:
```
Brier = mean((p - y)^2)
LogLoss = -mean(y * ln(p) + (1 - y) * ln(1 - p))
```
Reference points for a binary game outcome at 50/50 forecasts: Brier 0.25, log loss 0.693. A forecast has to beat those, then beat the market's own probabilities (see `odds-analysis`) on the same games.
**Reliability table.** Bin predictions (10 equal-count bins are better than 10 equal-width bins with small samples), then compare mean prediction to observed frequency per bin.
```python
df["bin"] = pd.qcut(df.p, 10, duplicates="drop")
rel = df.groupby("bin").agg(pred=("p", "mean"), obs=("y", "mean"), n=("y", "size"))
```
**Expected calibration error:** `sum(n_bin / N * |obs - pred|)`. Report with a bootstrap interval; with a few hundred games the interval is wide.
## Reading the Table
| Pattern | Meaning | Fix |
|---------|---------|-----|
| Predictions spread wider than outcomes (80% bin hits 68%) | Overconfident | Shrink toward the base rate, Platt scaling |
| Predictions narrower than outcomes | Underconfident | Rare; sharpen with Platt slope above 1 |
| Good in the middle, bad at the tails | Few tail samples | Do not fix tails with a flexible method on tiny n |
| Systematic offset (home always 3 points too high) | Bias | Intercept in Platt scaling |
## The Sample-Size Problem in Football
An NFL season has 272 regular season games. In 10 bins, that is about 27 games a bin per season. The standard error of an observed frequency near 0.5 at n = 27 is about 0.10. A bin at 0.60 predicted and 0.50 observed is inside the noise. Pool several seasons, use fewer bins (5), and show intervals. Do not conclude miscalibration from one season of one bin.
## Repairs
**Platt scaling (default).** Fit a logistic regression of outcome on the logit of your prediction:
```python
from sklearn.linear_model import LogisticRegression
z = np.log(p / (1 - p)).reshape(-1, 1)
cal = LogisticRegression(C=1e6).fit(z, y) # two parameters: slope and intercept
p_cal = cal.predict_proba(z)[:, 1]
```
Two parameters, stable on a few hundred games. A slope below 1 confirms overconfidence.
**Isotonic regression.** Flexible monotone fit. Needs thousands of rows; on a few hundred games it overfits steps. Use only with enough data.
**Fit the calibrator on out-of-sample predictions.** The calibration map must be learned on predictions from a walk-forward run (see `walk-forward-validation`), then applied forward in time. Fitting it on the same data used to score it reports an inflated gain.
## Regression Predictions
If the model predicts a margin, convert to a win probability with a normal approximation:
```
P(home wins) = Phi(predicted_margin / sigma)
```
with `sigma` estimated from your own residuals (`result` minus predicted margin). NFL margins are not normal around the spread; key numbers (3, 7) put extra mass at specific margins. For cover probabilities near the spread, estimate the empirical distribution of `result - spread_line` from the seasons you have and use it instead of the normal curve. Compute both and compare on held-out games.
## Using Calibration for Bets
## Credit Usage
Five credits per `get_games` query. Everything else is local.
## Anti-patterns
| Rationalization | Why It's Wrong | Do This Instead |
|----------------|---------------|-----------------|
| "Accuracy is 64% so it's good" | Says nothing about confidence | Report Brier and log loss next to the market's |
| "Calibrate on the test set" | Leaks the answer | Calibrate on prior out-of-sample predictions |
| "Isotonic is more flexible so better" | Overfits small samples | Platt first |
| "One season's reliability chart shows bias" | 27 games a bin | Pool seasons, show intervals |
| "Clip probabilities at 0.99" | Log loss punishes confident misses | Check the model, do not hide it |
## Output Format
```
Calibration, out-of-sample, 2022-2025 (N = 1,088 games)
Brier: 0.xxx (market 0.xxx) | Log loss: 0.xxx (market 0.xxx)
Platt slope 0.xx, intercept 0.xx -> [overconfident / fine]
Reliability (5 bins): pred x.xx obs x.xx n=NNN (95% CI x.xx to x.xx) ...
Verdict: [calibrated / adjust / insufficient data]
```
## What to Do Next
| What You Found | Next Action | Skill |
|----------------|-------------|-------|
| Poorly calibrated | Rebuild inputs or add data | `feature-engineering` |
prop-modeling8.95 KB
---
name: prop-modeling
description: "Builds NFL player prop models for passing yards, passing touchdowns, rushing yards, receiving yards, receptions and anytime touchdown, using prop history, usage, snap share, game script from the spread and total, and injuries. Use when user asks about player props, whether a player goes over a yardage line, prop projections, anytime TD odds, or the historical over rate against a line. Do not use for team game prediction, see feature-engineering. Do not use for browsing odds across books for a game side, see odds-explorer. Do not use for player profiles without a line, see player-scouting."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# Prop Modeling
> **Default data tool:** EndzoneAPI (`endzoneapi-tool`).
> `get_player_props` (10 credits) for lines, `get_prop_history` (10 credits for up to 200 games) for how a player did against his line, `get_snap_counts` and `get_player_stats` (5 credits each) for usage, `get_games` (5 credits) for the game environment.
> Props coverage starts in the 2023 season. Samples are small by nature.
You are an expert in player prop modeling. Your goal is to project a player's stat for one game as a distribution, compare it with the book's line and price, and be honest about how little data a single player-season gives you.
## When to Use
- "Will Mahomes go over 250.5 passing yards?"
- "What has this receiver done against his line this year?"
- "Project a running back's yardage"
- "What is the fair price on an anytime touchdown?"
- "Which book has the best number on this prop?"
## When NOT to Use
- Which team wins, see `feature-engineering`
- A team's spread price, see `odds-explorer`
- General scouting, see `player-scouting`
## Commands Available
| Command | What It Does | Credits |
|---------|-------------|---------|
| `get_player_props` | Props by book. `game_id` for all players in a game, or `player_id` plus `season`. `market`, `bookmaker`, `snapshot_type` (closing or opening), `estimate_only` | 10 per game returned |
| `get_prop_history` | One player and market: a row per game with `line`, `open_line`, prices, `actual`, `result`, `margin`, plus an over-rate summary. `from_date`, `to_date`, `bookmaker`, `limit` | 10 for up to 200 games |
| `get_snap_counts` | Snaps and shares by game, `player_id` (PFR id), or `team` and `season` | 5 |
| `get_player_stats` | Weekly lines for the season | 5 |
| `get_injuries`, `get_depth_chart` | Availability and role | 2 each |
| `get_games` | Spread and total for the game environment | 5 |
| `get_advanced_stats` | Tracking and charting context | 5 |
| `search_players` | The ids (GSIS for props and stats, PFR for snaps) | 2 |
## Markets
`get_player_props` markets: `player_pass_yds`, `player_pass_tds`, `player_rush_yds`, `player_reception_yds`, `player_receptions`, `player_anytime_td` (over means he scores).
`get_prop_history` adds `player_pass_completions`, `player_pass_attempts`, `player_pass_interceptions`, `player_rush_attempts`.
Books on props: DraftKings, FanDuel, BetMGM, ESPN BET, Pinnacle, Bovada, BetOnline.
## Commands That Do NOT Exist
| Not Available | Use Instead |
|--------------|-------------|
| `get_player_projection` | Build it as below |
| `get_dfs_projections` | Not provided |
| `get_prop_edges` | Compute edge from your distribution and the line |
| Props before 2023 | Not covered |
## Real Data Shapes
`get_prop_history(player_id="00-0033873", market="player_pass_yds", from_date="2025-09-01", limit=3)` (Mahomes) returned:
| game | line | open | over | under | books | actual | result | margin |
|------|------|------|------|-------|-------|--------|--------|--------|
| 2025_01_KC_LAC | 250.5 | 244.5 | -120 | -110 | 7 | 258 | over | +7.5 |
| 2025_02_PHI_KC | 245.5 | 245.5 | -110 | -121 | 7 | 187 | under | -58.5 |
with `summary` = overs 1, unders 2 of 3 graded, `over_rate` 0.333, `avg_line` 243.5, `avg_actual` 223, and `next_from_date` to continue. Three games is an illustration, not a signal.
`get_player_props(game_id="2025_17_DEN_KC", market="player_pass_yds")` returned 14 rows, each `{player_name, gsis_id, market, bookmaker, line, over_odds, under_odds, captured_at, source}`; for example Bo Nix at 228.5 with -115 on both sides at BetMGM. One row per player per book.
## How It Works
**Step 1: Establish the role.** Starter or not (`get_depth_chart`), injury status, snap share and target share over the last 4 to 6 games (`get_snap_counts`, `get_player_stats`). Prop outcomes follow opportunity.
**Step 2: Game environment.** From the spread and total, the implied team totals:
```
home_implied = (total + spread_line) / 2
away_implied = (total - spread_line) / 2
```
`spread_line` is positive when home is favored. A team implied for 26 points passes and scores differently from one implied for 17. Trailing teams pass more; favorites run late.
**Step 3: Decompose the stat.**
| Market | Decomposition |
|--------|---------------|
| Passing yards | attempts x yards per attempt (attempts depend on pace and game script) |
| Passing TDs | attempts x TD rate; or team implied points x passing share |
| Rushing yards | carries x yards per carry (carries depend on script and share of backfield) |
| Receiving yards | team pass attempts x target share x yards per target |
| Receptions | targets x catch rate |
| Anytime TD | expected scoring chances (red-zone usage) with Poisson probability `1 - exp(-lambda)` |
Project each component from rolling usage with shrinkage (see `feature-engineering`) and multiply, or fit a regression directly on past games from `get_prop_history` and `get_player_stats` (the history gives `actual` per game).
**Step 4: Distribution, not a point.** Yardage is right-skewed. Use a gamma or a log-normal fit to the player's game residuals, or a negative binomial for counts such as receptions. The variance is the major input: a projection of 250 with a standard deviation of 70 puts a 250.5 line near 50/50, nowhere near a lock.
```
P(over line) = 1 - F(line) F: fitted distribution of the stat
```
Compute `P(over)` and `P(under)` and compare with the devigged line price (see `odds-analysis`). The line itself is the market median projection.
**Step 6: Shop.** Different books carry different lines for the same prop. `get_player_props` returns them side by side. A half-point on a yardage line moves the over probability only a little but matters on an even-priced bet.
## Sample Size
- Props cover 2023 onward: at most about 17 games a year per player, 3 seasons by 2025, so roughly 50 games for a durable starter.
- A player-market history of 17 games has an over rate with a standard error near 12 percentage points. A 60% over rate in 17 games is consistent with 50%.
- The line is already built from the same stats, so a historical over rate away from 50% is weak evidence unless it is large and persistent.
- Do not tune a prop model on the games you test. Use walk-forward (see `walk-forward-validation`).
- Anytime TD is a rare event: a back at 0.5 TDs a game scores in about 40 percent of games; one season holds too few for a stable rate. Use team red-zone share as a prior.
## Correlation
A quarterback's passing yards and his top receiver's receiving yards move together. Two props from the same game are not independent bets. Same-game parlays multiply the book's margin; evaluate each leg's edge, and avoid assuming independence.
## Credit Usage
| Operation | Credits |
|-----------|---------|
| Prop lines for a whole game | 10 |
| One player-market history | 10 |
| One player's props across a season | 10 per game returned |
| Usage (snaps, stats) | 5 each |
| Full model for one player | about 35 |
`estimate_only=true` on `get_player_props` shows the price first. Full-league prop history across seasons is expensive; start with the players that matter to the question.
## Anti-patterns
| Rationalization | Why It's Wrong | Do This Instead |
|----------------|---------------|-----------------|
| "Average is 262 so over 250.5" | Ignores variance, role, script | Fit a distribution |
| "He is 11 of 15 over" | Small sample, line already adjusts | Report with an interval |
| "Starter is out, use the old role" | Usage shifts | Reload the depth chart |
| "Parlay these two props" | Correlated, extra margin | Price legs separately |
| "Use opening line for a closing bet" | Different information | State snapshot used |
## Output Format
```
Mahomes, passing yards, KC vs [opp]
Environment: total X, KC implied Y
Projection: attempts A x YPA B = C (distribution: gamma, sd D)
Line 250.5 (best over: [book] -115, best under: [book] -110)
P(over) 0.xx vs no-vig 0.xx -> edge +/-x.x pts (before shrinkage)
History: over rate x/y games (not predictive alone)
Risks: [injury news, game script, line moves]
```
## What to Do Next
| What You Found | Next Action | Skill |
|----------------|-------------|-------|
| A projection gap | Calibrate and shrink | `probability-calibration` |
| A needed price | Convert odds | `odds-analysis` |
## Reference
Python walkthrough: prop lines by sportsbook: https://endzoneapi.com/guides/nfl-player-prop-lines-by-sportsbook-python
walk-forward-validation7.24 KB
---
name: walk-forward-validation
description: "Evaluates sports models in time order: expanding or rolling windows, season-by-season holdouts, bye weeks and season rollover, baselines, and significance. Use when user asks how to validate an NFL model, whether k-fold is acceptable, why backtest results look too good, how many seasons to train on, or how to compare a model to the closing line. Do not use for building features, see feature-engineering. Do not use for probability checks, see probability-calibration."
metadata:
version: 1.0.0
author: EndzoneAPI
---
# Walk-Forward Validation
> **Default data tool:** EndzoneAPI (`endzoneapi-tool`).
> Data is the same as `feature-engineering`: `get_games` (5 credits per query) for seasons of results and consensus lines. Validation itself uses no credits.
You are an expert in evaluating predictive models on time-ordered data. Your goal is to estimate how a model would have done if used live, and to refuse any evaluation that lets the future inform the past.
## When to Use
- "How do I test my NFL model?"
- "Can I use cross-validation?"
- "My model has 58% against the spread in testing"
- "How many seasons should I train on?"
- "Does my model beat the closing line?"
## When NOT to Use
- Constructing inputs, see `feature-engineering`
- Checking if 70% means 70%, see `probability-calibration`
## Commands Available
| Command | Use Here | Credits |
|---------|---------|---------|
| `get_games` | Season results, scores, consensus lines for the test and baseline | 5 per query |
| `get_standings` | Sanity check of season records | 2 |
## Commands That Do NOT Exist
| Not Available | Use Instead |
|--------------|-------------|
| `get_train_test_split` | Do it in your own code by season and week |
| `get_model_predictions` | Not provided; bring your own |
| `get_closing_line` | `get_games` consensus close |
## Why Random Splits Fail
Random k-fold puts week 12 games in the training set for a week 5 test game. Team strength is persistent, so the model learns the team from the future. In football, a coach, quarterback or scheme carries across weeks. Results from random splits are optimistic and the amount is not predictable. Walk-forward only.
## The Procedure
1. Sort games by kickoff time.
2. Choose an initial training window and a step. For NFL, the natural step is one week (retrain weekly) or one season (retrain yearly).
3. For each step: fit on data strictly before the step, predict the step, store predictions.
4. Concatenate predictions. Evaluate once, on the stitched out-of-sample set.
```python
def walk_forward(df, first_test_season, step="week"):
preds = []
for (season, week), test in df[df.season >= first_test_season].groupby(["season", "week"]):
train = df[(df.season < season) | ((df.season == season) & (df.week < week))]
model = fit(train) # features already shift(1)-safe
test = test.assign(pred=model.predict(test))
preds.append(test)
return pd.concat(preds)
```
Fit hyperparameters inside the training window (nested), not on the final test set. Choosing the best of 20 settings on the test seasons and reporting that score is a leak.
## Football Specifics
**Season rollover.** Rosters, coaches and quarterbacks change. The first weeks of a season rely on priors; evaluate weeks 1 to 4 separately from weeks 5 to 18. A model that is strong only late hides an early-season problem.
**17-game seasons.** A season has about 272 regular season games, plus about 13 postseason games. Test over several seasons. One season of 272 games has a standard error on a hit rate near 3 percentage points (sqrt(0.25 / 272) is about 3.0 points). A 55% result on one season is within noise of 50%.
**Window choice.** Expanding window (all past data) is stable. Rolling window (last N seasons) adapts to rule changes: kickoff rules, passing-friendly officiating, and so on. Compare both by walk-forward error.
**Bye weeks and short weeks.** Rows with a bye the prior week have no prior-week game; handle features for them explicitly.
**Postseason.** Fewer games, different incentives. Report regular season and postseason separately, and do not tune on the postseason.
**Weeks 17 and 18.** Teams with clinched seeds rest starters. The market sees that; a model without lineup information will not.
## Baselines (the comparison that matters)
| Baseline | What It Tests |
|----------|---------------|
| Home team always wins | Floor for accuracy |
| Market-implied probability from the closing line | The hard bar |
| Elo-only model | Does your complexity add value |
| Previous season win percentage | Persistence |
Metrics to report, vs each baseline on the same games:
- **Log loss** and **Brier score** for probabilities (lower is better). Accuracy alone hides confidence.
- **Mean absolute error** of the predicted margin vs the closing spread's error. In public NFL data the closing spread's margin error is a hard benchmark to beat.
- **Calibration** (see `probability-calibration`).
A model that does not beat the closing line on log loss does not produce an edge by betting at the closing line, however well it picks winners.
## Significance
Differences between two models on the same games are paired. Use a paired bootstrap over games (resample game indices, recompute the log loss difference) and report the interval. With a few hundred games, a difference of 0.003 in log loss is not distinguishable from zero. Report the interval, not only the point estimate.
```python
rng = np.random.default_rng(0)
diffs = []
for _ in range(2000):
idx = rng.integers(0, n, n)
diffs.append(loss_a[idx].mean() - loss_b[idx].mean())
lo, hi = np.percentile(diffs, [2.5, 97.5])
```
If the interval contains zero, say the models are not separated on this data.
## Multiple Comparisons
Trying 30 feature sets and reporting the best inflates results. Count the variants you tried. Hold out the most recent complete season untouched until the final check, run it once, and report it as is.
## Credit Usage
Data pull only. Five seasons of consensus lines and results: 25 credits through `get_games`. Evaluation is local.
## Anti-patterns
| Rationalization | Why It's Wrong | Do This Instead |
|----------------|---------------|-----------------|
| "Cross-validation is standard" | It is for exchangeable data; games are ordered | Walk forward |
| "Test on 2024 and tune on 2024" | The test is no longer out of sample | Tune only on earlier seasons |
| "58% ATS in one season" | Standard error is about 3 points | Use more seasons and an interval |
| "Win rate is the metric" | Hides confidence | Use log loss and Brier |
| "Skip the closing-line baseline" | It is the only baseline that matters for betting | Always include it |
## Output Format
```
Walk-forward, expanding window, weekly refit, test seasons 2021-2025 (N games)
Log loss: model 0.xxx | closing line 0.xxx | Elo 0.xxx
Paired bootstrap, model minus closing: -0.00x (95% CI -0.0xx to +0.0xx)
By phase: weeks 1-4 [..], weeks 5-18 [..], postseason [..]
Verdict: [separated from the market / not separated], sample caveat
```
## What to Do Next
| What You Found | Next Action | Skill |
|----------------|-------------|-------|
| Model separated from baselines | Check probability quality | `probability-calibration` |
| Weak model | Revisit inputs | `feature-engineering` |
Release notes
Initial release. Read-only NFL football data tools with OAuth sign-in and 14 workflow skills.
Declared in the saved package. Remote tools may change independently.
Package details
Publisher declarations from the archived package. These are separate from our research and the live service's terms.
- Package license
- MIT
- Package author
- EndzoneAPI
- Keywords
- See keywords
- Commerce declaration
- Does not support commerceThis does not establish whether access is free or paid.
- Review scenarios
- 5 positive · 3 negativeScenario counts, not test results.
Declared capabilities
- Look up NFL teams, players and games
- Read standings, schedules and results
- Read play-by-play, EPA and advanced stats
- Read injuries, depth charts and snap counts
- Read sportsbook odds and prop lines (information only)
Package observed Nov 3, 2026.
Technical details
- First seen
- Oct 30, 2026 · 00:00 UTC
- Last seen
- Nov 3, 2026 · 18:00 UTC
- Collection status
- Collected
plugin_asdk_app_6ad12c268a0c819197d22541a1109e49
Download plugin data (JSON)