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.
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.
The primary way to authenticate: Authorization: Bearer <api-key>. When a request also carries ?apiKey=, the header wins. We store only a SHA-256 hash of a key, never the key itself.
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.
A team or a player also answers to a slug it was renamed away from, as long as no current team or player holds that slug — so a link made before a rename keeps working. The row returned carries its current slug.
Response Body
application/json
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": "match_merged", "message": "this match id was merged into 01a0d06b-4e06-7e01-905d-7384ae3c7ce1; use that id", "request_id": "01a12d10-6b2e-7d3a-9a4f-2c1d0e9b8a77" }}{ "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" }}