{"id":3887,"date":"2026-09-14T10:00:00","date_gmt":"2026-09-14T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=3887"},"modified":"2026-09-07T14:01:54","modified_gmt":"2026-09-07T14:01:54","slug":"afl-odds-api","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/","title":{"rendered":"AFL Odds API: Merge Two Market IDs Into a 124-Book Board"},"content":{"rendered":"<p>Search for an AFL odds API and you find two kinds of answer. One is a scraper pointed at a single Australian bookmaker. The other is a data contract with a sales call in front of it. Neither one tells you what sits on the board for a preliminary final on a Friday night in Melbourne.<\/p>\n<p>We measured it. On <strong>7 September 2026<\/strong> we pulled every Aussie Rules fixture in the next nine days and counted the board on each one. A preliminary final carried <strong>104 bookmakers<\/strong>. An AFLW round match carried <strong>121<\/strong>. Across the eleven priced fixtures we saw <strong>156 distinct bookmaker slugs<\/strong>.<\/p>\n<p>Then we tried to rank those books by margin and the numbers refused to line up. The reason turned out to be structural, and it will break your parser before it breaks your model.<\/p>\n<h2>Aussie Rules ships two market IDs for one result<\/h2>\n<p>The market catalogue holds exactly two markets for sportId 31:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>marketId<\/th>\n<th>marketName<\/th>\n<th>Length<\/th>\n<th>Outcome IDs<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>311<\/td>\n<td>Winner<\/td>\n<td>2<\/td>\n<td>311 (home), 312 (away)<\/td>\n<\/tr>\n<tr>\n<td>313<\/td>\n<td>1X2<\/td>\n<td>3<\/td>\n<td>313 (home), 314 (draw), 315 (away)<\/td>\n<\/tr>\n<\/tbody>\n<\/table><figcaption>Live <code>\/v4\/markets<\/code> filtered to sportId 31, 7 September 2026.<\/figcaption><\/figure>\n<p>Both markets settle the same match. A draw in the AFL is rare, so some books price the result two ways and others hang a draw price beside it. The feed keeps whichever shape the bookmaker publishes.<\/p>\n<p>On the Fremantle Dockers v Geelong Cats preliminary final, 78 books quoted market 311, 41 quoted market 313, and <strong>26 of them quoted 313 and nothing else<\/strong>. That set includes the entire bet365 group of nine slugs, 1xBet, 22bet, Melbet, Tipico and PointsBet Australia. Read market 311 alone and you drop a quarter of the board, including the book most of your readers actually hold an account with.<\/p>\n<p>This is the same trap we hit on <a href=\"https:\/\/oddspapi.io\/blog\/boxing-odds-api\/\">boxing, where one fight ships under three market IDs<\/a>. The fix is the same. Resolve on the market name, collect every ID that maps to it, and merge.<\/p>\n<pre class=\"wp-block-code\"><code>import os, requests\n\nAPI_KEY = os.environ[\"ODDSPAPI_API_KEY\"]\nBASE = \"https:\/\/api.oddspapi.io\/v4\"\n\nWINNER, ONE_X_TWO = \"311\", \"313\"\nHOME = {WINNER: \"311\", ONE_X_TWO: \"313\"}\nAWAY = {WINNER: \"312\", ONE_X_TWO: \"315\"}\nDRAW = \"314\"\n\ndef two_way_quotes(payload):\n    \"\"\"One home\/away price per bookmaker, from whichever market ID it uses.\"\"\"\n    out = {}\n    for slug, book in payload[\"bookmakerOdds\"].items():\n        if book.get(\"suspended\") or book.get(\"bookmakerIsActive\") is False:\n            continue\n        for market_id in (WINNER, ONE_X_TWO):\n            market = (book.get(\"markets\") or {}).get(market_id)\n            if not market:\n                continue\n            prices = {}\n            for outcome_id, outcome in market[\"outcomes\"].items():\n                p = outcome[\"players\"][\"0\"]\n                if p[\"active\"] and p[\"price\"]:\n                    prices[outcome_id] = p[\"price\"]\n            home, away = prices.get(HOME[market_id]), prices.get(AWAY[market_id])\n            if home and away:\n                out[slug] = {\"market\": market_id, \"home\": home,\n                             \"away\": away, \"draw\": prices.get(DRAW)}\n                break\n    return out\n\nodds = requests.get(f\"{BASE}\/odds\",\n                    params={\"apiKey\": API_KEY,\n                            \"fixtureId\": \"id3100065674372626\"}).json()\nquotes = two_way_quotes(odds)\nprint(len(quotes), \"books with a usable home\/away pair\")\nprint(sum(1 for q in quotes.values() if q[\"market\"] == ONE_X_TWO), \"of them on 313\")\n<\/code><\/pre>\n<p>That returns 99 usable pairs on the preliminary final, 26 of which arrive on market 313. A parser reading one ID sees 73.<\/p>\n<h3>Fifteen books publish a three-way market with two legs<\/h3>\n<p>Here is the second half of the trap. Of the 41 books quoting market 313 on that fixture, <strong>15 ship it with no draw outcome at all<\/strong>. PointsBet Australia, Fanatics, 1xBet, 22bet, Betwinner, Melbet, Fonbet and Tipico all publish a market the catalogue calls three-way and send two prices.<\/p>\n<p>Sum the inverse prices on those and you get a margin near 5.8%. Sum a complete three-way and you get 7.9%. Rank the board on that number and the incomplete books sit at the top of your leaderboard while offering you a worse bet. The overround is only comparable across books that priced the same number of outcomes, so count the legs before you compute anything. Our <a href=\"https:\/\/oddspapi.io\/blog\/vig-calculator-python-sportsbook-margin\/\">vig calculator walkthrough<\/a> covers the arithmetic; the leg count is the check that goes in front of it.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Quote shape<\/th>\n<th>Books<\/th>\n<th>Median overround<\/th>\n<th>Comparable to<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Market 311, two legs<\/td>\n<td>73<\/td>\n<td>6.71%<\/td>\n<td>other two-leg quotes<\/td>\n<\/tr>\n<tr>\n<td>Market 313, two legs<\/td>\n<td>12<\/td>\n<td>5.82%<\/td>\n<td>nothing on this board<\/td>\n<\/tr>\n<tr>\n<td>Market 313, three legs<\/td>\n<td>26<\/td>\n<td>7.91%<\/td>\n<td>other three-leg quotes<\/td>\n<\/tr>\n<\/tbody>\n<\/table><figcaption>Fremantle Dockers v Geelong Cats, active prices only, 7 September 2026.<\/figcaption><\/figure>\n<p>The draw price itself is the loosest number on the board. Across the 14 books with a complete three-way, it runs from <strong>24.5 to 85.0<\/strong>, an implied probability between 4.08% and 1.18%. De-vig the three-way consensus and the draw lands at 1.35%, which is close to the rate AFL matches actually draw at. Nobody competes on that leg, so the spread stays wide.<\/p>\n<h2>121 quotes, 16 prices<\/h2>\n<p>Board width and opinion count are different measurements. Group each fixture&#8217;s quotes by their price tuple and the AFL board collapses harder than any sport we have measured:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Fixture<\/th>\n<th>Books<\/th>\n<th>Usable pairs<\/th>\n<th>Independent prices<\/th>\n<th>Collapse<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>AFL: Fremantle v Geelong<\/td>\n<td>104<\/td>\n<td>99<\/td>\n<td>29<\/td>\n<td>70.7%<\/td>\n<\/tr>\n<tr>\n<td>AFL: Brisbane v Adelaide<\/td>\n<td>124<\/td>\n<td>109<\/td>\n<td>25<\/td>\n<td>77.1%<\/td>\n<\/tr>\n<tr>\n<td>AFLW: Hawthorn v Western Bulldogs<\/td>\n<td>121<\/td>\n<td>121<\/td>\n<td>20<\/td>\n<td>83.5%<\/td>\n<\/tr>\n<tr>\n<td>AFLW: Adelaide v Geelong<\/td>\n<td>121<\/td>\n<td>121<\/td>\n<td>18<\/td>\n<td>85.1%<\/td>\n<\/tr>\n<tr>\n<td>AFLW: Gold Coast v Collingwood<\/td>\n<td>119<\/td>\n<td>118<\/td>\n<td>16<\/td>\n<td>86.4%<\/td>\n<\/tr>\n<tr>\n<td>AFLW: Melbourne v Port Adelaide<\/td>\n<td>121<\/td>\n<td>121<\/td>\n<td>16<\/td>\n<td><strong>86.8%<\/strong><\/td>\n<\/tr>\n<tr>\n<td>AFLW: North Melbourne v Carlton<\/td>\n<td>121<\/td>\n<td>121<\/td>\n<td>16<\/td>\n<td><strong>86.8%<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table><figcaption>Seven of the eleven priced fixtures. Dedupe on the (home, away) price tuple.<\/figcaption><\/figure>\n<p>On the preliminary final, 22 slugs quoted an identical 1.606 \/ 2.25 and another 16 quoted 1.56 \/ 2.29. Those two tuples are 38% of the usable pairs between them. Average the raw slug list and you hand one pricing desk 22 votes.<\/p>\n<p>Our <a href=\"https:\/\/oddspapi.io\/blog\/how-many-bookmakers-backtest\/\">study of how many bookmakers a backtest needs<\/a> put the knee of the accuracy curve at 25 independent books. An AFLW board sits at 16. Treat the AFL consensus as a thinner signal than the raw count suggests, and lean on the exchange price as your anchor rather than the mean.<\/p>\n<pre class=\"wp-block-code\"><code>from collections import defaultdict\n\ngroups = defaultdict(list)\nfor slug, q in quotes.items():\n    groups[(q[\"home\"], q[\"away\"])].append(slug)\n\nprint(f\"{len(quotes)} quotes -> {len(groups)} independent prices \"\n      f\"({100 * (1 - len(groups) \/ len(quotes)):.1f}% collapse)\")\n\nfor tup, slugs in sorted(groups.items(), key=lambda kv: -len(kv[1]))[:3]:\n    print(tup, len(slugs), slugs[:5])\n<\/code><\/pre>\n<h2>The men&#8217;s and women&#8217;s competitions draw different bookmakers<\/h2>\n<p>We expected the AFLW round to run thinner than the men&#8217;s finals. It runs wider. Nine AFLW fixtures carried 116 to 121 books each; the two preliminary finals carried 104 and 124.<\/p>\n<p>The populations barely match. <strong>31 books priced the AFLW round and neither preliminary final. 35 books did the reverse.<\/strong> The Unibet group, along with neds.com.au, TABtouch, BetRivers, ATG and Svenska Spel, appeared on all nine women&#8217;s fixtures and on no men&#8217;s final. The bet365 group of nine slugs, Betway, FanDuel, Kalshi, PMU and Tipico appeared on both men&#8217;s finals and on no women&#8217;s fixture.<\/p>\n<p>If you test coverage on one fixture and generalise, you will describe half the market. Sample both competitions.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Bookmaker<\/th>\n<th>Priced fixtures<\/th>\n<th>Where<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>pointsbet.com.au<\/td>\n<td>11 of 11<\/td>\n<td>both, on market 313 with no draw leg<\/td>\n<\/tr>\n<tr>\n<td>1xbet, stake, superbet<\/td>\n<td>11 of 11<\/td>\n<td>both<\/td>\n<\/tr>\n<tr>\n<td>betfair-ex<\/td>\n<td>10 of 11<\/td>\n<td>both, tightest price on the board<\/td>\n<\/tr>\n<tr>\n<td>unibet.com.au, neds.com.au, tabtouch<\/td>\n<td>9 of 11<\/td>\n<td>AFLW only<\/td>\n<\/tr>\n<tr>\n<td>bet365, kalshi, fanduel, betway<\/td>\n<td>2 of 11<\/td>\n<td>AFL finals only<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Sixty-two slugs appeared on all eleven fixtures. For the sharp reference price, Betfair Exchange and its four network clones (fair999-ex, orbitx, piwi247-ex, sharpxch) quoted 1.62 \/ 2.58 at a <strong>0.49% overround<\/strong>, with Kalshi second at 2.00%. Those five exchange slugs carry one price between them, so count them once. <a href=\"https:\/\/oddspapi.io\/blog\/pointsbet-api-odds-access\/\">PointsBet Australia<\/a> was the only book on every fixture with an Australian licence attached.<\/p>\n<h2>The 80.0 that is not a price<\/h2>\n<p>One slug, betmgm.bet.br, published market 311 as 1.55 on Fremantle and <strong>80.0 on Geelong<\/strong>. The 80.0 looks like a draw price that landed on the away outcome. It carries <code>active: true<\/code>, <code>suspended: false<\/code> and a fresh timestamp, so no flag catches it.<\/p>\n<p>A best-price scanner without a guard reports a 3,393% improvement over the board median and sends you to a URL that will not take the bet. Band the price against the median before you rank:<\/p>\n<pre class=\"wp-block-code\"><code>from statistics import median\n\nmed_home = median(q[\"home\"] for q in quotes.values())\nmed_away = median(q[\"away\"] for q in quotes.values())\n\ndef sane(price, med):\n    return 0.5 * med &lt;= price &lt;= 1.5 * med\n\nbest_home = max((q[\"home\"], s) for s, q in quotes.items() if sane(q[\"home\"], med_home))\nbest_away = max((q[\"away\"], s) for s, q in quotes.items() if sane(q[\"away\"], med_away))\n\nprint(\"median\", med_home, med_away)          # 1.58 2.29\nprint(\"best  \", best_home, best_away)        # (1.64, 'spelet.lv') (2.58, 'sharpxch')\nprint(\"unguarded\", max((q[\"away\"], s) for s, q in quotes.items()))   # (80.0, 'betmgm.bet.br')\n<\/code><\/pre>\n<p>The real best price beats the median by 3.8% on Fremantle and 12.7% on Geelong. That is a normal <a href=\"https:\/\/oddspapi.io\/blog\/line-shopping-python-best-odds\/\">line shopping<\/a> gain, not a bug, and it survives the guard.<\/p>\n<h2>What you get, and what you do not<\/h2>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Scraping one Australian book<\/th>\n<th>OddsPapi <code>\/v4\/odds<\/code><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Books per fixture<\/td>\n<td>1<\/td>\n<td>104 to 124<\/td>\n<\/tr>\n<tr>\n<td>Market shapes handled<\/td>\n<td>whatever that site renders<\/td>\n<td>both market IDs in one payload<\/td>\n<\/tr>\n<tr>\n<td>Independent prices<\/td>\n<td>1<\/td>\n<td>16 to 29 after dedupe<\/td>\n<\/tr>\n<tr>\n<td>Exchange price<\/td>\n<td>separate account and API<\/td>\n<td>betfair-ex in the same call<\/td>\n<\/tr>\n<tr>\n<td>Price history<\/td>\n<td>whatever you stored<\/td>\n<td><code>\/v4\/historical-odds<\/code>, free tier<\/td>\n<\/tr>\n<tr>\n<td>Setup<\/td>\n<td>headless browser, proxies, breakage<\/td>\n<td>one API key<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Two honest limits. Aussie Rules carries the result market and nothing else: no line, no totals, no player props, because the catalogue defines two markets for the sport. And the state leagues run thinner than the national ones. On our pull, the AFL and AFLW fixtures held full boards while the VFL and WAFL matches on the same weekend had none open yet. Books post the national competitions first.<\/p>\n<h2>Pull it yourself<\/h2>\n<h3>1. Authenticate<\/h3>\n<p>The key goes in the query string. There is no header, and the free tier covers everything in this post.<\/p>\n<pre class=\"wp-block-code\"><code>import os, time, requests\n\nAPI_KEY = os.environ[\"ODDSPAPI_API_KEY\"]\nBASE = \"https:\/\/api.oddspapi.io\/v4\"\n\ndef get(path, **params):\n    params[\"apiKey\"] = API_KEY\n    r = requests.get(f\"{BASE}{path}\", params=params, timeout=30)\n    if r.status_code == 429:\n        time.sleep(5)\n        r = requests.get(f\"{BASE}{path}\", params=params, timeout=30)\n    r.raise_for_status()\n    return r.json()\n\nprint(len(get(\"\/sports\")), \"sports\")     # 69\n<\/code><\/pre>\n<h3>2. Find the fixtures<\/h3>\n<p>Aussie Rules is sportId 31. Ask for a window rather than a date, and set <code>to<\/code> to the day after the last day you want.<\/p>\n<pre class=\"wp-block-code\"><code>from datetime import date, timedelta\n\ntoday = date.today()\nfixtures = get(\"\/fixtures\", sportId=31,\n               **{\"from\": today.isoformat(),\n                  \"to\": (today + timedelta(days=9)).isoformat()})\n\nfor f in fixtures:\n    if f[\"hasOdds\"]:\n        print(f[\"startTime\"][:16], f[\"tournamentName\"],\n              f[\"participant1Name\"], \"v\", f[\"participant2Name\"], f[\"fixtureId\"])\n<\/code><\/pre>\n<p>That returned 14 fixtures across the AFL, AFLW, VFL and WAFL. <code>hasOdds<\/code> is a flag, not a depth signal, so probe <code>\/odds<\/code> on a few before you trust it. We cover that discovery pattern in more detail in the <a href=\"https:\/\/oddspapi.io\/blog\/soccer-fixtures-api\/\">soccer fixtures guide<\/a>.<\/p>\n<h3>3. Read the board<\/h3>\n<p>One call per fixture returns every bookmaker. Sleep a second between calls and never run them in parallel.<\/p>\n<pre class=\"wp-block-code\"><code>boards = {}\nfor f in fixtures:\n    if not f[\"hasOdds\"]:\n        continue\n    payload = get(\"\/odds\", fixtureId=f[\"fixtureId\"])\n    books = payload.get(\"bookmakerOdds\") or {}\n    if books:\n        boards[f[\"fixtureId\"]] = payload\n        print(f[\"participant1Name\"], \"v\", f[\"participant2Name\"], len(books), \"books\")\n    time.sleep(2)\n<\/code><\/pre>\n<h3>4. Resolve, dedupe, rank<\/h3>\n<p>Run <code>two_way_quotes<\/code> over each board, group on the price tuple, then compute the overround inside each leg-count class. Filter on the price-level <code>active<\/code> flag and the book-level <code>suspended<\/code> and <code>bookmakerIsActive<\/code> flags first. On this pull the board was <strong>98.5% active<\/strong>, the highest rate we have recorded on any sport, and the nine AFLW fixtures came back at 100%. Aussie Rules books post a price and stand behind it.<\/p>\n<pre class=\"wp-block-code\"><code>def overround(q):\n    legs = [q[\"home\"], q[\"away\"]] + ([q[\"draw\"]] if q[\"draw\"] else [])\n    return sum(1 \/ p for p in legs) - 1, len(legs)\n\nranked = []\nfor slug, q in quotes.items():\n    margin, legs = overround(q)\n    if 0 &lt; margin &lt; 0.30:          # drop the broken quotes\n        ranked.append((margin, legs, slug))\n\nfor margin, legs, slug in sorted(ranked)[:5]:\n    print(f\"{slug:&lt;20} {margin * 100:5.2f}%  {legs} legs\")\n<\/code><\/pre>\n<p>De-vig the deduped consensus for a fair price rather than trusting one book. The <a href=\"https:\/\/oddspapi.io\/blog\/no-vig-odds-api\/\">three de-vig methods<\/a> apply unchanged, with one AFL-specific note: the two-way and three-way boards agree. Proportional de-vig puts Fremantle at 59.5% on the two-leg quotes and 59.2% on the three-leg ones.<\/p>\n<h3>5. Read the history<\/h3>\n<p><code>\/v4\/historical-odds<\/code> is on the free tier and takes three bookmakers per call. It answers when a board opened, which no live call can.<\/p>\n<pre class=\"wp-block-code\"><code>hist = get(\"\/historical-odds\",\n           fixtureId=\"id3100065674372626\",\n           bookmakers=\"bet365,pointsbet.com.au,kalshi\")\n\nfor slug, book in hist[\"bookmakers\"].items():\n    for market_id, market in book[\"markets\"].items():\n        for outcome_id, outcome in market[\"outcomes\"].items():\n            snaps = sorted(outcome[\"players\"][\"0\"], key=lambda s: s[\"createdAt\"])\n            changes, prev = 0, None\n            for s in snaps:\n                if s[\"price\"] != prev:\n                    changes, prev = changes + 1, s[\"price\"]\n            print(f\"{slug:<18} {market_id}\/{outcome_id}  {len(snaps):>3} snapshots  \"\n                  f\"{changes - 1:>2} moves  opened {snaps[0]['createdAt'][:16]}\")\n<\/code><\/pre>\n<p>The preliminary final board opened on 5 September at 16:21 UTC, five days and eighteen hours before the bounce. Finals boards cannot open earlier than that, because the semi-finals decide who plays. bet365 posted 1.60 \/ 29.0 \/ 2.35 at 17:58 UTC and had not moved a leg 37 hours later across 98 snapshots. PointsBet repriced Fremantle twice and Geelong three times. Kalshi moved its home price 62 times. Count price changes, not snapshots, or you will measure our polling instead of their trading.<\/p>\n<h2>FAQ<\/h2>\n<h3>Which bookmakers carry AFL odds?<\/h3>\n<p>We counted 156 distinct slugs across eleven finals-week fixtures on 7 September 2026, with 104 to 124 on any single match. PointsBet Australia, 1xBet, Stake and Superbet priced all eleven. Betfair Exchange priced ten and posted the tightest number on the board at a 0.49% overround.<\/p>\n<h3>Does the AFL board carry lines and totals?<\/h3>\n<p>The Aussie Rules catalogue defines two markets, both of them result markets: 311 Winner as a two-way, and 313 1X2 with a draw. For handicaps, totals and player props, the deep menus live on soccer, NFL and basketball.<\/p>\n<h3>Why do two AFL bookmakers show different margins on the same match?<\/h3>\n<p>Check the leg count before you compare. Fifteen books publish market 313 with only two prices, so their overround sums to about 5.8% while a complete three-way sums to 7.9%. Compare quotes with the same number of outcomes, and dedupe on the price tuple first, because 70% to 87% of an AFL board repeats another slug&#8217;s exact prices.<\/p>\n<h3>Is AFLW odds data as deep as the AFL?<\/h3>\n<p>Deeper on the pull we took. Nine AFLW fixtures carried 116 to 121 bookmakers each against 104 and 124 on the two preliminary finals, and every AFLW price came back active. The book populations differ: 31 slugs priced the women&#8217;s round and neither men&#8217;s final, and 35 did the reverse.<\/p>\n<h3>Is historical AFL odds data free?<\/h3>\n<p>Yes. <code>\/v4\/historical-odds<\/code> is on the free tier. The preliminary final board opened on 5 September at 16:21 UTC and had logged 1,240 snapshots across three bookmakers by the time we pulled it. The endpoint takes three bookmakers per call, so loop and merge.<\/p>\n<h2>Get the board<\/h2>\n<p>An <a href=\"https:\/\/oddspapi.io\/blog\/free-odds-api-350-bookmakers\/\">OddsPapi key is free<\/a> and reads 350+ bookmakers across 69 sports, with historical snapshots and WebSocket streaming on the same tier. Grab one, run the resolver above against this week&#8217;s fixtures, and see both market IDs land in the same dictionary.<\/p>\n<p><script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Which bookmakers carry AFL odds?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"We counted 156 distinct bookmaker slugs across eleven finals-week fixtures on 7 September 2026, with 104 to 124 on any single match. PointsBet Australia, 1xBet, Stake and Superbet priced all eleven fixtures. Betfair Exchange priced ten and posted the tightest number on the board at a 0.49% overround.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Which market IDs does Aussie Rules use?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Two. Market 311 is Winner, a two-way with outcome IDs 311 and 312. Market 313 is 1X2, a three-way with outcome IDs 313, 314 and 315. Bookmakers pick one shape, so on a preliminary final 78 books quoted 311, 41 quoted 313, and 26 quoted 313 and nothing else. Resolve on the market name and merge both IDs.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why do two AFL bookmakers show different margins on the same match?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Check the leg count first. Fifteen books publish market 313 with only two prices, so their overround sums to about 5.8% while a complete three-way sums to 7.9%. Compare quotes with the same number of outcomes, and dedupe on the price tuple before averaging, because 70% to 87% of an AFL board repeats another slug's exact prices.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Is AFLW odds data as deep as the AFL?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Deeper on this pull. Nine AFLW fixtures carried 116 to 121 bookmakers each against 104 and 124 on the two preliminary finals, and every AFLW price came back active. The populations differ as well: 31 slugs priced the women's round and neither men's final, while 35 did the reverse, so sample both competitions before you generalise.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Is historical AFL odds data free?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Yes. The \/v4\/historical-odds endpoint is on the free tier. A preliminary final board opened on 5 September 2026 at 16:21 UTC and had logged 1,240 snapshots across three bookmakers when we pulled it. The endpoint takes three bookmakers per call, so loop and merge, and count price changes rather than snapshots.\"\n      }\n    }\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: afl odds api\nSEO Title: AFL Odds API: Merge Two Market IDs Into a 124-Book Board\nMeta Description: An AFL odds API pull across 11 finals-week fixtures found 156 bookmakers, and one AFLW fixture collapsed from 121 quotes to 16 independent prices.\nSlug: afl-odds-api\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>An AFL odds API pull across 11 finals-week fixtures found 156 bookmakers, and one AFLW fixture collapsed from 121 quotes to 16 independent prices.<\/p>\n","protected":false},"author":2,"featured_media":3888,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[96,12,9,11,10],"class_list":["post-3887","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-afl","tag-betting-data","tag-odds-api","tag-python","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>AFL Odds API: Merge Two Market IDs Into a 124-Book Board | 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\/afl-odds-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"AFL Odds API: Merge Two Market IDs Into a 124-Book Board | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"An AFL odds API pull across 11 finals-week fixtures found 156 bookmakers, and one AFLW fixture collapsed from 121 quotes to 16 independent prices.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-14T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-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=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"AFL Odds API: Merge Two Market IDs Into a 124-Book Board\",\"datePublished\":\"2026-09-14T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/\"},\"wordCount\":1809,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp\",\"keywords\":[\"AFL\",\"Betting Data\",\"Odds API\",\"Python\",\"Sports Betting API\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/\",\"name\":\"AFL Odds API: Merge Two Market IDs Into a 124-Book Board | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp\",\"datePublished\":\"2026-09-14T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"AFL Odds API header image\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"AFL Odds API: Merge Two Market IDs Into a 124-Book Board\"}]},{\"@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":"AFL Odds API: Merge Two Market IDs Into a 124-Book Board | 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\/afl-odds-api\/","og_locale":"en_US","og_type":"article","og_title":"AFL Odds API: Merge Two Market IDs Into a 124-Book Board | OddsPapi Blog","og_description":"An AFL odds API pull across 11 finals-week fixtures found 156 bookmakers, and one AFLW fixture collapsed from 121 quotes to 16 independent prices.","og_url":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-09-14T10:00:00+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-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":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"AFL Odds API: Merge Two Market IDs Into a 124-Book Board","datePublished":"2026-09-14T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/"},"wordCount":1809,"commentCount":1,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp","keywords":["AFL","Betting Data","Odds API","Python","Sports Betting API"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/afl-odds-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/","url":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/","name":"AFL Odds API: Merge Two Market IDs Into a 124-Book Board | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp","datePublished":"2026-09-14T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/afl-odds-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/09\/afl-odds-api-scaled.webp","width":2560,"height":1429,"caption":"AFL Odds API header image"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/afl-odds-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"AFL Odds API: Merge Two Market IDs Into a 124-Book Board"}]},{"@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\/3887","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=3887"}],"version-history":[{"count":2,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3887\/revisions"}],"predecessor-version":[{"id":3898,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3887\/revisions\/3898"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/3888"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=3887"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=3887"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=3887"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}