Pre-match roster snapshots for a match
Each team's listed roster as it stood in the 48 hours before the match, oldest snapshot first within each team. **This is a roster snapshot, not a confirmed starting five.** Substitutes are listed too, so `player_ids` usually holds 6 or 7 ids and can hold anywhere from 1 to 11 — never assume a length of 5. The five who actually played are the player rows on `/stats`; compare the two to see who was benched or who stood in. A new row is written only when a team's roster differs from its previous snapshot, so most teams have exactly one row per match, and a second row means the roster changed in the run-up. An old `captured_at` is therefore not staleness. Coverage starts on 2026-07-09 and reaches roughly 6 in 10 matches since then; every earlier match returns an empty list. `data_available.lineups` and `?has=lineups` tell you which. An unknown match id also returns an empty list.
Each team's listed roster as it stood in the 48 hours before the match, oldest snapshot first within each team.
This is a roster snapshot, not a confirmed starting five. Substitutes are listed too, so player_ids usually holds 6 or 7 ids and can hold anywhere from 1 to 11 — never assume a length of 5. The five who actually played are the player rows on /stats; compare the two to see who was benched or who stood in.
A new row is written only when a team's roster differs from its previous snapshot, so most teams have exactly one row per match, and a second row means the roster changed in the run-up. An old captured_at is therefore not staleness.
Coverage starts on 2026-07-09 and reaches roughly 6 in 10 matches since then; every earlier match returns an empty list. data_available.lineups and ?has=lineups tell you which. An unknown match id also returns an empty list.
Primary auth (live). Authorization: Bearer <api-key> — the header takes precedence over the query fallback. The raw key is hashed (SHA-256, hex) and looked up in api.keys.key_hash; the raw value is never stored.
In: header
Path Parameters
Game slug. cs2 is the only populated title today; an un-onboarded game 404s cleanly.
Resource identifier — either a UUID or the resource's human-readable slug, scoped to {game}. /v1/cs2/teams/natus-vincere and /v1/cs2/teams/019f23d1-fb5c-7987-b522-47c3a5e72111 address the same row, so you can go straight from a slug you already have without first looking up its id.
Slugs work on teams, players and tournaments. Matches have no slug, so a match id must be a UUID. Either way, an identifier that resolves to nothing returns 404 not_found.
Response Body
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/v1/cs2/matches/019f2858-e253-7f3d-bdff-bc7738bd1036/lineups"{ "data": [ { "id": "01a0a6a9-4c97-7277-a184-d9a9089da520", "match_id": "01a0a3e2-96a5-7a9f-8af2-fae0f1a7d678", "team_id": "019f2858-e255-78e4-9e7c-32f307dfac91", "player_ids": [ "019f28e2-22cb-74ea-af0f-0408f360cec2", "019f28e2-22cb-7de3-b94b-7652094f468c", "019f28e2-76af-7029-97b5-70686851cd14", "019f28e2-76af-707f-95ed-e47bae9e065f", "019f28e2-76af-70fb-96fe-9452dbabbdf5", "019f28e2-76af-7611-8aea-7794acc0c0bc", "019f2b8f-1e66-78cf-bc47-73b061cf0337" ], "captured_at": "2026-09-15T20:00:31.524108Z" }, { "id": "01a0a6a9-4c97-7dad-ab66-a95f39035e05", "match_id": "01a0a3e2-96a5-7a9f-8af2-fae0f1a7d678", "team_id": "01a0a3e2-96a0-7bf7-986c-6a68e151de5c", "player_ids": [ "019f28e1-e6af-7c9e-9dbf-9f83509caa47", "019f2bda-1afe-7645-b9dd-b05c9a89b19e", "01a0a3e2-96a0-7b37-8172-f2fae5cb4679", "01a0a583-31b0-7603-9de3-48bbbae8b4f2", "01a0a58a-0fb1-7520-b152-6649c8738d94" ], "captured_at": "2026-09-15T20:00:31.524108Z" } ], "meta": { "count": 2, "next_cursor": null }}{ "error": { "code": "not_found", "message": "not found", "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578" }}{ "error": { "code": "not_found", "message": "not found", "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578" }}{ "error": { "code": "rate_limited", "message": "rate limit exceeded", "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578" }}A single match GET
One match by id, with the same fields as a list row minus the denormalised names — a detail row carries bare `team_a_id`/`team_b_id`/`tournament_id`, so resolve those separately or read them off the list route instead. The `data_available` flags tell you which sub-resources (`maps`, `stats`, `map_stats`, `vetoes`, `rounds`, `depth`, `lineups`, `odds`) actually exist for this match, so you can skip requests that would return an empty list. Pass `include=` to embed related resources or the sub-resources themselves in this one response.
Per-map scores for one match GET
Map-by-map results (half/overtime splits included when known), ordered by map number. Unknown match id yields an empty list. Enveloped: `{"data": [MapResult, ...], "meta": {...}}` (not cursor-paginated; `next_cursor` is null).