Games. Odds. Outcomes. One API.
Pre-match odds and settlement outcomes for football across 2,000+ leagues. Games, odds from multiple bookmakers, and machine-readable outcomes for bet settlement. You build the sportsbook.
Getting Started
Here's the typical workflow.
The complete workflow
- Get today's games - Find upcoming or live fixtures with
GET /v1/games. Filter by league, date, or status. - Get odds for a game - Fetch pre-match odds with
GET /v1/games/{id}/odds. Each odd references amarket_idfrom our markets table. - After the game finishes, get outcomes - Call
GET /v1/outcomes/{gameId}to get outcomes. Available ~5 minutes after the final whistle. - Settle bets using outcomes - Match each outcome by
market_id+option_name+option_value. Theresultfield tells youwonorlost.
First request
Replace YOUR_KEY with the API key from your dashboard. This fetches today's scheduled games.
curl -G https://api.sportlogic.io/api/v1/games \ -H "X-API-Key: YOUR_KEY" \ --data-urlencode "date_from=2026-04-05" \ --data-urlencode "status=scheduled" \ --data-urlencode "per_page=5"
X-API-Key header. The GET /health endpoint is the only public route - no key needed.
Authentication
Every request requires a valid API key in the X-API-Key header.
Header
| Header | Value | Description |
|---|---|---|
X-API-Key | your_key_here | Required on all endpoints. Obtained when you sign up. |
Auth error codes
| HTTP | Code | Meaning |
|---|---|---|
| 401 | MISSING_API_KEY | No X-API-Key header sent |
| 401 | INVALID_API_KEY | Key not found or deleted |
| 403 | INACTIVE_API_KEY | Key suspended |
Rate Limits & Pricing
Limits are counted per API key per calendar day (UTC). Rate limits are enforced per minute.
| Plan | Price | Daily Limit | Rate Limit |
|---|---|---|---|
Free | $0 | 500 requests/day | 10 req/min |
Basic | $19/mo | 7,500 requests/day | 60 req/min |
Pro | $39/mo | 75,000 requests/day | 300 req/min |
Mega | $59/mo | 150,000 requests/day | 600 req/min |
Response headers
| Header | Description |
|---|---|
X-RateLimit-Limit | Your daily request limit |
X-RateLimit-Remaining | Requests remaining today |
On limit exceeded, the API returns HTTP 429 with error code RATE_LIMIT_EXCEEDED. Resets at UTC midnight.
Pagination
All list endpoints use cursor-based pagination.
Parameters
| Param | Type | Description |
|---|---|---|
| cursor | string | Opaque cursor from previous response's pagination.next_cursor. Omit for first page. |
| per_page | integer | Items per page. Default 50, max 100. |
Response shape
{
"success": true,
"data": [ ... ],
"pagination": {
"next_cursor": "eyJpZCI6MTAwfQ",
"prev_cursor": null,
"has_more": true,
"per_page": 25
}
}
Games
Football game fixtures with scores, status, and odds. The starting point for every workflow.
List games with optional filters. Returns cursor-paginated results ordered by start_time desc.
| Parameter | Type | Required | Description |
|---|---|---|---|
| league_id | integer | optional | Filter by league |
| status | string | optional | scheduled live finished postponed cancelled |
| date_from | date | optional | Format YYYY-MM-DD |
| date_to | date | optional | Format YYYY-MM-DD. Must be ≥ date_from |
| is_live | boolean | optional | Filter to currently live games |
| per_page | integer | optional | 1–100, default 50 |
| cursor | string | optional | Pagination cursor from previous response |
Response fields
- idGame ID, used consistently across odds and outcomes
- statusscheduled · live · finished · postponed · cancelled
- is_liveBoolean, true when game is actively in progress
- start_timeISO 8601 UTC kick-off time
- home_scoreHome goals scored, null if not started
- away_scoreAway goals scored, null if not started
- leagueEmbedded league object (id, name, country)
- home_teamEmbedded team object (id, name, country)
- away_teamEmbedded team object (id, name, country)
curl -G https://api.sportlogic.io/api/v1/games \ -H "X-API-Key: YOUR_KEY" \ --data-urlencode "date_from=2026-04-05" \ --data-urlencode "status=finished" \ --data-urlencode "per_page=25"
const res = await fetch( 'https://api.sportlogic.io/api/v1/games?date_from=2026-04-05&status=finished', { headers: { 'X-API-Key': 'YOUR_KEY' } } ); const { data, pagination } = await res.json();
import requests r = requests.get( "https://api.sportlogic.io/api/v1/games", headers={"X-API-Key": "YOUR_KEY"}, params={"date_from": "2026-04-05", "status": "finished"} ) games = r.json()["data"]
Retrieve a single game by ID with full league and team details.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | integer | required | Game ID (path parameter) |
curl https://api.sportlogic.io/api/v1/games/41200 \ -H "X-API-Key: YOUR_KEY"
Pre-match odds for a game, grouped by market. Updated until kickoff. Each odd references a market_id that matches the outcomes endpoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | integer | required | Game ID (path parameter) |
| market_id | integer | optional | Filter to a specific market |
| bookmaker_id | integer | optional | Filter to a specific bookmaker |
market_id on each odd is the same ID used in the outcomes endpoint.Response fields
- option_nameSelection label (e.g. "Home", "Draw", "Away", "Over", "Under")
- option_valueSelection value (e.g. "2.5" for Over/Under lines), null for standard markets
- oddsDecimal odds as string (e.g. "1.18"). Always parse with decimal-aware library.
- is_suspendedBoolean, true if the bookmaker has temporarily suspended this line
- market.keyMachine-readable market identifier (e.g. "match_winner", "goals_over_under")
curl https://api.sportlogic.io/api/v1/games/41200/odds \ -H "X-API-Key: YOUR_KEY"
Odds
Pre-match odds query across multiple games. For odds on a single game, prefer GET /games/{id}/odds.
Pre-match odds across multiple games with optional filters. Returns cursor-paginated results.
| Parameter | Type | Required | Description |
|---|---|---|---|
| game_id | integer | optional | Filter to a specific game |
| market_id | integer | optional | Filter to a specific market |
| bookmaker_id | integer | optional | Filter to a specific bookmaker |
| is_active | boolean | optional | Filter suspended vs active odds |
| per_page | integer | optional | 1–100, default 50 |
| cursor | string | optional | Pagination cursor |
"1.18"). Always parse with a decimal-aware library, never use floating point.curl -G https://api.sportlogic.io/api/v1/odds \ -H "X-API-Key: YOUR_KEY" \ --data-urlencode "game_id=41200" \ --data-urlencode "market_id=1"
Outcomes
After a game finishes, outcomes are computed for every betting market. Results are typically available within 5 minutes.
Get outcomes for a finished game. Use query params to filter by market, option, or result instead of fetching all outcomes.
| Parameter | Type | Required | Description |
|---|---|---|---|
| gameId | integer | required | Game ID (path parameter) |
| market_id | integer | optional | Filter by market ID |
| option_name | string | optional | Filter by option name (e.g. "Home", "Over") |
| option_value | string | optional | Filter by option value (e.g. "2.5") |
| result | string | optional | Filter by result: won or lost |
market_id + option_name + option_value to settle bets.
Response fields
- game_idThe game these outcomes belong to
- calculated_atISO 8601 timestamp when outcomes were computed
- outcomes[].market_idMarket ID, matches the market_id on odds
- outcomes[].option_nameOption label (e.g. "Home", "Draw", "Over")
- outcomes[].option_valueOption value if applicable (e.g. "2.5" for Over/Under), null otherwise
- outcomes[].result
won,lost,void,half_won,half_lost - outcomes[].marketEmbedded market object (id, name, key)
Result Values
won- The selection was correct. Pay out the bet.
lost- The selection was incorrect. Bet loses.
void- Market voided (e.g. player not in squad for goalscorer markets). Refund the stake.
half_won- Asian handicap: half the stake wins at full odds, half refunded.
half_lost- Asian handicap: half the stake loses, half refunded.
Settlement matching
market_id + option_name + option_value match the bet's selection. If result is "won", pay out. If "lost", the bet loses. That's it.
Error states
| Error Code | Meaning | retry_after |
|---|---|---|
GAME_NOT_STARTED | Game hasn't kicked off yet | Kick-off time |
GAME_IN_PROGRESS | Game is currently live | null |
GAME_CANCELLED | Postponed or abandoned | null |
OUTCOMES_PENDING | Finished, engine still calculating | +5 minutes |
# All outcomes for a game curl https://api.sportlogic.io/api/v1/outcomes/41200 \ -H "X-API-Key: sl_YOUR_KEY" # Filtered: only Match Winner (market 1), Home option curl "https://api.sportlogic.io/api/v1/outcomes/41200?market_id=1&option_name=Home" \ -H "X-API-Key: sl_YOUR_KEY"
const res = await fetch( 'https://api.sportlogic.io/api/v1/outcomes/41200', { headers: { 'X-API-Key': 'YOUR_KEY' } } ); if (!res.ok) throw new Error('Not ready yet'); const { data } = await res.json(); // Settle a bet const bet = { market_id: 1, option_name: 'Home', option_value: null }; const match = data.outcomes.find(o => o.market_id === bet.market_id && o.option_name === bet.option_name && o.option_value === bet.option_value ); console.log(match.result); // "won" or "lost"
import requests r = requests.get( "https://api.sportlogic.io/api/v1/outcomes/41200", headers={"X-API-Key": "YOUR_KEY"} ) data = r.json()["data"] for o in data["outcomes"]: print(o["market_id"], o["option_name"], "=>", o["result"])
List all calculated outcomes across games. Filter by game or date range. Useful for batch settlement processing.
| Parameter | Type | Required | Description |
|---|---|---|---|
| game_id | integer | optional | Filter to a specific game |
| date_from | date | optional | Filter by game start date from |
| date_to | date | optional | Filter by game start date to |
| per_page | integer | optional | 1–100, default 50 |
| cursor | string | optional | Cursor for next page |
curl -G https://api.sportlogic.io/api/v1/outcomes \ -H "X-API-Key: YOUR_KEY" \ --data-urlencode "date_from=2026-04-05"
const res = await fetch( 'https://api.sportlogic.io/api/v1/outcomes?date_from=2026-04-05', { headers: { 'X-API-Key': 'YOUR_KEY' } } ); const { data } = await res.json();
Reference
Lookup tables for leagues and markets. Use these IDs to filter games, odds, and outcomes.
List all active football leagues with country and tier.
- idLeague ID - use to filter games
- nameFull league name (e.g. "Bundesliga")
- countryCountry name
- logo_urlURL to league logo image
- tierDivision tier (1 = top flight)
- is_activeWhether the league is currently tracked
- seasonCurrent season year (e.g. 2025)
curl https://api.sportlogic.io/api/v1/leagues \
-H "X-API-Key: YOUR_KEY"
All betting markets available in the system. Use market_id to filter odds and match outcomes to bets.
| Field | Description |
|---|---|
id | Market ID - referenced in odds and outcomes |
name | Display name (e.g. "Match Winner", "Goals Over/Under") |
key | Machine-readable identifier (e.g. "match_winner", "goals_over_under") |
category | Market category grouping (e.g. "main", "goals") |
market_id is the common thread across odds and outcomes. When you fetch an odd with market_id: 1, the outcome for that same market will also have market_id: 1.curl https://api.sportlogic.io/api/v1/markets \
-H "X-API-Key: YOUR_KEY"
Errors
All error responses follow a consistent envelope. Machine-readable codes allow reliable error handling.
Error envelope
{
"success": false,
"error": {
"code": "MACHINE_READABLE_CODE",
"message": "Human-readable description",
"errors": { ... }
}
}
Common error codes
| HTTP | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR | Invalid query parameters. See errors field. |
| 401 | MISSING_API_KEY | No X-API-Key header |
| 401 | INVALID_API_KEY | Key not found or deleted |
| 403 | INACTIVE_API_KEY | Key suspended |
| 404 | RESOURCE_NOT_FOUND | Requested resource doesn't exist |
| 429 | RATE_LIMIT_EXCEEDED | Daily or per-minute limit reached. Resets at UTC midnight. |
| 400 | GAME_NOT_STARTED | Outcomes requested for a future game |
| 400 | GAME_IN_PROGRESS | Outcomes requested while game is live |
| 400 | OUTCOMES_PENDING | Game done but outcomes still calculating (~5 min) |