Overview
StoryStats API
The StoryStats API turns major sports events into narrated insights. Pregame previews, live event-driven updates, and postgame recaps, all through a single REST interface.
Broad sports coverage
StoryStats is built for major professional, college, global, and tournament sports.
OpenAPI 3.0 spec
AI-agent friendlyThe full machine-readable spec is the source of truth for every endpoint, parameter, and response shape. Drop it into Cursor, Claude Code, or any codegen pipeline.
Base URL
All endpoints live under a single base URL. Every successful response is JSON.
https://api.balldontlie.ioAuthentication
Every request must include your API key in the Authorization header using the Bearer scheme. Your API keys are provisioned during signup or onboarding and managed from your account dashboard.
Authorization: Bearer YOUR_API_KEYRate limits
Limits are per API key. The free tier can make requests across every StoryStats sport. Paid sport packages and BALLDONTLIE all-access use the paid bucket.
| Account | Limit | Scope |
|---|---|---|
| Free | 10 requests per day | Per API key |
| Paid sport package | 120 requests per minute | Per API key, for subscribed sports |
| BALLDONTLIE all-access | 120 requests per minute | Per API key, all StoryStats sports included |
Rate-limit responses use HTTP 429. Enterprise plans can be shaped for higher production throughput.
Typical workflow
Story endpoints require a game ID. Start by listing games for a date, then use the returned IDs to fetch stories.
- List games for a date to get game IDs.
- Fetch the pregame story within 1 hour of the scheduled start.
- Poll live stories during the game for event-driven updates.
- Fetch the postgame story once the game is final.
Story availability
Stories are generated on a schedule. If you request one before it's ready, the API returns 404.
| Phase | When available | If not ready |
|---|---|---|
| Pregame | Within 1 hour before scheduled start | 404 |
| Live | After the game starts (first scheduled checkpoint or high-impact event) | Empty data: [] |
| Postgame | Immediately after the game goes final | 404 |
Error responses
4xx errors return a JSON body with a single error field. The 429 rate-limit response is plain text.
| Status | When | Body |
|---|---|---|
| 400 | Validation failed (invalid sport, missing date, bad timezone, invalid audience or tone). | {"error": "Invalid sport."} |
| 401 | Missing or invalid Authorization header. | {"error": "Authentication required. Provide an API key via the Authorization header."} |
| 404 | Game does not exist for that sport, or the requested story has not been generated yet. | {"error": "Game not found"} {"error": "Story not yet generated for this game"} |
| 429 | Rate limit exceeded. Body is plain text, not JSON. | Too many requests, please try again later. |
| 500 | Unexpected server error. Safe to retry with backoff. | {"error": "Internal server error"} |
APIs
Every endpoint is scoped to a sport path parameter. The examples below show the shared games and stories interface using common sport slugs such as nba, wnba, mlb, nhl, nfl. Soccer uses competition-scoped paths such as /stories/soccer/competitions/epl or /stories/soccer/competitions/world_cup.
NBA example
NBA game listings plus pregame, live, and postgame stories.
WNBA example
WNBA game listings plus pregame, live, and postgame stories.
MLB example
MLB game listings plus pregame, live, and postgame stories.
Soccer example
Competition-scoped game listings plus pregame, live, and postgame stories for global soccer.
NHL example
NHL game listings plus pregame, live, and postgame stories.
NFL example
Short NFL stories for preseason, regular-season, and postseason games.
Next steps
Head to the Quickstart for a hello-world request, or jump into the APIs for the shared games and stories interface.