Eagles @ Bears
| Book | Eagles | Bears |
|---|---|---|
| FanDuel | -200 | +168 |
| DraftKings | -192 | +160 |
| BetOnline | -195 | +170 |
| Kalshi | -186 | +178 |
| Novig | -182 | +176 |
29 more books price this game
Sportsbooks, exchanges and prediction markets on one fixture, in one JSON shape, each price stamped with when its book last confirmed it.
| Book | Eagles | Bears |
|---|---|---|
| FanDuel | -200 | +168 |
| DraftKings | -192 | +160 |
| BetOnline | -195 | +170 |
| Kalshi | -186 | +178 |
| Novig | -182 | +176 |
29 more books price this game
| Book | Panthers | Hurricanes |
|---|---|---|
| Pinnacle | +109 | -122 |
| DraftKings | +105 | -125 |
| BetOnline | +106 | -120 |
| Polymarket | +108 | -113 |
| Novig | +115 | -120 |
26 more books price this game
| Book | Arsenal | Draw | Chelsea |
|---|---|---|---|
| Pinnacle | -118 | +290 | +320 |
| FanDuel | -125 | +280 | +330 |
| DraftKings | -120 | +285 | +310 |
| BetOnline | -115 | +288 | +318 |
| Kalshi | -112 | +300 | +305 |
24 more books price this game
A free plan, then flat plans from $24 to $199 a month. Each one is a set number of requests; the price never moves with what you use.
The free plan sees the same 46 books as the top plan. What grows is how much you can ask for, not what you're allowed to see.
Fixture, then books, then markets, then outcomes: each outcome a price, and a point where the market has one. American or decimal odds, chosen per call.
Every fixture keeps one stable id across all 46 books, so you never match team names from one book to the next.
last_update tells you when a book last confirmed a price. It is null when that value is unavailable, never an estimate.
Listing sports and upcoming fixtures is free. One odds call is one request, whatever comes back. Refused when spent, never a surprise bill.
Sportsbooks, exchanges and prediction markets, all priced through the same fields.
The same feed, four kinds of customer. None of them writes a scraper.
Fair prices from the no-vig line, +EV screens, arbitrage and middles scanners, closing-line-value tracking: every price with the book that posted it and when.
A best-price grid across 46 books from one call per sport, with last_update beside every number.
Kalshi and Polymarket contracts in the same shape as a sportsbook line, with sizes typed as dollars of depth, so a model compares venues without special cases.
An MCP server so an agent quotes a real book at a real time instead of a memory, and openers, closers and full series for backtests.
One set of markets, applied the same way whichever sport you ask about.
The whole surface, plus account endpoints for your keys and usage. Only calls that return prices count against your plan; looking around is free.
/v1/tryit/run freeRun a public read request as a guest/v1/sports freeList sports/v1/bookmakers freeList bookmakers/v1/pickem/payouts freeList published pick'em entry payouts/v1/markets freeList markets/v1/sports/{sport}/events freeList a sport's fixtures, no prices/v1/sports/{sport}/events/live freeList fixtures in play, no pricesGrowth (100K requests a month) and up/v1/sports/{sport}/odds 1 requestList a sport's fixtures with prices/v1/sports/{sport}/odds/live 1 requestList fixtures in play with pricesGrowth (100K requests a month) and up/v1/sports/{sport}/events/{id}/odds 1 requestOne fixture's prices, including periods and full-game ladders/v1/public/board/sports freeBoard sports with fixture counts/v1/public/board/{sport} freeThe public board for one sport/v1/public/featured freeThe homepage's featured games/v1/sports/{sport}/props 1 requestPlayer props across a sport's fixturesGrowth (100K requests a month) and up/v1/sports/{sport}/props/live 1 requestPlayer props for fixtures in playGrowth (100K requests a month) and up/v1/sports/{sport}/events/{id}/props 1 requestPlayer props for one fixtureGrowth (100K requests a month) and up/v1/historical/sports/{sport}/events freeDiscover archived fixture IDsScale (500K requests a month) and up/v1/historical/sports/{sport}/events/{id}/odds 1 requestThe full recorded price series for one fixtureScale (500K requests a month) and up/v1/historical/sports/{sport}/events/{id}/openers 1 requestEach book's opening line for one fixtureScale (500K requests a month) and up/v1/historical/sports/{sport}/events/{id}/closing 1 requestEach book's closing line for one fixtureScale (500K requests a month) and up/v1/historical/sports/{sport}/events/{id}/props 1 requestRecorded full-game prop checkpoints for one fixtureScale (500K requests a month) and up/v1/historical/sports/{sport}/events/{id}/props/movement 1 requestRecorded full-game prop price changes for one fixtureScale (500K requests a month) and up/v1/historical/sports/{sport}/events/{id}/props/openers 1 requestEach prop selection first observed by each bookScale (500K requests a month) and up/v1/historical/sports/{sport}/events/{id}/props/closing 1 requestEach prop selection last observed before kickoffScale (500K requests a month) and up/v1/billing/subscription freeThis account's subscriptionThree common calls in five languages. The key always travels in the X-API-Key header.
/v1/sports/soccer/odds?league=epl&markets=h2h,spreadsGET/v1/sports/mlb/events/mlb:baltimoreorioles-milwaukeebrewers:2026-09-18/odds?markets=h2h,totals&periods=f5GET/v1/historical/sports/nfl/events/nfl:atlantafalcons-carolinapanthers:2026-09-20/odds?markets=spreads,totalscurl --request GET \
--url "https://oddslink.app/v1/sports/soccer/odds?league=epl&markets=h2h,spreads" \
--header "X-API-Key: ok_live_..." \
--compressedimport requests
import json
resp = requests.get(
"https://oddslink.app/v1/sports/soccer/odds",
params={"league": "epl", "markets": "h2h,spreads"},
headers={"X-API-Key": "ok_live_..."},
timeout=60,
)
resp.raise_for_status()
data = resp.json()
print(json.dumps(data, indent=2))async function main() {
const res = await fetch(
"https://oddslink.app/v1/sports/soccer/odds?league=epl&markets=h2h,spreads",
{ headers: { "X-API-Key": "ok_live_..." } }
);
if (!res.ok) throw new Error((await res.json()).error.code);
const data = await res.json();
console.log(JSON.stringify(data, null, 2));
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET",
"https://oddslink.app/v1/sports/soccer/odds?league=epl&markets=h2h,spreads", nil)
req.Header.Set("X-API-Key", "ok_live_...")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$ch = curl_init("https://oddslink.app/v1/sports/soccer/odds?league=epl&markets=h2h,spreads");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_HTTPHEADER => ["X-API-Key: ok_live_..."],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);curl --request GET \
--url "https://oddslink.app/v1/sports/mlb/events/mlb:baltimoreorioles-milwaukeebrewers:2026-09-18/odds?markets=h2h,totals&periods=f5" \
--header "X-API-Key: ok_live_..." \
--compressedimport requests
import json
resp = requests.get(
"https://oddslink.app/v1/sports/mlb/events/mlb:baltimoreorioles-milwaukeebrewers:2026-09-18/odds",
params={"markets": "h2h,totals", "periods": "f5"},
headers={"X-API-Key": "ok_live_..."},
timeout=60,
)
resp.raise_for_status()
data = resp.json()
print(json.dumps(data, indent=2))async function main() {
const res = await fetch(
"https://oddslink.app/v1/sports/mlb/events/mlb:baltimoreorioles-milwaukeebrewers:2026-09-18/odds?markets=h2h,totals&periods=f5",
{ headers: { "X-API-Key": "ok_live_..." } }
);
if (!res.ok) throw new Error((await res.json()).error.code);
const data = await res.json();
console.log(JSON.stringify(data, null, 2));
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET",
"https://oddslink.app/v1/sports/mlb/events/mlb:baltimoreorioles-milwaukeebrewers:2026-09-18/odds?markets=h2h,totals&periods=f5", nil)
req.Header.Set("X-API-Key", "ok_live_...")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$ch = curl_init("https://oddslink.app/v1/sports/mlb/events/mlb:baltimoreorioles-milwaukeebrewers:2026-09-18/odds?markets=h2h,totals&periods=f5");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_HTTPHEADER => ["X-API-Key: ok_live_..."],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);curl --request GET \
--url "https://oddslink.app/v1/historical/sports/nfl/events/nfl:atlantafalcons-carolinapanthers:2026-09-20/odds?markets=spreads,totals" \
--header "X-API-Key: ok_live_..." \
--compressedimport requests
import json
resp = requests.get(
"https://oddslink.app/v1/historical/sports/nfl/events/nfl:atlantafalcons-carolinapanthers:2026-09-20/odds",
params={"markets": "spreads,totals"},
headers={"X-API-Key": "ok_live_..."},
timeout=60,
)
resp.raise_for_status()
data = resp.json()
print(json.dumps(data, indent=2))async function main() {
const res = await fetch(
"https://oddslink.app/v1/historical/sports/nfl/events/nfl:atlantafalcons-carolinapanthers:2026-09-20/odds?markets=spreads,totals",
{ headers: { "X-API-Key": "ok_live_..." } }
);
if (!res.ok) throw new Error((await res.json()).error.code);
const data = await res.json();
console.log(JSON.stringify(data, null, 2));
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET",
"https://oddslink.app/v1/historical/sports/nfl/events/nfl:atlantafalcons-carolinapanthers:2026-09-20/odds?markets=spreads,totals", nil)
req.Header.Set("X-API-Key", "ok_live_...")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$ch = curl_init("https://oddslink.app/v1/historical/sports/nfl/events/nfl:atlantafalcons-carolinapanthers:2026-09-20/odds?markets=spreads,totals");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_HTTPHEADER => ["X-API-Key: ok_live_..."],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);[
{
"id": "soccer:crystalpalace-nottinghamforest:2026-10-11",
"sport_key": "soccer",
"sport_title": "Soccer",
"commence_time": "2026-10-11T13:00:00.000Z",
"is_live": false,
"status": "scheduled",
"home_team": "Crystal Palace",
"away_team": "Nottingham Forest",
"bookmakers": [
{
"key": "betmgm",
"title": "BetMGM",
"link": "https://sports.nj.betmgm.com/en/sports/events/crystal-palace-nottingham-forest-2:7865814",
"last_update": "2026-10-10T22:06:51.003Z",
"markets": [
{
"key": "spreads",
"last_update": "2026-10-10T22:06:51.003Z",
"outcomes": [
{
"name": "Nottingham Forest",
"price": 145,
"point": -0.5,
"main": true
},
{
"name": "Crystal Palace",
"price": -210,
"point": 0.5,
"main": true
}
]
}
]
}
],
"unmatched_bookmakers": []
}
]{
"id": "mlb:baltimoreorioles-milwaukeebrewers:2026-09-18",
"sport_key": "mlb",
"sport_title": "MLB",
"commence_time": "2026-09-18T23:06:00.000Z",
"is_live": false,
"home_team": "Baltimore Orioles",
"away_team": "Milwaukee Brewers",
"bookmakers": [
{
"key": "betano",
"title": "Betano",
"last_update": "2026-09-18T18:08:59.000Z",
"markets": [
{
"key": "h2h",
"period": "f5",
"last_update": "2026-09-18T18:08:59.000Z",
"outcomes": [
{
"name": "Baltimore Orioles",
"price": 114
},
{
"name": "Milwaukee Brewers",
"price": -142
}
]
},
{
"key": "totals",
"period": "f5",
"last_update": "2026-09-18T18:08:51.000Z",
"outcomes": [
{
"name": "Over",
"price": -120,
"point": 4.5,
"main": true
},
{
"name": "Under",
"price": -108,
"point": 4.5,
"main": true
}
]
}
]
},
{
"key": "prophetx",
"title": "ProphetX",
"last_update": null,
"markets": [
{
"key": "h2h",
"period": "f5",
"last_update": null,
"outcomes": [
{
"name": "Baltimore Orioles",
"price": 118,
"size": {
"kind": "resting_depth",
"amount": 850
}
},
{
"name": "Milwaukee Brewers",
"price": -132,
"size": {
"kind": "resting_depth",
"amount": 600
}
}
]
}
]
}
],
"unmatched_bookmakers": []
}{
"id": "nfl:atlantafalcons-carolinapanthers:2026-09-20",
"sport_key": "nfl",
"sport_title": "NFL",
"commence_time": "2026-09-20T17:00:00.000Z",
"is_live": false,
"home_team": "Atlanta Falcons",
"away_team": "Carolina Panthers",
"archive_from": "2026-09-01T00:00:00.000Z",
"bookmakers": [
{
"key": "draftkings",
"title": "DraftKings",
"markets": [
{
"key": "spreads",
"movement": "recorded",
"points": [
{
"recorded_at": "2026-09-15T14:00:03.000Z",
"outcomes": [
{
"name": "Atlanta Falcons",
"price": -110,
"point": 3
},
{
"name": "Carolina Panthers",
"price": -110,
"point": -3
}
]
},
{
"recorded_at": "2026-09-18T18:08:20.000Z",
"outcomes": [
{
"name": "Atlanta Falcons",
"price": 100,
"point": 2.5
},
{
"name": "Carolina Panthers",
"price": -120,
"point": -2.5
}
]
}
]
},
{
"key": "totals",
"movement": "no_movement",
"points": [
{
"recorded_at": "2026-09-15T14:00:03.000Z",
"outcomes": [
{
"name": "Over",
"price": -108,
"point": 43.5
},
{
"name": "Under",
"price": -112,
"point": 43.5
}
]
}
]
},
{
"key": "h2h",
"period": "1h",
"movement": "not_recorded",
"points": []
}
]
}
],
"unmatched_bookmakers": []
}They sit beside the prices, so code that doesn't read them can skip them.
last_updateOn every book and market: when the book last confirmed its prices, or null when it is unavailable. We do not estimate it.
{ "key": "totals", "period": "f5",
"last_update": "2026-09-21T16:42:07Z" }size.kindA posted limit, a resting exchange depth and a contract count aren't the same number. Each outcome says which one it's giving you, and says nothing when the book publishes none.
{ "kind": "resting_depth",
"amount": 1200 }unmatched_bookmakersA book that reached us but couldn't be matched to this fixture is listed in the response instead of silently missing. Ask for books by name with bookmakers= and every one that returned nothing is listed too.
"unmatched_bookmakers": ["betano"]Free plan: 1,000 requests a month, every book.