Features · Auth, limits, streaming, history

How the esports API works.

The esports data feed developers build on: one bearer token, a versioned snake_case schema, rate limits you can read off every response, and a WebSocket that pushes updates so you stop polling — with six years of Counter-Strike history behind it.

Bearer auth/v1 · snake_caseVisible limitsPush updatesHistory since 2020
Odds · Two lines, one live and one coming

The CS2 odds line

One clean reference line per match — not a shopping list of prices.

eo_marketLive today
The market odds line

At least two books behind every line, refreshed on our ingest cadence, and appended — never overwritten — so history holds.

"source": "eo_market",
"price": 1.72,
"book_count": 4
eo_modelComing soon
Our own modeled line

A predictive line built on the same six years of match history — currently in validation. It ships when it clears our accuracy bar, not before. Until then, it appears nowhere in the API.

"source": "eo_model",
"status": "validating"
# not yet served — no early access
The contract · Four promises the API keeps

Auth, versioning, history & errors

01 / AUTH
One bearer token, any language.

Send Authorization: Bearer <key>. That’s the whole integration story — no OAuth dance, no signing, and an official Python client if you want one. A ?apiKey= query fallback exists for callers that can’t set a header; the header always wins if both are present.

02 / VERSIONING
A schema that will not move under you.

Everything lives under /v1, game-namespaced as /v1/cs2/.... Fields are snake_case, mapping 1:1 onto the underlying columns. A second game adds a namespace; it doesn’t reshape your parser.

03 / HISTORY
Six years of Counter-Strike, not a rolling window.

27,000+ completed matches back to 2020 — 20,000+ of them CS2-era. Odds history is append-only: a line you read last season is still there this one.

04 / ERRORS
Failures you can actually branch on.

Every error returns a coded envelope — {"error": {"code", "message", ...}} — so you branch on a stable code rather than string-matching prose. A request_id comes back on every response, error or not, so one id turns a support question into a single log lookup.

Limits · Two caps, both on every response

Rate limits & monthly quota

A per-key token bucket smooths bursts; a hard monthly quota (50,000 requests on the Standard plan) bounds the bill. Every metered response carries remaining tokens, remaining quota, and the exact reset instant — no guessing, no surprise invoices.

Exceed either cap and you get a 429 with a Retry-After header in seconds.

response headers
$ curl -i -H "Authorization: Bearer $EO_KEY" \
    "api.esportsodds.gg/v1/cs2/matches"

HTTP/2 200
X-RateLimit-Limit: 20        X-RateLimit-Remaining: 19
X-Quota-Limit: 50000         X-Quota-Remaining: 39873
X-Quota-Reset: 2026-08-01T00:00:00Z
wss://api.esportsodds.gg/v1/wsconnected
# 1. mint a short-lived ticket
$ curl -X POST "api.esportsodds.gg/v1/cs2/ws-token"

# 2. connect and subscribe
→ {"subscribe": ["match:019f4ba2"]}

# 3. updates arrive when our feed changes
← {"type": "odds_update", "price": 1.68, ...}
Streaming · Push, so you stop polling

WebSocket push updates

Mint a short-lived ticket, open the socket, subscribe to the matches you care about. When a score or line changes in our feed, it’s pushed to you instead of you burning quota on polls.

Being precise

Matches and the market line are polled by us about once a minute, so freshness is bounded by that cadence, not by a live server connection. Every line carries the age of its inputs (input_oldest_at), typically a few minutes while a match is live. Lines from after the start are kept and flagged in_play. This is a polled feed, not a real-time one.

Depth · Where the data actually stops

CS2 data coverage

Coverage is not uniform, and we’d rather you know that before you build. The gaps cluster in lower-tier events nobody recorded that granularly. We do not synthesize the missing rounds — a gap stays a gap.

Fixtures & results
Every completed match of the 27,000+ carries a winner
~100%
Per-map scores
Completed matches with at least one played map
91.3%
Per-player stats
K/A/D, ADR, KAST, clutches, multi-kills
86.2%
Per-round economy & duels
Thinner — concentrated in top-tier events
varies
27,000+
Counter-Strike matches since 2020
20,000+
CS2-era matches
5,600+
Players
1,800+
Teams
1,100+
Tournaments

Make your first call today

Start free with a sandbox key: a fixed sample of past matches, no card. Then plans from $99/mo, 50,000 requests.