Core concepts

The model line and its validation gate

eo_model, why it isn't served yet, and how to read the accuracy we publish.

source: "eo_model" is our own forecast, as distinct from the market line, which describes what bookmakers think.

It is not served yet

Requesting it returns an empty page:

curl -H "Authorization: Bearer $ESPORTSODDS_API_KEY" \
  "https://api.esportsodds.gg/v1/cs2/odds?source=eo_model"
# 200 { "data": [], "meta": { "count": 0, "next_cursor": null } }

That's a 200, not an error — the source is valid, there is simply nothing to return until the model clears its accuracy gate. Write your client to tolerate an empty page for this source; it will start returning rows without any API change on your side.

Why a gate exists at all

The market line needs no accuracy gate: it is descriptive, a measurement of prices that existed. A forecast is a claim, and shipping a claim we haven't tested would be the easiest thing in this product to get wrong quietly. So the model is held behind a published, numeric bar.

The bar

Accuracy is scored with the Brier score — the mean squared error of forecast probabilities. Lower is better; 0 is perfect. For a two-way market, always guessing 50/50 scores 0.25, so 0.25 is the no-skill baseline a forecast has to beat.

The gate requires the upper bound of the confidence interval to sit below that baseline, not just the point estimate — a lucky score over a small sample with a wide interval does not pass — and a minimum sample of several hundred settled matches.

Reading the published metrics

/v1/{game}/model/metrics is the transparency surface, and it is not gated — you can read the model's score before the model itself is served:

{
  "market": "match_winner",
  "brier": 0.2814810548009245,
  "brier_skill_score": -0.125924219203698,
  "settled_matches": 514,
  "model_version": "v0-placeholder",
  "gate_passed": false
}

That is the honest current state, not an illustration. Reading it:

  • brier 0.281 is worse than the 0.25 baseline.
  • brier_skill_score is 1 − brier/0.25, so positive means better than a coin flip. −0.126 means worse.
  • gate_passed: false — so nothing is served.

We publish this rather than a headline number precisely because it currently says the model isn't good enough. When that changes, the same endpoint will say so with the same fields.

What to build now

Treat eo_model as a source that may start returning rows later. Two habits make that free:

  1. Don't hardcode source=eo_market in a way that would need a rewrite — filter explicitly, and handle an unfamiliar source value by ignoring it rather than erroring.
  2. Colour or label model data distinctly from market data in any UI. They answer different questions and shouldn't be visually merged.

On this page