/bookmakers[public]Lists active bookmakers with last_scrape_at for freshness badges.
HTTP/JSON API for live football odds, surebet detection, and movement signals across our bookmaker network. Designed for B2B integrators building their own betting products on top of our data.
Base URL: https://api.freeoddportal.space
All endpoints return application/json. Public endpoints are unauthenticated (browse the catalogue, see surebets); paid endpoints require either a B2B API key or a consumer Supabase JWT.
Network coverage: multiple international and regional bookmakers, kept anonymous to protect our scraping operation. Specific source identities are surfaced only to authenticated paying customers (in the response under the books key) — they need them to place the bet. Markets covered: 1x2, over/under, asian handicap, BTS, double chance, plus deep markets (corners, cards, correct score, half-time variants).
Two parallel auth paths — the API key path is preferred for B2B and server-to-server; the bearer path is used by our consumer web app.
Pass your key in the X-API-Key header. Each key is bound to a single site domain (registered when you request the key). Browser requests must come from that origin; server-to-server calls have no Origin header and pass through.
curl "https://api.freeoddportal.space/matches/237/odds"
-H "X-API-Key: op_live_xuQXhqq8IvDRp0bpzE_G8ZFS3Vea4SAT"For consumer apps using Supabase Auth, pass the user's access token. Subscription state is enforced server-side — the user must be in their trial window or have a paid period remaining.
curl "https://api.freeoddportal.space/me"
-H "Authorization: Bearer eyJhbGc…"Exceeded limits return 429 Too Many Requests with a Retry-After header in seconds.
/bookmakers[public]Lists active bookmakers with last_scrape_at for freshness badges.
/matches[public]Filterable upcoming match list.
| param | type | notes |
|---|---|---|
| league_id | int | filter to one league |
| sport_id | int | 1 = football |
| status | string | upcoming | live | finished | cancelled |
| from_time / to_time | ISO8601 | kickoff window |
| min_books | int | only matches with ≥N book coverage |
| limit / offset | int | pagination, default 50 |
/matches/{id}[public]Match metadata only (teams, kickoff, status, league, scores).
/matches/{id}/markets[public]Distinct market_type values for a match with outcome / book / handicap-line counts. Use this to know which tabs to render.
/matches/{id}/odds[paid]Wide-format pivot of all live odds for a match. Pivoted by (market_type, outcome, handicap) → books{slug: {value, prev, direction, last_seen_at, scraped_at}}.
| param | type | notes |
|---|---|---|
| markets | csv | filter to specific market types (e.g. corners_over_under,btts). Default: all. |
/matches/{id}/movement[paid]Historical odds for a single (market, outcome, handicap).
| param | type | notes |
|---|---|---|
| market_type | string | required, e.g. '1x2' |
| outcome | string | required, e.g. 'home' |
| handicap | float | if applicable |
| bookmaker_slug | string | filter to one book |
| limit | int | default 500, max 5000 |
/signals/surebets[public]Cross-book arbitrage opportunities for 1x2. Rare — when they appear, the window is short. Free for v1; alerts on new ones will be a paid feature.
| param | type | notes |
|---|---|---|
| market | string | 1x2 only currently |
| min_roi | float | filter to ≥X% ROI |
| limit | int | default 50, max 200 |
400 — bad input (e.g. invalid markets= regex).401 — missing or invalid auth credentials.402 — authenticated but no active subscription. Detail includes balance and required amount.403— API key presented from an origin that doesn't match its bound site_domain.404 — match or resource not found.429 — rate limit exceeded. Backoff per Retry-After.5xx — backend error. Contact us if persistent.import requests
res = requests.get(
"https://api.freeoddportal.space/signals/surebets",
params={"min_roi": 1.0},
headers={"X-API-Key": "op_live_…"},
)
for sb in res.json()["surebets"]:
print(sb["match_id"], sb["roi_pct"])const res = await fetch(
"https://api.freeoddportal.space/matches/237/odds",
{
headers: {
"X-API-Key": "op_live_…",
"Accept": "application/json",
}
}
);
const data = await res.json();
console.log(data.odds);{
"match": {
"id": 237,
"home_team": "Arsenal",
"away_team": "Liverpool"
},
"odds": [
{ "market_type": "1x2", "outcome": "home",
"handicap": null, "books": {
"book_a": { "value": 1.85, "direction": "up" },
"book_b": { "value": 1.83, "direction": "flat" }
} }
]
}B2B keys are issued by hand for v1. Send us:
Email keys@freeoddportal.space with those details. Or, if you just want the consumer plan, start with a $5 deposit and use the bearer JWT path.