API documentation
Base URL https://api.spreadmodel.com. JSON over HTTPS. sport is nfl, nba or cfb.
Quickstart
curl "https://api.spreadmodel.com/v1/nba/projections?date=2026-10-20" \
-H "X-API-Key: spk_your_key"No key yet? Try the public sample: /v1/sample/nba.
Authentication
Send your key in the X-API-Key header. Keys start with spk_, are shown once when issued, and are scoped to the sports on your plan. Keep them server-side.
Endpoints
| Endpoint | Auth | Description |
|---|---|---|
| GET/v1/{sport}/projections | key | Latest projection for each game. ?date=YYYY-MM-DD (US Eastern) or upcoming games for ?days=1-14 (default 7). |
| GET/v1/{sport}/games/{game_id} | key | Every published version of a game's projection, and the final score once played. |
| GET/v1/{sport}/track-record | key | Graded games, error vs the closing line, record vs the closing spread and total. ?season= optional. |
| GET/v1/sample/{sport} | public | Most recent finished slate with final scores (up to 10 games). |
| GET/v1/sports | public | Sports covered. |
| GET/v1/health | public | Service status. |
Response fields
| Field | Type | Meaning |
|---|---|---|
| game_id | string | Stable game id (ESPN id for NBA and college, nflverse id for NFL) |
| kickoff | string | Scheduled start, UTC ISO 8601 |
| home, away | string | Team abbreviations |
| proj_home_pts, proj_away_pts | number | Projected points |
| proj_margin | number | Projected home margin (home minus away). Positive = home favoured |
| proj_total | number | Projected combined points |
| margin_sd, total_sd | number | Standard deviation of the margin and total errors (uncertainty) |
| home_win_prob | number | Probability the home team wins, from margin and margin_sd |
| model_version | string | Model that produced the projection |
| generated_at | string | When this version was produced, UTC |
Update schedule
- NBA: every game day after the 6 PM ET injury report.
- NFL: weekly, re-run Saturday morning after the final Friday injury reports.
- College football: weekly during the FBS season.
New versions never overwrite old ones; /games/{game_id} returns the full history.
Rate limits & errors
Each key has a per-minute limit (60 by default). Errors return JSON {"detail": "..."} with these codes:
- 401 missing or invalid key
- 403 sport not on your plan
- 404 unknown sport or game
- 422 bad parameter (e.g. date format)
- 429 rate limit; retry after the Retry-After header