A single match
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`, `vetoes`, `rounds`, `depth`) actually exist for this match, so you can skip requests that would return an empty list.
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, vetoes, rounds, depth) actually exist for this match, so you can skip requests that would return 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.
Query Parameters
Comma-separated related resources to embed inline: teams (adds team_a/team_b), tournament, and odds (the latest derived line per outcome). include=teams,tournament,odds turns the four requests a match view needs into one. Unknown names are ignored rather than rejected, so adding an expansion later never breaks an existing client. Omit it and the response is exactly as before — every embedded field is absent, not null.
Only the detail route offers this: a match row from /v1/{game}/matches already carries team_a_name, team_b_name, team_a_short, team_b_short and tournament_name denormalised, whereas the detail route returns bare ids.
Response Body
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/v1/cs2/matches/019f2858-e253-7f3d-bdff-bc7738bd1036"{ "data": { "id": "019f3d18-c15f-7319-81a7-343e8a80a578", "game_id": "019f23d1-fb5b-7d24-935d-e4d68f6f565a", "tournament_id": "019f23d1-fb5b-79dc-a1de-f9fa281dd3ea", "team_a_id": "019f2858-e253-7f3d-bdff-bc7738bd1036", "team_b_id": "019f23d1-fb5c-7940-be14-c8b28e2d90e8", "format": "bo3", "status": "completed", "stage": "CCT South America 2026 Series 3 Playoffs", "scheduled_at": "2026-07-08T19:00:00Z", "score_a": 2, "score_b": 0, "winner_team_id": "019f2858-e253-7f3d-bdff-bc7738bd1036", "created_at": "2026-07-07T15:01:00.497296Z", "updated_at": "2026-07-25T23:06:56.921667Z", "data_available": { "maps": true, "stats": true, "vetoes": true, "rounds": true, "depth": true } }}{ "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": "not_found", "message": "not found", "request_id": "019f3d18-c15f-7319-81a7-343e8a80a578" }}Per-player CS2 depth breakdowns for one match GET
The five CS2 depth breakdowns for one match, grouped into a single object: per-player `weapons`, `grenades`, `hitgroups` (body hit-group distribution), `duels` (the killer→victim kills matrix) and `flashes` (the flasher→flashed blind matrix). These are per-MATCH aggregates (not per map). Each group is a flat array whose elements carry their own `player_id` (and, for duels/flashes, the ordered pair of player ids), so a client groups by player itself. A match with no depth on record (older or lower-tier matches — roughly one in six lack it) returns every group as an empty array (never null); an unknown match id does the same. Single-resource envelope: `{"data": {weapons, grenades, hitgroups, duels, flashes}}`.
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).