Known limitations
What the API doesn't do today, stated plainly so you find out before you build.
This page exists because discovering a gap after you've built around it is worse than reading about it now.
Not served
Per-book odds. One de-vigged aggregate line, never individual bookmaker prices or names. Not a roadmap item — it's a product decision.
The model line. eo_model returns an empty page until it clears its accuracy gate.
/v1/cs2/model/metrics shows the current standing, and it currently says the model isn't good
enough.
Team logos. logo_url exists but is always empty — no redistribution rights.
Market metadata. You get market_id on each odds line, which is enough to group them, but
there's no endpoint listing markets or market types.
Thin or absent data
seed on tournament participants is always null. No upstream we ingest publishes seeding, so
it's reserved rather than populated. Don't order participants by it.
role on players is populated on roughly 14% of players — a ?role= filter excludes everyone
whose role is simply unknown, which is most of them.
Per-player depth (weapons, grenades, hitgroups, duels, flashes) is the least universal layer.
Check data_available.depth before requesting it.
Depth is match-level, not per-map. The upstream exposes it per match, so per-map weapon usage isn't available.
started_at is present on about 42% of completed matches. Only matches we were watching while
they ran carry one, and it is never back-guessed from scheduled_at — a null means we don't know,
not that the match never started. Two shapes surprise people: it can fall a minute or two before
scheduled_at, because series genuinely open early, and a postponed match that returns to
scheduled has it cleared back to null along with its score.
Shape constraints
No total count on lists. meta.count is the page size, not the size of the set — counting the
whole set costs a second query most callers don't want.
No random-access pagination. Cursors are forward-only; you can't jump to page 7. That's the trade for correctness under concurrent writes.
/odds bulk snapshot and /rankings don't paginate. limit truncates silently.
No sparse fieldsets. There's no ?fields= — responses are complete or nothing.
No conditional requests. No ETag or If-Modified-Since, so you can't cheaply ask "has this
changed". Use changed_at on a match, or ask for only what moved with ?changed_since= — see
pull the historical corpus. Don't use updated_at for this: it
advances on every refresh pass whether or not anything changed.
Compression on the bulk route only. /matches/bulk honours Accept-Encoding: gzip; every other
response is uncompressed JSON.
Sorting
sort= exists on /teams, /players, /rankings and /matches (including /matches/bulk) only,
with a small allowlist of keys per endpoint. Player performance metrics aren't sortable on the players list — they live on match stats,
not the player row. Use /rankings?type=player for a performance-ordered board.
Live data
The WebSocket carries ingestion-cadence updates, not sub-second ticks. The protocol is final; the tick rate improves when the underlying service ships.
If one of these blocks you
Several are "not yet" rather than "never" — tell us which one and why. Knowing what people are actually blocked on is how this list gets shorter.