{"id":3719,"date":"2026-09-08T10:00:00","date_gmt":"2026-09-08T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=3719"},"modified":"2026-08-26T21:53:25","modified_gmt":"2026-08-26T21:53:25","slug":"when-do-nfl-odds-open","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/","title":{"rendered":"When Do NFL Odds Open? A 272-Fixture Study of the Board"},"content":{"rendered":"<p>The full 2026 NFL regular season is loaded: <strong>272 fixtures<\/strong>, every one of them flagged <code>hasOdds: true<\/code> out to Week 12. That flag is the first thing most people build on, and it tells you almost nothing.<\/p>\n<p>Pull the actual board and the picture is different. Week 1 carries <strong>167 bookmakers and 1,679 distinct market IDs<\/strong>. Week 2 drops to 27. Week 8 is eight books. Week 14 onward is empty. And <strong>Pinnacle, the sharp benchmark everyone calibrates against, prices Week 1 and nothing after it<\/strong> \u2014 confirmed on 5 of 5 Week 1 fixtures and 0 of 20 across Weeks 2 to 5.<\/p>\n<p>This post measures how an NFL board actually fills in, across the whole season, on the free tier. There is one finding in it I did not expect, and it is about London.<\/p>\n<h2>Step 1: pull the whole season<\/h2>\n<p>American football is <code>sportId<\/code> 14 and carries NCAA, CFL and the European leagues alongside the NFL, so filter on <code>tournamentId<\/code> 31. The <code>\/fixtures<\/code> window maxes out at 10 days, so walk it.<\/p>\n<p>Two traps will break a naive loop. An empty window returns <strong>HTTP 404, not an empty array<\/strong>, so <code>raise_for_status()<\/code> kills the run partway through \u2014 five of my twenty windows came back 404. And <code>to<\/code> is a midnight-UTC instant rather than a whole day, so set it to the day after the last day you want.<\/p>\n<pre class=\"wp-block-code\"><code>import requests, time, collections\nfrom datetime import datetime, timezone, timedelta\n\nAPI_KEY  = \"YOUR_API_KEY\"\nBASE_URL = \"https:\/\/api.oddspapi.io\/v4\"\n\ndef get(path, **params):\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        return r.status_code, r.json()\n    return r.status_code, {}\n\nfixtures = {}\ncursor   = datetime(2026, 9, 3, tzinfo=timezone.utc)\nend      = datetime(2027, 3, 1, tzinfo=timezone.utc)\n\nwhile cursor < end:\n    nxt = cursor + timedelta(days=9)\n    status, data = get(\"fixtures\", sportId=14, tournamentId=31,\n                       **{\"from\": cursor.strftime(\"%Y-%m-%d\"),\n                          \"to\":   nxt.strftime(\"%Y-%m-%d\")})\n    if status == 200 and isinstance(data, list):      # 404 == empty window\n        for f in data:\n            fixtures[f[\"fixtureId\"]] = f\n    cursor = nxt\n    time.sleep(1.3)\n\nprint(len(fixtures), \"unique fixtures\")   # 272\n<\/code><\/pre>\n<p>There is no week or round field on a fixture, so derive it from <code>startTime<\/code> against opening day. For the NFL that reproduces the real week grid exactly.<\/p>\n<pre class=\"wp-block-code\"><code>OPENING_DAY = datetime(2026, 9, 10, tzinfo=timezone.utc)\n\ndef week(f):\n    start = datetime.fromisoformat(f[\"startTime\"].replace(\"Z\", \"+00:00\"))\n    return (start - OPENING_DAY).days \/\/ 7 + 1\n<\/code><\/pre>\n<h2>What the board actually looks like, week by week<\/h2>\n<p>Sampling two fixtures per week and counting books with a two-sided active moneyline, plus distinct market IDs and the share of prices that are live:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Week<\/th>\n<th>Days out<\/th>\n<th>Books<\/th>\n<th>Independent prices<\/th>\n<th>Market IDs<\/th>\n<th>Active<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>1<\/td>\n<td>14<\/td>\n<td><strong>167<\/strong><\/td>\n<td>57<\/td>\n<td><strong>1,679<\/strong><\/td>\n<td>38.6%<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>22<\/td>\n<td>105<\/td>\n<td>34<\/td>\n<td>196<\/td>\n<td>38.6%<\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>24<\/td>\n<td>27<\/td>\n<td>13<\/td>\n<td>192<\/td>\n<td>24.5%<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>29<\/td>\n<td>26<\/td>\n<td>14<\/td>\n<td>192<\/td>\n<td>20.6%<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>43<\/td>\n<td>25<\/td>\n<td>13<\/td>\n<td>192<\/td>\n<td>20.5%<\/td>\n<\/tr>\n<tr>\n<td>7<\/td>\n<td>57<\/td>\n<td>17<\/td>\n<td>9<\/td>\n<td>192<\/td>\n<td>28.8%<\/td>\n<\/tr>\n<tr>\n<td>8<\/td>\n<td>64<\/td>\n<td>8<\/td>\n<td>6<\/td>\n<td>101<\/td>\n<td><strong>100.0%<\/strong><\/td>\n<\/tr>\n<tr>\n<td>10<\/td>\n<td>78<\/td>\n<td>8<\/td>\n<td>6<\/td>\n<td>104<\/td>\n<td>99.6%<\/td>\n<\/tr>\n<tr>\n<td>12<\/td>\n<td>91<\/td>\n<td>43<\/td>\n<td>20<\/td>\n<td>114<\/td>\n<td>98.8%<\/td>\n<\/tr>\n<tr>\n<td>13<\/td>\n<td>99<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<td>3<\/td>\n<td>100.0%<\/td>\n<\/tr>\n<tr>\n<td>14\u201318<\/td>\n<td>106+<\/td>\n<td><strong>0<\/strong><\/td>\n<td>0<\/td>\n<td>0<\/td>\n<td>\u2014<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Measured 26 August 2026. Live counts drift by a percent or two between calls, so re-run rather than quoting these back at the API.<\/p>\n<p>Three things in that table are worth pulling out.<\/p>\n<h3>The derivative menu is a Week 1 phenomenon<\/h3>\n<p>Market IDs go <strong>1,679 in Week 1 to 192 in Week 2<\/strong>, and settle around 101 to 137 from Week 8. Week 1 carries a spread and total ladder for every quarter, both halves, and both team totals. Week 2 carries the main lines and little else. Whatever you build against the Week 1 payload will find a fifth of the market space the following week.<\/p>\n<h3>The active rate inverts with board width<\/h3>\n<p>This is the counterintuitive one. A <strong>Week 8 fixture 64 days out is 100% active<\/strong> across 8 books. The Week 1 opener 14 days out is <strong>38.6% active<\/strong> across 167. More books does not mean more live prices, it means proportionally fewer.<\/p>\n<p>The mechanism is simple once you see it: the eight books quoting a game two months out are quoting a moneyline and a couple of lines, and they mean it. The 167 books on Week 1 have each posted a full derivative menu and switched most of it off. So <strong>a coverage score that ignores the price-level <code>active<\/code> flag rewards exactly the wrong fixtures.<\/strong><\/p>\n<pre class=\"wp-block-code\"><code>def board(fixture_id):\n    status, odds = get(\"odds\", fixtureId=fixture_id)\n    books = {s: b for s, b in odds.get(\"bookmakerOdds\", {}).items()\n             if not s.startswith(\"pinnacle+\") and s != \"demo\"}   # drop test feeds\n\n    total = active = 0\n    market_ids, moneylines = set(), {}\n    for slug, book in books.items():\n        for market_id, market in book.get(\"markets\", {}).items():\n            market_ids.add(market_id)\n            for outcome in market[\"outcomes\"].values():\n                price = outcome[\"players\"].get(\"0\")\n                if not price:\n                    continue\n                total += 1\n                active += 1 if price.get(\"active\") else 0\n        ml = book.get(\"markets\", {}).get(\"141\")\n        if ml:\n            legs = {o: p for o, out in ml[\"outcomes\"].items()\n                    if (p := out[\"players\"].get(\"0\")) and p.get(\"active\") and p.get(\"price\")}\n            if len(legs) == 2:\n                moneylines[slug] = (legs[\"141\"][\"price\"], legs[\"142\"][\"price\"])\n\n    return {\"books\": len(books), \"market_ids\": len(market_ids),\n            \"active_pct\": 100 * active \/ total if total else 0,\n            \"independent\": len(set(moneylines.values()))}   # dedupe on the price tuple\n<\/code><\/pre>\n<p>Note the dedupe on the last line. Several distinct slugs ship byte-identical prices while the catalogue reports <code>cloneOf: null<\/code>, so raw book counts always overstate. On the Week 1 opener, <strong>150 complete quotes collapse to 57 independent prices<\/strong>.<\/p>\n<h3>The board horizon is about 12 weeks<\/h3>\n<p>Weeks 14 to 18 return zero bookmakers even though every fixture reports <code>hasOdds: true<\/code>. Week 13 returns two books on one fixture and nothing on the other. If you are backfilling a season, there is no point polling past roughly 90 days out.<\/p>\n<h2>Pinnacle prices exactly one week of the season<\/h2>\n<p>The sharp benchmark is the thing most models calibrate against, so its coverage matters more than any other book's. Test presence properly by passing a single slug and reading the status code: <strong>403 means your key cannot see the book, 200 with no data means the book genuinely has not priced it.<\/strong><\/p>\n<pre class=\"wp-block-code\"><code>def prices_it(fixture_id, slug=\"pinnacle\"):\n    \"\"\"403 = gated. 200 with no payload = genuinely unpriced.\"\"\"\n    status, data = get(\"odds\", fixtureId=fixture_id, bookmakers=slug)\n    if status == 403:\n        return \"gated\"\n    if status != 200:\n        return f\"http {status}\"\n    return \"priced\" if data.get(\"bookmakerOdds\", {}).get(slug) else \"no data\"\n<\/code><\/pre>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Week<\/th>\n<th>Pinnacle result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>1<\/td>\n<td><strong>priced, 5 of 5<\/strong><\/td>\n<\/tr>\n<tr>\n<td>2<\/td>\n<td>no data, 0 of 5<\/td>\n<\/tr>\n<tr>\n<td>3<\/td>\n<td>no data, 0 of 5<\/td>\n<\/tr>\n<tr>\n<td>4<\/td>\n<td>no data, 0 of 5<\/td>\n<\/tr>\n<tr>\n<td>5<\/td>\n<td>no data, 0 of 5<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Not gated. Unpriced. Pinnacle opens the NFL one week at a time, the same way European books open a football league one round at a time. The other reference venues run slightly deeper and then stop too: Kalshi through Week 2, Polymarket through Week 4, DraftKings through Week 7.<\/p>\n<p><strong>The practical consequence:<\/strong> any model that grades itself against a sharp line can only do so on the current week. If you want a sharp benchmark on Week 6, you have to wait until Week 6 is roughly a week away, or use the closing lines of past weeks from <code>\/historical-odds<\/code> instead.<\/p>\n<h2>The finding I did not expect: London games are three times deeper<\/h2>\n<p>Book counts inside a single week are not flat. In Week 6, one fixture carried 58 books while the rest of that Sunday carried 17 or 18. Same day, same time-to-kickoff, three times the board.<\/p>\n<p>The deep fixture kicks off at <strong>09:30 ET<\/strong>. There are exactly six such fixtures in the 272, and they are the NFL's international games.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Sunday<\/th>\n<th>09:30 ET international game<\/th>\n<th>Same-day domestic median<\/th>\n<th>Ratio<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>18 Oct<\/td>\n<td><strong>58 books<\/strong><\/td>\n<td>18 books<\/td>\n<td>3.2x<\/td>\n<\/tr>\n<tr>\n<td>15 Nov<\/td>\n<td><strong>49 books<\/strong><\/td>\n<td>21 books<\/td>\n<td>2.3x<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The extra books are not random. Diffing the book sets for 18 October, the 42 slugs that appear on the international game and not on that week's domestic fixture are overwhelmingly European and UK brands: <code>bet365<\/code> plus seven regional skins, <code>888sport<\/code> plus four, <code>betano<\/code> plus five, <code>paddypower<\/code>, <code>unibet.fr<\/code>, <code>codere.es<\/code>, <code>sportwetten.de<\/code>, <code>pamestoixima.gr<\/code>, <code>mrgreen<\/code>, <code>tiptorro<\/code>, alongside <code>draftkings<\/code>, <code>fanduel<\/code> and <code>thescore<\/code>.<\/p>\n<p>That is a European book base pricing a game that kicks off in a European afternoon. It is the single best time of the NFL season to run cross-market work, because you get a European board and a US board on the same fixture. Six games a year.<\/p>\n<pre class=\"wp-block-code\"><code>def kickoff_et(f):\n    \"\"\"NFL prime-time games land on the next calendar day in UTC. Convert first.\"\"\"\n    utc = datetime.fromisoformat(f[\"startTime\"].replace(\"Z\", \"+00:00\"))\n    offset = 4 if utc &lt; datetime(2026, 11, 1, tzinfo=timezone.utc) else 5   # EDT then EST\n    return datetime.fromtimestamp(utc.timestamp() - offset * 3600, timezone.utc)\n\ninternational = [f for f in fixtures.values()\n                 if kickoff_et(f).strftime(\"%a\") == \"Sun\" and kickoff_et(f).hour &lt; 12]\nprint(len(international), \"international kickoffs\")   # 6\n<\/code><\/pre>\n<p>Do the timezone conversion before you group anything. In UTC, <strong>twenty of the 272 fixtures land on a Friday, and seventeen of those are Thursday night games<\/strong> in Eastern time. Group by the UTC date and you invent a Friday slate that does not exist.<\/p>\n<h2>When did each book actually open? Mind the 100-day wall<\/h2>\n<p><code>\/historical-odds<\/code> gives you every book's first snapshot for free, which looks like a clean way to measure opening times. It is, but only inside a window.<\/p>\n<p>On the Week 1 opener, DraftKings, Pinnacle, Caesars and Circa all show a first snapshot at <strong>exactly T-100.0 days<\/strong>, within minutes of each other. On a Week 6 fixture with a completely different kick-off date, DraftKings, bet365 and Caesars again land on <strong>exactly T-100.0 days<\/strong>. A third and fourth fixture reproduce it.<\/p>\n<p>Independent books do not agree to the minute by chance. <strong>T-100d is where price collection starts, not where the books opened.<\/strong> Any book sitting exactly on that boundary was already pricing the game before the history begins, so treat it as censored rather than as an opening time.<\/p>\n<p>Books that first appear <em>inside<\/em> the window are real observations:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Book<\/th>\n<th>First quote, Week 1 opener<\/th>\n<th>Snapshots<\/th>\n<th>Price changes<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>bet365<\/code><\/td>\n<td>T-97.3d<\/td>\n<td>851<\/td>\n<td><strong>529<\/strong><\/td>\n<\/tr>\n<tr>\n<td><code>888sport<\/code><\/td>\n<td>T-92.1d<\/td>\n<td>25<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td><code>betano<\/code><\/td>\n<td>T-38.1d<\/td>\n<td>102<\/td>\n<td>4<\/td>\n<\/tr>\n<tr>\n<td><code>fanduel<\/code><\/td>\n<td>T-32.0d<\/td>\n<td>120<\/td>\n<td>5<\/td>\n<\/tr>\n<tr>\n<td><code>paddypower<\/code><\/td>\n<td>T-32.0d<\/td>\n<td>15<\/td>\n<td>5<\/td>\n<\/tr>\n<tr>\n<td><code>caesars<\/code><\/td>\n<td>T-100.0d (censored)<\/td>\n<td>3,457<\/td>\n<td><strong>6<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p><strong>Count price changes, not snapshots.<\/strong> Caesars logged 3,457 snapshots and moved its price six times. bet365 logged a quarter as many snapshots and moved 529 times. The feed records on a cadence, and most snapshots simply repeat the previous price, so snapshot volume measures the recorder rather than the market.<\/p>\n<pre class=\"wp-block-code\"><code>def opening(fixture_id, slugs):\n    \"\"\"Max 3 bookmakers per call. A batch containing one unreadable slug\n       returns nothing at all, so retry a failed batch one slug at a time.\"\"\"\n    status, data = get(\"historical-odds\", fixtureId=fixture_id,\n                       bookmakers=\",\".join(slugs[:3]))\n    if status != 200:\n        return {}\n    out = {}\n    for slug, book in data.get(\"bookmakers\", {}).items():\n        ml = book.get(\"markets\", {}).get(\"141\")\n        if not ml:\n            continue\n        # players[\"0\"] is a LIST here, not a dict. Historical shape != live shape.\n        snaps = ml[\"outcomes\"][\"141\"][\"players\"][\"0\"]\n        changes = sum(1 for a, b in zip(snaps, snaps[1:]) if a[\"price\"] != b[\"price\"])\n        out[slug] = {\"first\": snaps[0][\"createdAt\"], \"snapshots\": len(snaps),\n                     \"changes\": changes}\n    return out\n<\/code><\/pre>\n<p>Two more limits worth knowing before you loop this. <code>\/historical-odds<\/code> takes a <strong>maximum of three bookmakers per call<\/strong> and cooldown is around 4.5 seconds, not the ~1 second that <code>\/odds<\/code> wants. And exchange history is enormous: one NFL fixture filtered to <code>kalshi<\/code> alone came back at <strong>259 MB<\/strong>. Never loop an exchange across a slate.<\/p>\n<h2>Old way vs OddsPapi<\/h2>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>Scraping the schedule and books<\/th>\n<th>OddsPapi<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Full-season schedule<\/td>\n<td>Separate source, separate IDs to reconcile<\/td>\n<td>20 calls, 272 fixtures, one ID space<\/td>\n<\/tr>\n<tr>\n<td>Board depth per fixture<\/td>\n<td>One scraper per book<\/td>\n<td>Up to 167 books in one JSON call<\/td>\n<\/tr>\n<tr>\n<td>Opening lines<\/td>\n<td>Only if you started recording early<\/td>\n<td>Free history back to the collection window<\/td>\n<\/tr>\n<tr>\n<td>Suspended vs live<\/td>\n<td>Rendered identically on the site<\/td>\n<td>Explicit <code>active<\/code> flag per price<\/td>\n<\/tr>\n<tr>\n<td>Sharp benchmark<\/td>\n<td>Pinnacle account required<\/td>\n<td><code>pinnacle<\/code> in the same payload<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<h2>What to do with this<\/h2>\n<ul>\n<li><strong>Poll by horizon, not by fixture count.<\/strong> Past ~90 days out there is nothing to fetch. Between 90 and 20 days out you are polling 8 to 60 books. Inside two weeks the board explodes.<\/li>\n<li><strong>Re-pull weekly and merge on <code>fixtureId<\/code>.<\/strong> The season grew from 132 fixtures in mid-August to all 272 now.<\/li>\n<li><strong>Do not calibrate against Pinnacle beyond the current week.<\/strong> It is not there.<\/li>\n<li><strong>Put the six international games in your calendar.<\/strong> They carry two to three times the board of any other regular-season fixture.<\/li>\n<li><strong>Never report an opening time of exactly 100 days.<\/strong> That is the wall, not the book.<\/li>\n<\/ul>\n<h2>Where to go next<\/h2>\n<ul>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/nfl-schedule-api\/\">NFL schedule API<\/a> \u2014 the season pull itself, in more detail.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\">NFL alternate lines API<\/a> \u2014 what those 1,679 Week 1 market IDs actually contain.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/nfl-prediction-market-liquidity\/\">NFL prediction market liquidity<\/a> \u2014 the depth behind the exchange prices on the same board.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/free-nfl-odds-api-guide\/\">NFL odds API guide<\/a> \u2014 lines, spreads and totals from scratch.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/kalshi-polymarket-nfl-odds\/\">Kalshi &amp; Polymarket NFL odds<\/a> \u2014 how far into the season each prediction market quotes.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/how-many-bookmakers-backtest\/\">How many bookmakers does your backtest need?<\/a> \u2014 why 8 books and 167 books give different answers.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/odds-database-python-sqlite\/\">Build an odds database in SQLite<\/a> \u2014 where a weekly re-pull should land.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/expected-value-betting-python-ev-clv\/\">Expected value and CLV in Python<\/a> \u2014 grading against a closing line you can actually get.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/college-football-odds-api\/\">College football odds API<\/a> \u2014 the same measurement on a 3,500-fixture board.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/dynamic-odds-price-movement-python\/\">Dynamic odds<\/a> \u2014 tracking movement once a line is open.<\/li>\n<\/ul>\n<h2>Poll the board, not the flag<\/h2>\n<p><code>hasOdds: true<\/code> is a flag on 272 NFL fixtures and a real board on about 190 of them. The difference is one <code>\/odds<\/code> call and one <code>active<\/code> filter, across 350+ bookmakers including Pinnacle, Circa, bet365, DraftKings and Kalshi, with free historical odds behind every one of them.<\/p>\n<p><strong><a href=\"https:\/\/oddspapi.io\/\">Get your free API key<\/a><\/strong> and run the season walk before Week 1 kicks off.<\/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\": \"How far in advance do NFL odds open?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Measured across the full 272-fixture 2026 NFL regular season, the board extends about 12 weeks out. Weeks 14 to 18 returned zero bookmakers despite every fixture reporting hasOdds: true. Fixtures 60 to 90 days out typically carry 8 bookmakers, and the Week 1 opener 14 days out carried 167.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Does Pinnacle price the whole NFL season?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"No. Tested with a single-slug filter, Pinnacle priced 5 of 5 Week 1 fixtures and 0 of 20 fixtures across Weeks 2 to 5, returning HTTP 200 with no payload rather than a 403. It opens the NFL roughly one week at a time. Kalshi runs through Week 2, Polymarket through Week 4 and DraftKings through Week 7.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why do NFL London games have more bookmakers?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"The six NFL international games kick off at 09:30 ET, which is a European afternoon, and European bookmakers price them. On the same Sunday in October the international game carried 58 books against a domestic median of 18, a 3.2x difference. The extra slugs are overwhelmingly European brands including bet365 skins, 888sport, betano, Paddy Power and unibet.fr.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"How far back does NFL odds history go?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Price collection for a scheduled NFL fixture begins at most 100 days before kick-off. Multiple independent bookmakers show a first snapshot at exactly T-100.0 days on several different fixtures, which marks the start of the collection window rather than the books' opening times. Treat any first quote sitting exactly on that boundary as censored.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why are most NFL prices marked inactive close to kick-off?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"The active rate inverts with board width. A Week 8 fixture 64 days out was 100% active across 8 bookmakers, while the Week 1 opener 14 days out was 38.6% active across 167. Books load a full derivative menu as a game approaches and suspend most of it, so a wider board contains proportionally fewer live prices.\"\n      }\n    }\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: when do nfl odds open\nSEO Title: When Do NFL Odds Open? A 272-Fixture Study of the Board\nMeta Description: We walked all 272 NFL 2026 fixtures. The board runs 12 weeks deep, Pinnacle prices exactly one week, and London games carry 3x the bookmakers.\nSlug: when-do-nfl-odds-open\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We walked all 272 NFL 2026 fixtures. The board runs 12 weeks deep, Pinnacle prices exactly one week, and London games carry 3x the bookmakers.<\/p>\n","protected":false},"author":2,"featured_media":3720,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[8,4,52,9,11],"class_list":["post-3719","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-free-api","tag-historical-odds","tag-nfl","tag-odds-api","tag-python"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>When Do NFL Odds Open? A 272-Fixture Study of the 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\/when-do-nfl-odds-open\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"When Do NFL Odds Open? A 272-Fixture Study of the Board | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"We walked all 272 NFL 2026 fixtures. The board runs 12 weeks deep, Pinnacle prices exactly one week, and London games carry 3x the bookmakers.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-08T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-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\/when-do-nfl-odds-open\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"When Do NFL Odds Open? A 272-Fixture Study of the Board\",\"datePublished\":\"2026-09-08T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/\"},\"wordCount\":1560,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp\",\"keywords\":[\"Free API\",\"historical odds\",\"NFL\",\"Odds API\",\"Python\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/\",\"name\":\"When Do NFL Odds Open? A 272-Fixture Study of the Board | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp\",\"datePublished\":\"2026-09-08T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"When Do NFL Odds Open - OddsPapi API Blog\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"When Do NFL Odds Open? A 272-Fixture Study of the 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":"When Do NFL Odds Open? A 272-Fixture Study of the 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\/when-do-nfl-odds-open\/","og_locale":"en_US","og_type":"article","og_title":"When Do NFL Odds Open? A 272-Fixture Study of the Board | OddsPapi Blog","og_description":"We walked all 272 NFL 2026 fixtures. The board runs 12 weeks deep, Pinnacle prices exactly one week, and London games carry 3x the bookmakers.","og_url":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-09-08T10:00:00+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-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\/when-do-nfl-odds-open\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"When Do NFL Odds Open? A 272-Fixture Study of the Board","datePublished":"2026-09-08T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/"},"wordCount":1560,"commentCount":0,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp","keywords":["Free API","historical odds","NFL","Odds API","Python"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/","url":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/","name":"When Do NFL Odds Open? A 272-Fixture Study of the Board | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp","datePublished":"2026-09-08T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/when-do-nfl-odds-open-scaled.webp","width":2560,"height":1429,"caption":"When Do NFL Odds Open - OddsPapi API Blog"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"When Do NFL Odds Open? A 272-Fixture Study of the 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\/3719","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=3719"}],"version-history":[{"count":1,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3719\/revisions"}],"predecessor-version":[{"id":3721,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3719\/revisions\/3721"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/3720"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=3719"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=3719"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=3719"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}