The opponents a team meets most often
The opponents a team has met most often, most meetings first. A rival is an opponent met at least `min_meetings` times (default 2) in decided, played matches inside the window (default the last 36 months). Each row gives the head-to-head split, the date of the last meeting, the most recent ten meetings oldest to newest as won/lost booleans, and `avg_rating_gap`: the opponent's rating minus the team's going into each meeting, averaged over only the `rated_meetings` where both teams had a rating then. It is `null` when no meeting had both, never zero. A negative gap means the team was the higher-rated side on average. For the meetings themselves, with scores, maps and both ratings, call `/teams/{id}/results?opponent=`. `limit` default 5, maximum 20. Enveloped `{"data": [TeamRival, ...], "meta": {...}}`.
The opponents a team has met most often, most meetings first. A rival is an opponent met at least min_meetings times (default 2) in decided, played matches inside the window (default the last 36 months).
Each row gives the head-to-head split, the date of the last meeting, the most recent ten meetings oldest to newest as won/lost booleans, and avg_rating_gap: the opponent's rating minus the team's going into each meeting, averaged over only the rated_meetings where both teams had a rating then. It is null when no meeting had both, never zero. A negative gap means the team was the higher-rated side on average. For the meetings themselves, with scores, maps and both ratings, call /teams/{id}/results?opponent=. limit default 5, maximum 20. Enveloped {"data": [TeamRival, ...], "meta": {...}}.
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.
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.
Query Parameters
How many rivals to return. Default 5, maximum 20. Not paginated.
1 <= value <= 205The fewest meetings an opponent needs to count as a rival: a whole number from 1 to 50. Default 2. Anything else is a 400 naming the parameter.
1 <= value <= 502The trailing span of matches the figures cover: a whole number of months with an m suffix, such as 6m, up to 120m, or all for the whole history. Default 36m. Anything else is a 400 naming the parameter.
"36m"Response Body
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/v1/cs2/teams/019f2858-e253-7f3d-bdff-bc7738bd1036/rivals"{ "data": [ { "opponent": { "id": "019f23d1-fb5c-738b-8ca9-2e78eaeb5b42", "name": "MOUZ", "slug": "mouz-cs2" }, "meetings": 19, "wins": 14, "opponent_wins": 5, "last_meeting_at": "2026-09-05T16:45:00Z", "avg_rating_gap": -96.61298197407216, "rated_meetings": 19, "results_oldest_first": [ false, true, true, true, true, false, true, false, true, true ] }, { "opponent": { "id": "019f23d1-fb5b-7963-9295-da73d11ba912", "name": "FaZe", "slug": "faze" }, "meetings": 16, "wins": 12, "opponent_wins": 4, "last_meeting_at": "2026-08-20T13:25:00Z", "avg_rating_gap": -108.76017881012469, "rated_meetings": 16, "results_oldest_first": [ true, true, true, false, true, true, true, false, true, true ] }, { "opponent": { "id": "019f23d1-fb5c-782d-be6f-5314d5adc883", "name": "The MongolZ", "slug": "the-mongolz" }, "meetings": 15, "wins": 13, "opponent_wins": 2, "last_meeting_at": "2026-03-21T21:10:00Z", "avg_rating_gap": -155.23871385509048, "rated_meetings": 15, "results_oldest_first": [ true, true, true, true, false, false, true, true, true, true ] } ], "meta": { "count": 3, "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": "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 team's recent results GET
A team's completed, decided matches, newest first — the rows of a results table. Each carries the opponent, the tournament and stage, the series score, every played map's score from the team's side, and both teams' ratings going into the match. `rating_before` and `opponent_rating_before` are the latest Glicko-2 state strictly before the match started, so a result never contains its own outcome. A side with no earlier rated match has `null` there, never a default rating. Walkovers are awarded rather than played, so they are not listed, and neither is a match with no recorded winner; a forfeited or abandoned map is left out of `maps`. `opponent` (a team id or slug) narrows the list to one rivalry. `limit` default 20, maximum 100. Enveloped `{"data": [TeamResult, ...], "meta": {...}}` (not cursor-paginated).
A team's roster timeline (the five it actually fielded) GET
The five players a team actually fielded in each recent completed match, newest first, with the derived roster-change facts. `limit` default 20, max 100. Enveloped `{"data": [TeamRosterEntry, ...], "meta": {...}}` (not cursor-paginated). Read `continuity` BEFORE interpreting `changed_count`: `stable` (same five as last match), `changed` (1–4 players swapped — the only value for which `has_debutant` is asserted), `reset` (all five swapped, i.e. an organisation rename or full rebuild, NOT five stand-ins), `resumed` (previous match beyond a 60-day gap — a transfer window, not a stand-in), and `new` (no prior match, so `players_in`/`players_out` are empty because there is no baseline to diff against). A match where a team used more than five players across maps is omitted rather than guessed at.