Status and support
Checking whether it's us, and what to include when it is.
Is the API up?
curl -sS https://api.esportsodds.gg/health
# {"status":"ok"}/health needs no API key, isn't metered, and returns 503 with {"status":"unavailable"} when
the service is up but can't reach its database. It's the right thing to point a monitor at.
Note it's the one endpoint without the {data, meta} envelope — it's a probe, and keeping it
trivial is the point.
For history and incidents: status.esportsodds.gg.
Is it me?
Work down this list before reporting a problem:
| Symptom | Most likely cause |
|---|---|
| Everything 401s | Key not sent as Authorization: Bearer <key>, or rotated more than 24h ago |
| Everything 429s | Check error.code — quota_exceeded means out of requests, not overloaded |
| One endpoint 404s | A malformed id, or a slug on /matches (matches have no slug) |
| Empty arrays everywhere | Filters too narrow, or a sub-resource with no data — check data_available |
eo_model returns nothing | Expected — the model line isn't served yet |
Troubleshooting covers each of these properly.
What data coverage exists
/v1/{game}/coverage states what the product actually has, per capability, with an honest status:
curl -H "Authorization: Bearer $ESPORTSODDS_API_KEY" \
"https://api.esportsodds.gg/v1/cs2/coverage"live means available now. pending_validation means built but held back until it clears an
accuracy bar. schema_ready means the shape exists but isn't populated. planned means intended,
not built. licence_required means blocked on rights rather than engineering.
It's a deliberately unflattering endpoint — it tells you what we don't have as clearly as what we do, so you can find out before you build rather than after.
How fresh each capability actually is
Every coverage row also carries a freshness object: measured p50_seconds, p90_seconds and
p99_seconds over a recent window, the sample behind them, and a basis naming the two instants
measured.
{
"capability": "results",
"cadence_seconds": 300,
"freshness": {
"basis": "from a match's end time to us first publishing it as completed",
"p50_seconds": 412, "p90_seconds": 980, "p99_seconds": 4211,
"sample": 143, "window_days": 30, "note": null,
"measured_at": "2026-09-20T17:00:00Z"
}
}Four things worth knowing before you quote these numbers back at us:
- They are observations, not a service level. There is no latency SLA on any plan. The window describes matches that already finished; nothing is promised about the next one.
- Null is a real answer, and 0 never stands in for it. The three percentiles are null together
when the window holds nothing yet, and
notesays why. Several figures derive from our own change history, which starts when we began recording it, so they fill in over the following days rather than arriving complete.window_daysis how much is genuinely covered. - They err slow. A late correction or a repair inside the window pushes a figure up. We don't drop late arrivals, so the p99 is the real tail rather than a trimmed one.
cadence_secondsis a different number — how often a collector runs, not how long anything waited.
One row carries no percentile: live round score. Each score states its own age instead —
live_state.as_of is the round-level feed's timestamp for it — but we keep only a match's current
live state, not a history of past ones, so there is no window of samples to take a percentile over.
That row says so in its note.
Uptime is not on this endpoint
Coverage publishes freshness, not availability. We do not publish an uptime percentage, because
the monitor we would compute it from runs on the same machine as the API — a box-level outage is
invisible to it, and it has recorded healthy beats straight through a real one. Point your own
monitor at /health and trust that instead of a number we grade ourselves on.
Reporting a problem
Include the X-Request-Id. Every response carries one, and it's repeated in error.request_id
on failures. With it we can find the exact request in our logs; without it we're matching on a
timestamp.
A good report is: the request id, the URL you called (minus your key), what you expected, and what you got.
On a Pro plan we aim to send a first reply within 1 business day, and to fix or explain a data gap you report within 2 business days (UK business days). These are targets, not a service level agreement.
Notifications
Settings → notifications controls the emails we send about your account: a warning at 80% and again at 100% of your monthly requests, the getting-started and follow-up emails, and notices of API changes. The emails that are not sign-in links or billing notices carry an unsubscribe link that switches off the matching setting. The API change notices are how a deprecation would reach you — see the deprecation policy — so they are worth leaving on.