Edge Model Public API
Read-only access to championship probabilities, standings, and model-vs-market divergence. All endpoints require a Bearer token.
https://www.edgemodel.techIntroduction
The Edge Model API provides programmatic access to the same Bayesian predictions shown in the web app. Data is updated automatically as match results are recorded — typically within minutes of a final whistle.
API keys are issued by the Edge Model team. Contact support@edgemodel.tech to request access.
Authentication
Pass your API key in the Authorization header on every request:
Authorization: Bearer em_your_key_here
Example with curl:
curl https://www.edgemodel.tech/api/v1/presets \ -H "Authorization: Bearer em_your_key_here"
Example with Python:
import requests
headers = {"Authorization": "Bearer em_your_key_here"}
r = requests.get("https://www.edgemodel.tech/api/v1/presets", headers=headers)
print(r.json())
Rate limits
60 requests per minute per API key. Exceeding the limit returns HTTP 429. The limit resets every 60 seconds.
| Header (on 429) | Meaning |
|---|---|
| Retry-After | Not currently set — wait 60 s and retry |
Error format
All errors return JSON with an error field:
{"error": "No saved state for preset 'epl-2026-27' — check /api/v1/presets for valid ids"}
| Status | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 404 | Preset not found or no saved state for that preset |
| 429 | Rate limit exceeded |
List presets
Returns all active competition presets — league and tournament — with their metadata. Use the id field in subsequent calls to /api/v1/league/{id}/state and /api/v1/league/{id}/edge.
Example response
{
"presets": [
{
"id": "epl-2026-27",
"name": "Premier League 2026-27",
"description": "Premier League · 20 clubs · 2026-27",
"icon": "🏴",
"n_teams": 20,
"format": "league",
"sport": "soccer",
"has_state": true
},
...
]
}
| Field | Type | Description |
|---|---|---|
| id | string | Preset identifier — use this in other endpoints |
| name | string | Human-readable competition name |
| format | "league" | "tournament" | Competition type |
| sport | string | Sport (e.g. "soccer", "basketball_nba") |
| has_state | boolean | Whether results have been recorded and a state exists |
League state
Returns the full league state for a preset: standings, Bayesian parameter posteriors, championship probabilities, and result history.
Replace {id} with a preset id from /api/v1/presets — e.g. /api/v1/league/epl-2026-27/state.
Example request
curl "https://www.edgemodel.tech/api/v1/league/epl-2026-27/state" \ -H "Authorization: Bearer em_your_key_here"
Example response
{
"preset_id": "epl-2026-27",
"meta": {
"id": "epl-2026-27",
"name": "Premier League 2026-27",
"n_teams": 20,
"rounds": 2,
"total_matches": 380,
"matches_played": 47,
"scoring": {"win": 3, "draw": 1, "loss": 0}
},
"teams": [
{
"name": "Arsenal",
"played": 13,
"wins": 9,
"draws": 2,
"losses": 2,
"points": 29,
"gf": 28,
"ga": 14,
"gd": 14,
"attack_mean": 1.92,
"defense_mean": 0.87
},
...
],
"history": [
"Arsenal|2-1|Chelsea",
"Man City|0-0|Liverpool",
...
]
}
| Field | Type | Description |
|---|---|---|
| teams[].name | string | Team name as used in the preset |
| teams[].points | int | League table points |
| teams[].gd | int | Goal difference |
| teams[].attack_mean | float | Posterior mean attack rate (goals/game) |
| teams[].defense_mean | float | Posterior mean conceding rate (goals/game) |
| history[] | string[] | Results in Home|score-score|Away format |
Model-vs-market divergence
Returns unplayed fixtures where the model's win probability diverges from market-implied probability by at least the given threshold. Only fixtures with available market odds are included.
Query parameters
| Param | Default | Description |
|---|---|---|
| threshold | 0.05 | Minimum edge (absolute probability difference) to include. Range 0–1. |
Example request
curl "https://www.edgemodel.tech/api/v1/league/epl-2026-27/edge?threshold=0.08" \ -H "Authorization: Bearer em_your_key_here"
Example response
{
"preset_id": "epl-2026-27",
"threshold": 0.08,
"odds_available": true,
"fixtures": [
{
"home": "Arsenal",
"away": "Chelsea",
"commence_time": "2026-09-15T19:45:00Z",
"model": {"home": 0.5431, "draw": 0.2341, "away": 0.2228},
"market": {
"home": {"implied_prob": 0.4521, "odds": 2.21},
"draw": {"implied_prob": 0.2688, "odds": 3.72},
"away": {"implied_prob": 0.2791, "odds": 3.58}
},
"edge": {"home": 0.091, "away": -0.0563}
}
]
}
| Field | Description |
|---|---|
| odds_available | False if The Odds API key is absent or the competition has no market data |
| model.home/draw/away | Model probability for each outcome (sums to ~1) |
| market.home.implied_prob | Vig-adjusted implied probability from best available decimal odds |
| market.home.odds | Best decimal odds across tracked bookmakers |
| edge.home | model.home − market.home.implied_prob (positive = model more bullish on home win) |
Create API key (admin)
Generates a new API key. Requires an active admin session (not a Bearer key — admin login via the web app). Keys are not stored in plaintext after creation.
Request body
{"label": "My integration"}
Response
{"ok": true, "key": "em_a1b2c3d4...", "label": "My integration"}
List API keys (admin)
Lists all issued API keys with their labels and creation dates. Requires an active admin session.
Response
{
"keys": [
{
"key": "em_a1b2c3d4...",
"label": "My integration",
"created": "2026-09-03T10:00:00Z"
}
],
"count": 1
}