Match lifecycle
What populates when, from scheduled through live to completed.
A match moves through three states, and which fields are trustworthy depends on where it is.
The states
status | Meaning | Scores | winner_team_id |
|---|---|---|---|
scheduled | Not started | null | null |
live | In progress | Partial | null |
completed | Finished | Final | Set, once the result is ingested |
scheduled_at is the planned start. There is no separate actual-start field, so a match that
started late still shows its scheduled time. Treat it as the fixture's slot, not as evidence of when
play began.
What appears when
Fixtures are created ahead of time with teams, tournament and format. Odds start being captured as soon as a market opens — often days before. Everything else lands as the match plays out or shortly after:
- Map results appear per map as each finishes.
- Round stats and player stats arrive with the map they belong to.
- Vetoes are known before play starts, since the pick/ban happens first.
- Depth (weapons, grenades, hitgroups, duels, flashes) is the last and least universal layer.
A completed match therefore does not guarantee every sub-resource exists.
Don't guess — read data_available
Every match row carries flags for exactly which sub-resources have data:
"data_available": { "maps": true, "stats": true, "vetoes": true, "rounds": true, "depth": false }Use them instead of speculatively fetching five endpoints and discarding empty responses. Each avoided request is one you keep in your monthly quota.
You can also filter the list to matches that have what you need:
# Only completed matches with round-level AND per-player depth data
curl -H "Authorization: Bearer $ESPORTSODDS_API_KEY" \
"https://api.esportsodds.gg/v1/cs2/matches?status=completed&has=rounds,depth&limit=20"has= accepts any comma-separated subset of maps,stats,vetoes,rounds,depth, AND-ed together. An
unknown value is a 400 rather than a silently ignored filter.
Settled odds
Once a match settles, its odds lines gain is_winner (which outcome came in) and one line per
outcome is flagged is_closing — the last price captured before scheduled_at. The closing line is
the standard benchmark for evaluating a forecast, so if you are scoring predictions, that's the row
you want. See odds movement.
How fast it changes
Measured over a recent 7-day window, the whole fixture corpus takes about 6 writes an hour — matches simply don't change often. Odds move roughly 110× faster. Polling both on the same timer is the single most common way to burn a monthly quota; the arithmetic is in how often to poll.