Feed vitals
⚡ Steam moves · last 60m
≥3% swing⏱ Starting soon
next kick-offs◍ Coverage
top sportsAPI keys
| Label | Key | Status | Rate limit | Today | Total | Last used | |
|---|---|---|---|---|---|---|---|
| Loading… | |||||||
Your plan
Quick start
curl -H "X-Api-Key: YOUR_KEY" \
https://your-host/api/v1/events?live=1
// real-time push
const es = new EventSource('/api/v1/stream?api_key=YOUR_KEY');
es.addEventListener('live', (e) => {
const { events } = JSON.parse(e.data);
});
API Documentation
Authentication
Pass your API key in the X-Api-Key header (or as a Bearer token). Keys are created under API Keys. Limits depend on your plan:
| Plan | Rate limit | Daily quota | Keys |
|---|---|---|---|
| free | 60 req/min | 20,000 | 2 |
| pro | 300 req/min | 500,000 | 5 |
| enterprise | 1000 req/min | 5,000,000 | 20 |
curl -H "X-Api-Key: sb_live_xxxxxxxx" \ "https://your-host/api/v1/events?live=1"
Endpoints
GET /api/v1/sports
List all sports with current event and championship counts.
{
"data": [
{ "id": 1, "name": "Football", "events": 2370, "championships": 387 }
]
}
GET /api/v1/events
Paginated event list with odds markets. Supports filtering and delta sync.
| Param | Description |
|---|---|
| live | 1 only live, 0 only pre-match |
| sport_id | Filter by sport (see /sports) |
| league | Substring match on league name |
| updated_after | Unix ms — delta sync: only events updated after this timestamp |
| markets | 0 to exclude odds (smaller payloads) |
| page, limit | Pagination (limit ≤ 500, default 100) |
{
"page": 1, "limit": 100, "total": 2381, "pages": 24,
"data": [{
"id": 739473824,
"sport_id": 1, "sport": "Football",
"league_id": 122768, "league": "England. Premier League",
"home": "Arsenal", "away": "Chelsea",
"start": 1786485600, "start_iso": "2026-08-10T14:00:00.000Z",
"live": false, "state": null, "score": null,
"markets": [
{ "market": "1x2", "selection": "1", "line": null, "price": 2.02 },
{ "market": "total", "selection": "over", "line": 2.5, "price": 1.85 },
{ "market": "handicap", "selection": "1", "line": -0.5, "price": 2.02 }
],
"updated_at": 1786480000000
}]
}
GET /api/v1/live
Live events with scores and in-play markets, ordered by freshness.
{
"data": [{
"id": 740111222, "sport": "Football",
"home": "Real Madrid", "away": "Barcelona",
"live": true, "state": "1st half",
"score": { "home": 1, "away": 0 },
"markets": [ /* in-play odds */ ]
}]
}
GET /api/v1/events/:id/history
Odds movement timeline for an event — every price change we observed, oldest first. Filter with market, cap with limit (≤ 5000). Retained for 7 days.
{
"data": [
{ "market": "1x2", "selection": "1", "line": null, "price": 2.02, "ts": 1786480000000 },
{ "market": "1x2", "selection": "1", "line": null, "price": 1.95, "ts": 1786480900000 }
]
}
GET /api/v1/events/:id/opening
The opening line — first-seen odds for every market of the event, with the timestamp we first observed them. Derived from the same 7-day store as /history.
{
"data": [
{ "market": "1x2", "selection": "1", "line": null, "opening_price": 2.10, "opening_ts": 1786470000000 }
]
}
GET /api/v1/events/:id/closing
The closing line — one full-market snapshot captured shortly before kickoff (~15 min out), kept permanently. This is the reference price for closing-line value (CLV) analytics. Returns 404 until the event’s snapshot is captured.
{
"captured_at": 1786484100000,
"data": [
{ "market": "1x2", "selection": "1", "line": null, "closing_price": 2.04 },
{ "market": "total", "selection": "over", "line": 2.5, "closing_price": 1.83 }
]
}
GET /api/v1/events/:id/compile — odds compilation toolkit
A pricing desk in one call for sportsbooks: the current line with opening price, drift and the captured closing price, no-vig fair probabilities (three devig methods), and ready-to-publish odds with your chosen margin re-applied (three margin methods) — each with clv_pct, the edge of your compiled price over the market close.
| Param | Description |
|---|---|
| market | Market name to compile (default 1x2) |
| margin | Target margin % for compiled odds, 0–30 (default 5) |
| devig | Fair-prob method used as compilation base: shin (default) | proportional | power |
| line | For lined markets (totals/handicaps); defaults to the median available line |
{
"event": { "id": 739473824, "home": "Arsenal", "away": "Chelsea", "live": false },
"market": "1x2", "line": null, "margin_pct": 5, "devig": "shin",
"overround_pct": 5.4,
"closing_captured_at": 1786484100000,
"raw": [
{ "selection": "1", "price": 2.02, "opening_price": 2.10, "opening_ts": 1786470000000, "drift_pct": -3.81, "closing_price": 2.04 },
{ "selection": "x", "price": 3.60, "opening_price": 3.50, "opening_ts": 1786470000000, "drift_pct": 2.86, "closing_price": 3.55 },
{ "selection": "2", "price": 3.90, "opening_price": 3.80, "opening_ts": 1786470000000, "drift_pct": 2.63, "closing_price": 3.95 }
],
"fair": {
"shin": [{ "selection": "1", "probability": 0.4621, "odds": 2.16 }, /* x, 2 */ ],
"proportional": [{ "selection": "1", "probability": 0.4623, "odds": 2.16 }, /* x, 2 */ ],
"power": [{ "selection": "1", "probability": 0.4618, "odds": 2.17 }, /* x, 2 */ ]
},
"compiled": {
"proportional": [{ "selection": "1", "implied_pct": 48.54, "odds": 2.06, "clv_pct": 0.98 }, /* x, 2 */ ],
"power": [{ "selection": "1", "implied_pct": 48.60, "odds": 2.06, "clv_pct": 0.98 }, /* x, 2 */ ],
"favourite_longshot": [{ "selection": "1", "implied_pct": 48.30, "odds": 2.07, "clv_pct": 1.47 }, /* x, 2 */ ]
}
}
Devig methods: proportional normalizes implieds; power raises them to k (Σπ^k = 1); shin solves Shin’s (1993) z-parameter and is most robust to favourite–longshot bias. Margin methods re-apply your vig: proportional equal margin on every selection, power multiplicative, favourite_longshot shifts half the margin onto longshots. clv_pct = (your odds / closing price − 1) × 100 — positive means your published price beats the market close.
GET /api/v1/stream — real-time push
Server-Sent Events stream. On connect you receive a snapshot event with all live events; afterwards a live event is pushed whenever any score or match state changes. Keep-alive ping events arrive every 25s. Browser EventSource cannot set headers, so pass the key as ?api_key= (max 3 concurrent connections per key).
const es = new EventSource('/api/v1/stream?api_key=YOUR_KEY');
es.addEventListener('snapshot', (e) => renderAll(JSON.parse(e.data).events));
es.addEventListener('live', (e) => applyDiff(JSON.parse(e.data).events));
Market types
Odds are normalized to these market names (unknown upstream types are passed through as type_<code>):
1x2, double_chance, handicap, total, total_odd_even, individual_total_1, individual_total_2, team_total_1, team_total_2, handicap_1x2, goal_total, double_chance_total, both_teams_to_score, winner, race_to
Each market entry has market, selection, optional line (handicap/total value), upstream group and price.
Upcoming fixtures in the deep-coverage sports (football, ice hockey, basketball, tennis, baseball, volleyball, table tennis, american football, esports, cricket) are additionally enriched with full market depth (hundreds of markets per event, refreshed every few minutes). Events carrying deep data have "deep_markets": true.
Errors
401 missing or invalid API key 403 key disabled 404 resource not found 429 rate limit or daily quota exceeded (Retry-After header set)
Integration tips
• Prefer /api/v1/stream for live score updates — it pushes diffs instead of requiring polling.
• Poll /api/v1/live every 15–30 seconds as a fallback/sync anchor.
• Use updated_after on /events for cheap incremental pre-match syncs.
• Track line movement via /events/:id/history.
• start is unix seconds; updated_at is unix milliseconds.
• Events that finish/drop off the upstream feed are removed automatically within hours.