Sample responses
Everything on this page is what the API returned for two real games, untrimmed. Read the files to see the shapes before you sign up, test your parser against them, or replay the NFL game’s journal through your client to see a whole game arrive change by change. None of it needs a key, and none of it starts your trial.
The games
The files were made by replaying the recorded upstream responses through Statpad’s real ingest pipeline into a fresh database and requesting each endpoint from the real API, so they’re the exact bodies you’d get. Two things differ from production: the ids are that database’s, and every updated_at and change at is when the sample was generated, not when the game was played.
Files
NFL: Bills at Vikings
Premier League: Man United v Aston Villa
Other
The files allow requests from any origin, so you can fetch them from a browser too:
A game in progress
game-live.json is the game with 7:02 left in the 4th quarter, the Bills up 13 to 6 with 1st and goal at the Minnesota 5. This is its live_state, unedited:
Its seq is 1101. Line 1,102 of changes.ndjson is the first change after it, which is where the Quickstart client would resume. Four changes later, at seq 1106, James Cook runs it in.
Replay the game
changes.ndjson is the game’s whole journal, in seq order, exactly as the stream delivers it to a client that resumes from seq 0. Feeding it through your code is the closest thing to watching the game live, any day of the week.
This script plays it back and prints each play as it lands. It keeps the same map as the Quickstart client, keyed by entity type and id, with the newest version winning, so it also shows corrections arriving:
It needs no packages. Run it with Node 22.18 or newer; the argument is changes per second, so the default of 20 plays the game in about a minute:
Corrections are normal. In this game, 83 of the 270 play changes rewrite a play that already arrived: a second tackler added, a touchdown that gains its extra point, a first-quarter penalty noted after the final whistle. Each is an upsert with a higher version, so replacing by id keeps you right without special handling.
To run your real client against the file, wrap each line in the message the stream sends, { "type": "changes", "stream": "game:<id>", "changes": [change] }, and pass it to the handler you use for the WebSocket.
Replay a recent game on the API
With a key, a game replays the same way on the real API, from the first change, for at least 7 days after it ends:
- Over the stream, subscribe with
resumeset to0:{ "type": "subscribe", "streams": ["game:<id>"], "resume": { "game:<id>": 0 } }. The server sends every change from the start, then carries on live if the game is still going. Replay doesn’t use your request allowance. - Over REST, page
GET /v1/{league}/games/{id}/changes?after_seq=0&limit=1000, passing the lastseqof each page as the nextafter_seq. Each page counts as one request against your allowance.
From a position older than what’s retained, the stream sends resync_required and /changes answers 410. The game’s plays, drives and box score are still there over REST.
What to expect in the data
These samples show the API as it is today, including the fields nothing fills yet. A few you’ll notice:
period_scoresand the box score’steamsare empty lists. Add up the player lines for team totals.- In the NFL game,
clock_runningisnull: the football feed has no running flag. - After the final,
live_state.footballkeeps the last down, distance and yard line, and its timeouts arenull, because the feed stops reporting them. - NFL plays have an empty
participantslist; thedescriptionnames the players. - Premier League events have no
group_idorclock_seconds. Their time issoccer.minuteandsoccer.added_minute.
Coverage by league lists every field and endpoint that isn’t filled yet, per league.
The Premier League match is a finished-match sample, so it has no journal to replay. A recorded Premier League match will join the NFL game here.