{"id":3881,"date":"2026-09-12T10:00:00","date_gmt":"2026-09-12T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=3881"},"modified":"2026-09-03T15:29:11","modified_gmt":"2026-09-03T15:29:11","slug":"soccer-fixtures-api","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/","title":{"rendered":"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers"},"content":{"rendered":"<p>Pull two days of soccer fixtures from the OddsPapi API and you get 951 games across 283 competitions. Ask which of them a bookmaker has actually priced and the answer is not the one you would guess. The deepest board in the sample belongs to Helmond Sport against VVV Venlo in the Dutch second division: <strong>254 bookmakers, 442 market IDs, 59,728 prices on a single fixture<\/strong>. England&#8217;s FA Cup qualifying round on the same weekend drew two books. NCAA women&#8217;s soccer drew none.<\/p>\n<p>So the job is to tell those groups apart before you spend the calls, because <code>\/odds<\/code> is one fixture per request and the free tier wants a second between them. Calling all 951 takes 16 minutes and a quarter of it is wasted. This post measures 180 of those fixtures live, tests four filters against the result, and shows what a 254-book board contains once you open it.<\/p>\n<h2>What two days of soccer actually looks like<\/h2>\n<p>The <code>\/fixtures<\/code> endpoint takes a sport and a date range. Note the date quirk: <code>to<\/code> is a midnight-UTC instant, not a whole day, so pass the day after the last one you want.<\/p>\n<pre class=\"wp-block-code\"><code>import requests, time, collections\n\nAPI_KEY = \"YOUR_API_KEY\"\nBASE_URL = \"https:\/\/api.oddspapi.io\/v4\"\n\ndef get(path, **params):\n    \"\"\"One call, with the retry the free tier asks for.\"\"\"\n    for _ in range(5):\n        params[\"apiKey\"] = API_KEY\n        r = requests.get(f\"{BASE_URL}\/{path}\", params=params)\n        if r.status_code == 429:\n            time.sleep(r.json()[\"error\"].get(\"retryMs\", 1500) \/ 1000 + 1.2)\n            continue\n        if r.status_code == 404:\n            return 404, []          # empty window, not an error\n        return r.status_code, r.json()\n    return r.status_code, []\n\n# `to` is a midnight-UTC instant: pass the day AFTER your last day.\nstatus, fixtures = get(\"fixtures\", sportId=10,\n                       **{\"from\": \"2026-09-03\", \"to\": \"2026-09-05\"})\n\ncomps = collections.Counter((f[\"categoryName\"], f[\"tournamentName\"]) for f in fixtures)\nprint(len(fixtures), \"fixtures in\", len(comps), \"competitions\")\nfor (cat, name), n in comps.most_common(5):\n    print(f\"  {n:>4}  {cat} \/ {name}\")<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>951 fixtures in 283 competitions\n   134  USA \/ NCAA Regular Season, Women\n    47  USA \/ NCAA, Regular Season\n    45  Finland \/ Kolmonen\n    21  Romania \/ Liga 3\n    19  Brazil \/ U20 Paulista<\/code><\/pre>\n<p>College soccer, Finnish third-tier and Brazilian under-20 football lead the calendar. That is the shape of world football on a Thursday in September, and none of the four biggest blocks carries a betting market worth scanning. Meanwhile 873 of the 951 fixtures report <code>hasOdds: true<\/code>, which is 91.8% of them, so that flag will not sort the list for you.<\/p>\n<h2>The 180-fixture measurement<\/h2>\n<p>I sampled 180 fixtures, 25 from each bucket of the <code>externalProviders<\/code> key count, and called <code>\/odds<\/code> on every one. Excluding the 14 that had already kicked off, here is the pre-match board distribution across 166 fixtures.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Bookmakers on the fixture<\/th>\n<th>Fixtures<\/th>\n<th>Share<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>0<\/td>\n<td>27<\/td>\n<td>16.3%<\/td>\n<\/tr>\n<tr>\n<td>1 to 9<\/td>\n<td>16<\/td>\n<td>9.6%<\/td>\n<\/tr>\n<tr>\n<td>10 to 99<\/td>\n<td>27<\/td>\n<td>16.3%<\/td>\n<\/tr>\n<tr>\n<td>100 to 199<\/td>\n<td>37<\/td>\n<td>22.3%<\/td>\n<\/tr>\n<tr>\n<td>200 or more<\/td>\n<td>59<\/td>\n<td>35.5%<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The median non-empty board carries <strong>178 bookmakers<\/strong> and the deepest carries 287. Soccer has no cliff. Our <a href=\"https:\/\/oddspapi.io\/blog\/college-football-odds-coverage\/\">college football census<\/a> found a slate that was either fully covered or barely covered, with nothing at all between 10 and 49 books. Soccer fills every rung of that ladder.<\/p>\n<h2>Four filters, tested<\/h2>\n<p>Every fixture ships an <code>externalProviders<\/code> object mapping it to third-party data vendors. On college football, counting the populated keys sorted the slate perfectly: two or more providers meant a real board, every time, no exceptions. That rule cut 136 calls to 54 and lost nothing.<\/p>\n<p>It does not survive the move to soccer.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Filter<\/th>\n<th>Calls kept<\/th>\n<th>Boards found<\/th>\n<th>Wasted calls<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>hasOdds<\/code> is true<\/td>\n<td>164 of 166<\/td>\n<td>139 of 139<\/td>\n<td>25<\/td>\n<\/tr>\n<tr>\n<td>2 or more providers<\/td>\n<td>144 of 166<\/td>\n<td>132 of 139<\/td>\n<td>12<\/td>\n<\/tr>\n<tr>\n<td>3 or more providers<\/td>\n<td>120 of 166<\/td>\n<td>118 of 139<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td><code>pinnacleId<\/code> is populated<\/td>\n<td>135 of 166<\/td>\n<td>126 of 139<\/td>\n<td>9<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Two providers now saves 13% of the calls and misses seven boards. Three providers gets the precision back, with only two wasted calls, and costs you 15% of the boards on the way. One of the ones it drops is an Azerbaijani First Division game carrying <code>betradarId<\/code> and nothing else, priced by 124 bookmakers.<\/p>\n<p><code>pinnacleId<\/code> is the best single field. Populated, the median board is 167 books and Pinnacle itself turns up in the payload 100 times out of 145. Absent, the median board is zero. It is a good default, not a clean rule.<\/p>\n<pre class=\"wp-block-code\"><code>def worth_a_call(f):\n    providers = {k: v for k, v in (f.get(\"externalProviders\") or {}).items() if v}\n    return bool(providers.get(\"pinnacleId\")) or len(providers) >= 3\n\nshortlist = [f for f in fixtures if worth_a_call(f)]\nprint(len(fixtures), \"->\", len(shortlist))    # 951 -> 472<\/code><\/pre>\n<h2>The competition is the stable unit, and the clock is the trap<\/h2>\n<p>Thirty-six competitions came up more than once in the pre-match sample. Thirty-two of them gave the same answer every time: either every sampled fixture had a board, or none did. Coverage is a property of the competition, not of the individual game, which means one probe per competition answers for the whole calendar. That is 283 calls instead of 951 on day one, and none at all on day two if you cache the verdict.<\/p>\n<p>The four that flipped are worth reading, because one of them explains most of what looks like missing coverage. Finland&#8217;s Kolmonen, the third tier, returned this:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Hours to kick-off<\/th>\n<th>Bookmakers<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>26.3<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>25.8<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>4.1<\/td>\n<td>138<\/td>\n<\/tr>\n<tr>\n<td>3.8<\/td>\n<td>142<\/td>\n<\/tr>\n<tr>\n<td>2.3<\/td>\n<td>128<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Same competition, same sample, same afternoon. The two fixtures a day out read as uncovered and the three inside four hours carry 128 books or more. Books open a small league close to the whistle, so a scan run 26 hours early records a zero that will be a full board by lunchtime. Our <a href=\"https:\/\/oddspapi.io\/blog\/african-football-odds-api\/\">African football census<\/a> put that window at roughly 36 hours; on Finnish third-tier football it is shorter still.<\/p>\n<p>The other timing trap sits at the front of your window. Fixtures that have already started drop their live prices: 11 of the 14 kicked-off fixtures in the sample returned an empty payload. Filter on <code>startTime<\/code> before you call, or your scan will report this morning&#8217;s games as unpriced.<\/p>\n<pre class=\"wp-block-code\"><code>from datetime import datetime, timezone\n\nnow = datetime.now(timezone.utc)\nupcoming = [f for f in shortlist\n            if datetime.fromisoformat(f[\"startTime\"].replace(\"Z\", \"+00:00\")) > now]<\/code><\/pre>\n<h2>Depth does not follow prestige<\/h2>\n<p>The Premier League tops the sample at 287 books and LaLiga sits one behind on 286. After that the ordering stops matching reputation.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Competition<\/th>\n<th>Tier<\/th>\n<th>Bookmakers<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>England, Premier League<\/td>\n<td>1<\/td>\n<td>287<\/td>\n<\/tr>\n<tr>\n<td>Spain, LaLiga<\/td>\n<td>1<\/td>\n<td>285 to 286<\/td>\n<\/tr>\n<tr>\n<td>Saudi Arabia, Saudi Pro League<\/td>\n<td>1<\/td>\n<td>224 to 264<\/td>\n<\/tr>\n<tr>\n<td>Germany, 2. Bundesliga<\/td>\n<td>2<\/td>\n<td>261<\/td>\n<\/tr>\n<tr>\n<td>Netherlands, Eerste Divisie<\/td>\n<td>2<\/td>\n<td>253 to 254<\/td>\n<\/tr>\n<tr>\n<td>Brazil, Brasileiro Serie B<\/td>\n<td>2<\/td>\n<td>252 to 254<\/td>\n<\/tr>\n<tr>\n<td>Ireland, First Division<\/td>\n<td>2<\/td>\n<td>233 to 242<\/td>\n<\/tr>\n<tr>\n<td>Wales, Cymru Premier<\/td>\n<td>1<\/td>\n<td>211 to 219<\/td>\n<\/tr>\n<tr>\n<td>Switzerland, Challenge League<\/td>\n<td>2<\/td>\n<td>187<\/td>\n<\/tr>\n<tr>\n<td>Egypt, 2. Division A<\/td>\n<td>2<\/td>\n<td>142 to 158<\/td>\n<\/tr>\n<tr>\n<td>England, FA Cup qualifying<\/td>\n<td>amateur<\/td>\n<td>2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>A second-division Dutch fixture outdraws every competition below the big five, and the Welsh top flight beats the Swiss second tier. What decides it is whether the competition runs a fixed, licensed, year-round schedule that European and Asian books can price in volume. Prestige has little to do with it, which is why OddsPapi carries <strong>350+ bookmakers<\/strong> rather than the 20 or 30 a US-facing feed ships.<\/p>\n<h2>Inside a 254-book board<\/h2>\n<p>Helmond Sport against VVV Venlo, <code>tournamentId<\/code> 131, kicking off at 18:00 UTC. One call returns 254 bookmakers, 442 distinct market IDs and a median of 66 markets per book. Here is how to read the three-way off it without tripping the two flags that will otherwise poison your average.<\/p>\n<pre class=\"wp-block-code\"><code>status, odds = get(\"odds\", fixtureId=\"id1000013172044614\")\nbooks = odds[\"bookmakerOdds\"]\n\ndef three_way(book):\n    \"\"\"Return (home, draw, away) if the book has a live, complete 1X2.\"\"\"\n    if book.get(\"suspended\") or book.get(\"bookmakerIsActive\") is False:\n        return None\n    market = (book.get(\"markets\") or {}).get(\"101\")\n    if not market:\n        return None\n    prices = []\n    for outcome_id in (\"101\", \"102\", \"103\"):\n        outcome = (market.get(\"outcomes\") or {}).get(outcome_id)\n        if not outcome:\n            return None\n        price = outcome[\"players\"][\"0\"]\n        if not price.get(\"active\") or not price.get(\"price\"):\n            return None\n        prices.append(price[\"price\"])\n    return tuple(prices)\n\nquotes = {slug: t for slug, book in books.items() if (t := three_way(book))}\nprint(len(books), \"books,\", len(quotes), \"complete and active\")   # 254 books, 231<\/code><\/pre>\n<p>Two flags do the work there. <code>bookmakerIsActive<\/code> is false on 21 of the 254 books on this fixture, and the price-level <code>active<\/code> field catches the rest. Skip either check and you will average dead numbers into a fair price. The book-level and price-level flags disagree often enough that you need both, as our <a href=\"https:\/\/oddspapi.io\/blog\/bwin-api-odds-access\/\">Bwin study<\/a> found when one regional feed shipped a parked board with every price marked live.<\/p>\n<h3>Dedupe before you average<\/h3>\n<p>231 books is not 231 opinions. Group on the price tuple and the board collapses.<\/p>\n<pre class=\"wp-block-code\"><code>groups = collections.defaultdict(list)\nfor slug, t in quotes.items():\n    groups[t].append(slug)\n\nprint(len(groups), \"independent prices\",\n      f\"({100 * (1 - len(groups) \/ len(quotes)):.1f}% collapse)\")\n# 67 independent prices (71.0% collapse)<\/code><\/pre>\n<p>Sixty-seven independent prices out of 231 slugs, a <strong>71.0% collapse<\/strong>, and the largest identical group is 23 separate slugs all quoting 2.50 \/ 3.35 \/ 2.45. Feed the raw 231 into a consensus and you have weighted one syndicate&#8217;s opinion 23 times. Our <a href=\"https:\/\/oddspapi.io\/blog\/how-many-bookmakers-backtest\/\">176-book closing-line study<\/a> found the same collapse on Premier League fixtures and put the point of diminishing returns at 25 independent books.<\/p>\n<h3>Rank the board on margin<\/h3>\n<pre class=\"wp-block-code\"><code>def margin(t):\n    return (sum(1 \/ p for p in t) - 1) * 100\n\nranked = sorted(groups.items(), key=lambda kv: margin(kv[0]))\nfor t, slugs in ranked[:3]:\n    print(f\"  {margin(t):5.2f}%  {t}  {len(slugs)} feed(s): {', '.join(sorted(slugs)[:3])}\")<\/code><\/pre>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Book<\/th>\n<th>Price (H \/ D \/ A)<\/th>\n<th>Margin<\/th>\n<th>Rank of 67<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>betfair-ex<\/code> and 4 clones<\/td>\n<td>2.62 \/ 3.85 \/ 2.56<\/td>\n<td>3.20%<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td><code>polymarket<\/code><\/td>\n<td>2.632 \/ 3.571 \/ 2.632<\/td>\n<td>3.99%<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td><code>betika<\/code><\/td>\n<td>2.60 \/ 3.55 \/ 2.55<\/td>\n<td>5.85%<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<td><code>betpawa.cm<\/code><\/td>\n<td>2.60 \/ 3.58 \/ 2.52<\/td>\n<td>6.08%<\/td>\n<td>4<\/td>\n<\/tr>\n<tr>\n<td><code>pinnacle<\/code><\/td>\n<td>2.57 \/ 3.47 \/ 2.58<\/td>\n<td>6.49%<\/td>\n<td>8<\/td>\n<\/tr>\n<tr>\n<td><code>bet365<\/code><\/td>\n<td>2.55 \/ 3.40 \/ 2.55<\/td>\n<td>7.84%<\/td>\n<td>25<\/td>\n<\/tr>\n<tr>\n<td><code>kalshi<\/code><\/td>\n<td>2.50 \/ 3.125 \/ 2.50<\/td>\n<td>12.00%<\/td>\n<td>58<\/td>\n<\/tr>\n<tr>\n<td><code>betway<\/code><\/td>\n<td>2.30 \/ 3.10 \/ 2.30<\/td>\n<td>19.21%<\/td>\n<td>66<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Median margin across the 67 independent prices is 8.86%. Pinnacle takes 6.49% here, against the 2.95% to 3.20% it charges on a Premier League close. That is the pattern our African football census recorded: <strong>Pinnacle&#8217;s margin widens with the obscurity of the league, so it stops being an automatic fair-value anchor once you leave the big five<\/strong>. On this board two Kenyan and Cameroonian books, betika and betpawa.cm, price the Dutch second division tighter than Pinnacle does. De-vig the deduped consensus instead, using one of the <a href=\"https:\/\/oddspapi.io\/blog\/no-vig-odds-api\/\">three de-vigging methods<\/a>, and rank every book on the board you are actually betting into.<\/p>\n<h3>Best price across the whole board<\/h3>\n<pre class=\"wp-block-code\"><code>best = [max(t[i] for t in quotes.values()) for i in range(3)]\nbook_for = [max(quotes.items(), key=lambda kv: kv[1][i])[0] for i in range(3)]\nprint(list(zip((\"home\", \"draw\", \"away\"), best, book_for)))\nprint(f\"composite overround: {(sum(1 \/ p for p in best) - 1) * 100:.2f}%\")<\/code><\/pre>\n<pre class=\"wp-block-code\"><code>[('home', 2.632, 'polymarket'), ('draw', 3.85, 'betfair-ex'), ('away', 2.632, 'polymarket')]\ncomposite overround: 1.96%<\/code><\/pre>\n<p>Taking the best number on each outcome from 231 books leaves a 1.96% overround, against 8.86% at the median book. That is the size of the <a href=\"https:\/\/oddspapi.io\/blog\/line-shopping-python-best-odds\/\">line shopping<\/a> gap on a fixture nobody writes about. Watch the sanity check on that composite: a sum below 100% on a thin board is a stale price, not free money, and a single book never offers an arb against itself.<\/p>\n<h2>The pipeline, end to end<\/h2>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Step<\/th>\n<th>Endpoint<\/th>\n<th>Calls for two days of soccer<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Pull the calendar<\/td>\n<td><code>\/fixtures<\/code><\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Drop started fixtures<\/td>\n<td>local<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>Probe one game per competition<\/td>\n<td><code>\/odds<\/code><\/td>\n<td>283, then cached<\/td>\n<\/tr>\n<tr>\n<td>Read the boards that pay<\/td>\n<td><code>\/odds<\/code><\/td>\n<td>as many as you need<\/td>\n<\/tr>\n<tr>\n<td>Backfill closing prices<\/td>\n<td><code>\/historical-odds<\/code><\/td>\n<td>3 books per call<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>That last row is the free part that competitors charge for. <code>\/historical-odds<\/code> keeps the full price history after a fixture finishes, including the books you were not watching live, so you can grade a scanner against real closing lines without paying for a data plan. Snapshots run past kick-off, so filter on <code>createdAt &lt; startTime<\/code> for a true close.<\/p>\n<h2>FAQ<\/h2>\n<h3>How many soccer fixtures does the API return per day?<\/h3>\n<p>Around 475 a day in early September 2026, or 951 across the two-day window measured here, spread over 283 competitions. The count rises during the European club season and falls during international breaks.<\/p>\n<h3>Which field tells me a fixture has a bookmaker board?<\/h3>\n<p><code>pinnacleId<\/code> inside <code>externalProviders<\/code> is the strongest single signal: populated, the median board is 167 bookmakers. Combine it with a three-provider threshold and you keep 92% of the boards. No field is exact on soccer, so probe one fixture per competition and cache the verdict.<\/p>\n<h3>Why does a fixture return no bookmakers when hasOdds is true?<\/h3>\n<p>Two reasons. The fixture has already kicked off and live prices have been dropped, or the market has not opened yet. Small leagues open close to kick-off: Finnish third-tier fixtures read empty 26 hours out and carried 128 or more books inside four hours.<\/p>\n<h3>Do 254 bookmakers mean 254 different prices?<\/h3>\n<p>No. On the Eerste Divisie fixture measured here, 231 complete and active three-way quotes collapsed to 67 independent prices, a 71.0% reduction, with 23 slugs sharing one tuple. Group on the price tuple before you average or you will overweight a single feed.<\/p>\n<h3>Is Pinnacle the fair-value benchmark on second-division soccer?<\/h3>\n<p>Not reliably. Pinnacle charged 6.49% on this Dutch second-division fixture and ranked eighth of 67 independent prices, behind Betfair Exchange, Polymarket, Betika and betPawa. Its margin widens as the league gets more obscure, so de-vig the deduped consensus rather than trusting one book.<\/p>\n<h2>Get your key<\/h2>\n<p>Every number here came off the free tier: one <code>\/fixtures<\/code> call, 181 <code>\/odds<\/code> calls and a second of patience between them. <a href=\"https:\/\/oddspapi.io\/\">Grab a free API key<\/a> and pull your own two days of soccer, or start with our <a href=\"https:\/\/oddspapi.io\/blog\/free-odds-api-350-bookmakers\/\">free odds API guide<\/a> if this is your first call.<\/p>\n<p><script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\"@type\": \"Question\", \"name\": \"How many soccer fixtures does the API return per day?\",\n     \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Around 475 a day in early September 2026, or 951 across a two-day window, spread over 283 competitions. The count rises during the European club season and falls during international breaks.\"}},\n    {\"@type\": \"Question\", \"name\": \"Which field tells me a fixture has a bookmaker board?\",\n     \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"pinnacleId inside externalProviders is the strongest single signal: populated, the median board is 167 bookmakers. Combined with a three-provider threshold it keeps 92% of the boards. Probe one fixture per competition and cache the verdict.\"}},\n    {\"@type\": \"Question\", \"name\": \"Why does a fixture return no bookmakers when hasOdds is true?\",\n     \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Either the fixture has already kicked off and live prices have been dropped, or the market has not opened yet. Small leagues open close to kick-off: Finnish third-tier fixtures carried 128 or more books inside four hours of the whistle.\"}},\n    {\"@type\": \"Question\", \"name\": \"Do 254 bookmakers mean 254 different prices?\",\n     \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. On the Eerste Divisie fixture measured here, 231 complete and active three-way quotes collapsed to 67 independent prices, a 71.0% reduction, with 23 slugs sharing one tuple. Group on the price tuple before averaging.\"}},\n    {\"@type\": \"Question\", \"name\": \"Is Pinnacle the fair-value benchmark on second-division soccer?\",\n     \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Not reliably. Pinnacle charged 6.49% on a Dutch second-division fixture and ranked eighth of 67 independent prices, behind Betfair Exchange, Polymarket, Betika and betPawa. De-vig the deduped consensus instead.\"}}\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: soccer fixtures api\nSEO Title: Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers\nMeta Description: Two days of soccer is 951 fixtures across 283 competitions. Pull them in Python, then read pinnacleId to find the boards that run past 200 bookmakers.\nSlug: soccer-fixtures-api\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Two days of soccer is 951 fixtures across 283 competitions. Pull them in Python, then read pinnacleId to find the boards that run past 200 bookmakers.<\/p>\n","protected":false},"author":2,"featured_media":3882,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[12,9,11,15,10],"class_list":["post-3881","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-betting-data","tag-odds-api","tag-python","tag-soccer","tag-sports-betting-api"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers | OddsPapi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"Two days of soccer is 951 fixtures across 283 competitions. Pull them in Python, then read pinnacleId to find the boards that run past 200 bookmakers.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-12T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1429\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Odds API Writer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/oddspapi.io\/logo-v2.webp\" \/>\n<meta name=\"twitter:creator\" content=\"@oddspapiapi\" \/>\n<meta name=\"twitter:site\" content=\"@oddspapiapi\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Odds API Writer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers\",\"datePublished\":\"2026-09-12T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\"},\"wordCount\":1615,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp\",\"keywords\":[\"Betting Data\",\"Odds API\",\"Python\",\"Soccer\",\"Sports Betting API\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\",\"name\":\"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp\",\"datePublished\":\"2026-09-12T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"Soccer Fixtures API - OddsPapi API Blog\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\",\"url\":\"https:\/\/oddspapi.io\/blog\/\",\"name\":\"OddsPapi\",\"description\":\"Sports Odds API Tutorials &amp; Guides\",\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"alternateName\":\"Odds Papi\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/oddspapi.io\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\",\"name\":\"OddsPapi\",\"url\":\"https:\/\/oddspapi.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png\",\"width\":135,\"height\":135,\"caption\":\"OddsPapi\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/oddspapiapi\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\",\"name\":\"Odds API Writer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g\",\"caption\":\"Odds API Writer\"},\"url\":\"https:\/\/oddspapi.io\/blog\/author\/andy-lavelle\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers | OddsPapi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/","og_locale":"en_US","og_type":"article","og_title":"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers | OddsPapi Blog","og_description":"Two days of soccer is 951 fixtures across 283 competitions. Pull them in Python, then read pinnacleId to find the boards that run past 200 bookmakers.","og_url":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-09-12T10:00:00+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp","type":"image\/webp"}],"author":"Odds API Writer","twitter_card":"summary_large_image","twitter_image":"https:\/\/oddspapi.io\/logo-v2.webp","twitter_creator":"@oddspapiapi","twitter_site":"@oddspapiapi","twitter_misc":{"Written by":"Odds API Writer","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers","datePublished":"2026-09-12T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/"},"wordCount":1615,"commentCount":0,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp","keywords":["Betting Data","Odds API","Python","Soccer","Sports Betting API"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/","url":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/","name":"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp","datePublished":"2026-09-12T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/soccer-fixtures-api-scaled.webp","width":2560,"height":1429,"caption":"Soccer Fixtures API - OddsPapi API Blog"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"Soccer Fixtures API: The Dutch Second Division Draws 254 Bookmakers"}]},{"@type":"WebSite","@id":"https:\/\/oddspapi.io\/blog\/#website","url":"https:\/\/oddspapi.io\/blog\/","name":"OddsPapi","description":"Sports Odds API Tutorials &amp; Guides","publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"alternateName":"Odds Papi","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/oddspapi.io\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/oddspapi.io\/blog\/#organization","name":"OddsPapi","url":"https:\/\/oddspapi.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2025\/11\/oddspapi.png","width":135,"height":135,"caption":"OddsPapi"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/oddspapiapi"]},{"@type":"Person","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13","name":"Odds API Writer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/33b204f24af3d02e35b25ae730c0536121ca6a783fdb196e7611c9e49fcd13eb?s=96&d=mm&r=g","caption":"Odds API Writer"},"url":"https:\/\/oddspapi.io\/blog\/author\/andy-lavelle\/"}]}},"_links":{"self":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3881","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/comments?post=3881"}],"version-history":[{"count":1,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3881\/revisions"}],"predecessor-version":[{"id":3883,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3881\/revisions\/3883"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/3882"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=3881"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=3881"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=3881"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}