Rankings

Team or player rankings (leaderboard)

Ranked leaderboard over a rolling 3-month window.

GET
/v1/{game}/rankings

Ranked leaderboard over a rolling 3-month window. ?type=team (default) or ?type=player — the two are ranked on different metrics, reported in each row's metric field.

Teams rank on glicko2_conservative: a Glicko-2 rating discounted by twice its rating deviation (rating − 2·RD), so a team with a volatile, thinly-evidenced rating sorts below an equally-rated team the model is confident about. Players rank on rating.

Sorting rows by value reproduces rank exactly. Entities below the sample floor are omitted rather than ranked on noise: teams need at least 5 rated matches in the window, players at least 30 rated maps. A map counts once, from its own per-map rating, and only if it was played on a competitive map — the whole-match summary stored beside a player's maps is neither counted nor averaged. This is always our own rating, never a third party's — a team's separately-sourced external_rank is reported alongside for comparison, not used for ordering. Not cursor-paginated: limit truncates the computed board and meta.next_cursor is always null.

Team rows carry rank_delta, the movement against seven days ago by default; delta_days sets how far back it looks. include=trend adds trend, the board metric at each of the last twelve weekly marks, and include=rating adds rating and rd, the Glicko-2 rating and deviation behind value. None of them changes the board itself, and without them the response is unchanged. For the board's top over a longer span use /rankings/history.

Authorization

AuthorizationBearer <token>

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. To try the API with no account, use the public sample key eo_sample_public: one published key, shared by everyone, that reads a fixed sample of past matches within daily limits. For evaluation; our Terms apply.

In: header

Path Parameters

game*string

Game slug. cs2 is the only populated title today; an un-onboarded game 404s cleanly.

Query Parameters

type?string

Which leaderboard to return: team (the default) or player. The two rank on different metrics — teams on a confidence-discounted Glicko-2 rating, players on their rating — and each row reports which in its metric field.

Default"team"

Value in

  • "team"
  • "player"
region?string

Filter to one circuit region. Values are full names, not codes — Europe, North America, South America, Asia, CIS, Oceania, Africa. Exact match, so EU matches nothing.

role?string

Filter by player role (type=player).

sort?string

Ordering. rank (default), value or name, each reversible with a - prefix. Re-sorting changes the order rows come back in, never the rank each entity holds — so sort=-rank returns the bottom of the board with its real ranks. An unrecognised key returns 400.

delta_days?integer

How many days back rank_delta compares against (teams only): a whole number from 1 to 90. Default 7. Anything else is a 400 naming the parameter.

Range1 <= value <= 90
Default7
include?string

Optional extras, comma-separated. trend adds the board metric at each of the last twelve weekly marks to team rows, oldest first and ending now. rating adds the Glicko-2 rating and its deviation rd to team rows. Both are opt-in so the default response does not grow; an unknown name is ignored.

limit?integer

Page size. The default and maximum vary per endpoint — this shared definition documents the common case (default 100, max 500); each operation that differs states its own numbers. cursor carries the page position, not limit.

A value above the endpoint's maximum is silently clamped, not rejected. A missing, zero, negative or non-numeric value silently falls back to the default — so ?limit=abc and ?limit=0 both return the default page size rather than a 400. Read meta.count if you need to know how many rows you actually got.

Range1 <= value
Default100

Response Body

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/cs2/rankings"
{  "data": [    {      "rank": 1,      "entity_type": "team",      "entity_id": "019f23d1-fb5c-7be8-b53d-f9801eb21ee6",      "name": "Vitality",      "slug": "vitality",      "region": "Europe",      "country_code": "FR",      "role": null,      "metric": "glicko2_conservative",      "value": 1922.5,      "window": "3mo",      "external_rank": 3,      "form": [        "L",        "L"      ],      "rank_delta": 0    },    {      "rank": 2,      "entity_type": "team",      "entity_id": "019f23d1-fb5c-7a98-97da-542fb409d0ad",      "name": "Spirit",      "slug": "spirit",      "region": "CIS",      "country_code": "RU",      "role": null,      "metric": "glicko2_conservative",      "value": 1909.5,      "window": "3mo",      "external_rank": 1,      "form": [        "W",        "L"      ],      "rank_delta": 0    }  ],  "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"  }}