Skip to main content

Why scopes

Same URL, different field set per caller. A bookmaker on cs2.odds.basic calling GET /cs2/v1/matches/{id} gets the markets and rounds. A stats consumer on cs2.stats calling the same URL gets the stats but no markets. An internal operator calling it gets everything plus operational fields. One URL, one serializer, scope-filtered output. Use /v1/whoami to introspect what your key currently grants.

Bundles

Bundles are issuance shorthand — pick one (or several) at key creation, the system expands them to a flat scope list. There is no “bundle” entity in the database — just the resulting scope set on your key.

Granular scopes

Format: cs2:{resource}:{action}. Keys can also be issued with raw scopes a la carte (e.g. add cs2:matches:scoreboard to a stats key on request). cs2 and soccer are the live public sport namespaces today. Treat GET /v1/sports as the source of truth before using any future sport namespace. Dota 2 scope strings exist only as internal groundwork until the Dota router is deliberately mounted.

Scope → fields

The same URL emits different fields depending on which scopes you have. Fields outside your scope set are simply absent from the response — not nulled, just not emitted.

Example: GET /cs2/v1/matches/{id}

The same logic applies to Round, Stream, Market, and other shapes. Detailed mappings live alongside the corresponding endpoint pages in the API Reference.

Content negotiation

Every REST endpoint serves both JSON (default) and XML. Pass Accept: application/xml and the response body comes back as XML on the same URL. The seven AMQP-feed endpoints additionally expose a .xml sibling URL for clients whose HTTP infrastructure prefers a distinct cache key per format.

Two XML dialects

Feed XML endpoints

These use hand-tuned envelopes that match the AMQP feed byte-for-byte — useful for clients that already have an UOF-style XML pipeline.

Stats XML

Every other endpoint produces a mechanical XML rendering of the JSON shape. Example: GET /cs2/v1/teams/11712 with Accept: application/xml returns:
Rules: scalars become attributes, nested dicts become child elements, lists become wrapper elements with singularised item tags, null is elided. There is no XSD for this dialect today — consumers parse it via XPath / element-tree.
Pass the Accept: application/xml header on any GET, or use the .xml URL form on the seven feed endpoints. Errors (4xx/5xx) keep the JSON {"detail": "..."} shape regardless of Accept so error parsing stays uniform.
WebSocket frames are JSON only.
Last modified on June 21, 2026