{"id":3716,"date":"2026-09-07T10:00:00","date_gmt":"2026-09-07T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=3716"},"modified":"2026-09-07T14:01:46","modified_gmt":"2026-09-07T14:01:46","slug":"nfl-alternate-lines-api","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/","title":{"rendered":"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check"},"content":{"rendered":"<p>Pull the NFL Week 1 opener from OddsPapi with no bookmaker filter and count the markets. You get <strong>1,679 distinct market IDs<\/strong> from 169 bookmakers: spreads from -24.5 to +19.5, totals from 30.5 to 68.5, team totals, first-half lines, and a separate handicap and total ladder for each of the four quarters.<\/p>\n<p>Now count the ones you can actually bet. <strong>414 have a single active price. 295 have a two-sided active quote from three or more books.<\/strong> That is 17.6% of the headline number. The other 82% is a menu the books have posted and suspended.<\/p>\n<p>This post is about the gap between those two numbers, and about the code that tells them apart. Everything below is measured live on all 16 NFL Week 1 fixtures, 422,141 prices, on the free tier.<\/p>\n<h2>The active rate falls off a cliff, family by family<\/h2>\n<p>Across the full 16-fixture slate, <strong>29.2% of 422,141 prices are active<\/strong>. That average hides the real structure. Sorted by how far a market sits from the moneyline:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Market family<\/th>\n<th>Prices<\/th>\n<th>Active<\/th>\n<th>Books present<\/th>\n<th>Market IDs<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Winner (incl. overtime)<\/td>\n<td>4,980<\/td>\n<td><strong>98.3%<\/strong><\/td>\n<td>164<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Total (incl. overtime)<\/td>\n<td>74,653<\/td>\n<td>67.2%<\/td>\n<td>155<\/td>\n<td>90<\/td>\n<\/tr>\n<tr>\n<td>Handicap (incl. overtime)<\/td>\n<td>67,475<\/td>\n<td>59.7%<\/td>\n<td>149<\/td>\n<td>101<\/td>\n<\/tr>\n<tr>\n<td>Over Under Team 1 (incl. overtime)<\/td>\n<td>35,698<\/td>\n<td>22.1%<\/td>\n<td>91<\/td>\n<td>120<\/td>\n<\/tr>\n<tr>\n<td>Over Under First Half<\/td>\n<td>24,634<\/td>\n<td>4.8%<\/td>\n<td>79<\/td>\n<td>120<\/td>\n<\/tr>\n<tr>\n<td>Handicap First Half<\/td>\n<td>19,402<\/td>\n<td>4.0%<\/td>\n<td>37<\/td>\n<td>121<\/td>\n<\/tr>\n<tr>\n<td>Over Under First Quarter<\/td>\n<td>18,574<\/td>\n<td>2.9%<\/td>\n<td>64<\/td>\n<td>80<\/td>\n<\/tr>\n<tr>\n<td>Handicap First Quarter<\/td>\n<td>9,790<\/td>\n<td>6.6%<\/td>\n<td>71<\/td>\n<td>81<\/td>\n<\/tr>\n<tr>\n<td>Over Under Fourth Quarter<\/td>\n<td>18,098<\/td>\n<td><strong>0.9%<\/strong><\/td>\n<td>21<\/td>\n<td>80<\/td>\n<\/tr>\n<tr>\n<td>Handicap Fourth Quarter<\/td>\n<td>9,242<\/td>\n<td><strong>1.0%<\/strong><\/td>\n<td>19<\/td>\n<td>81<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The moneyline is 98.3% live. The fourth-quarter handicap is 1.0% live. Same fixtures, same books, same payload, two weeks before kick-off.<\/p>\n<p>This is not a coverage problem, it is a timing one. Books load the whole derivative menu early and switch almost all of it off until the game is close. If you audit NFL market coverage a fortnight out and report a market count, you will report a number that is roughly five times what a bettor can touch.<\/p>\n<h2>Rule 1: never hardcode a market ID<\/h2>\n<p>American football has <strong>one market ID per line<\/strong>. There is no single &#8220;spread&#8221; or &#8220;totals&#8221; ID. On the opener, spread -3.5 is <code>14272<\/code> and -4 is <code>14270<\/code>; total 44.5 is <code>1464<\/code> and 45 is <code>1466<\/code>. The full-game handicap family alone spans <strong>101 distinct market IDs<\/strong> and the totals family 90.<\/p>\n<p>So resolve by name against the catalogue and collect every ID that maps to the family you want. Note that <code>sportId<\/code> on <code>\/v4\/markets<\/code> is a no-op: the catalogue is global (32,815 rows), not per sport, so use it purely as a lookup and read the live IDs off the <code>\/odds<\/code> payload.<\/p>\n<pre class=\"wp-block-code\"><code>import requests, time\n\nAPI_KEY = \"YOUR_API_KEY\"\nBASE_URL = \"https:\/\/api.oddspapi.io\/v4\"\n\ndef get(path, **params):\n    \"\"\"One retry on the documented 429 body, which carries retryMs.\"\"\"\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\nstatus, catalogue = get(\"markets\", sportId=14)\n\n# marketId -> (name, handicap, period). This is the only lookup you need.\nMETA = {m[\"marketId\"]: (m[\"marketName\"], m.get(\"handicap\"), m.get(\"period\"))\n        for m in catalogue}\nprint(len(META), \"market IDs in the catalogue\")   # 32815\n<\/code><\/pre>\n<h2>Rule 2: trust only the price-level <code>active<\/code> flag<\/h2>\n<p>Three fields look like liveness flags and only one is. <code>marketActive<\/code> sits on the market object, <code>bookmakerIsActive<\/code> and <code>suspended<\/code> sit on the book object, and all three disagree with their own prices often enough to break a parser. The flag that matters lives on the price object at <code>players[\"0\"]<\/code>, one level below the outcome.<\/p>\n<p>Two more filters belong in the same pass. Drop the internal test feeds \u2014 <code>pinnacle+30<\/code> and <code>pinnacle+5<\/code> quote the identical number to <code>pinnacle<\/code>, so an unfiltered count includes the sharp three times. And on game lines, prices key on <code>\"0\"<\/code>; player-keyed entries are prop markets and there are currently none on the NFL board.<\/p>\n<pre class=\"wp-block-code\"><code>import collections\n\nOPENER = \"id1400003171515752\"       # Seahawks v Patriots, 10 Sep 2026\n\nstatus, odds = get(\"odds\", fixtureId=OPENER)\n\nrows = []\nfor slug, book in odds[\"bookmakerOdds\"].items():\n    if slug.startswith(\"pinnacle+\") or slug == \"demo\":\n        continue\n    for market_id, market in book.get(\"markets\", {}).items():\n        name, handicap, period = META.get(int(market_id), (\"?\", None, None))\n        for outcome_id, outcome in market[\"outcomes\"].items():\n            price = outcome[\"players\"].get(\"0\")\n            if not price or not price.get(\"price\"):\n                continue\n            rows.append({\"book\": slug, \"market_id\": market_id, \"family\": name,\n                         \"handicap\": handicap, \"outcome\": outcome_id,\n                         \"price\": price[\"price\"], \"active\": price.get(\"active\"),\n                         \"main_line\": price.get(\"mainLine\"), \"limit\": price.get(\"limit\")})\n\nlive = [r for r in rows if r[\"active\"]]\nprint(len(rows), \"prices ->\", len(live), \"active\")\n# 46008 prices -> 17764 active   (38.6%)  -- live counts move minute to minute\nprint(len({r[\"market_id\"] for r in rows}), \"market IDs ->\",\n      len({r[\"market_id\"] for r in live}), \"with an active price\")\n# 1679 market IDs -> 414 with an active price\n<\/code><\/pre>\n<h2>Rule 3: a rung only counts if both sides are live<\/h2>\n<p>A one-sided quote cannot be de-vigged and cannot be compared to anything. Group by <code>(book, handicap)<\/code> inside a family and keep only the pairs.<\/p>\n<pre class=\"wp-block-code\"><code>def ladder(rows, family):\n    \"\"\"{(book, handicap): {outcome_id: row}} for two-sided ACTIVE rungs.\"\"\"\n    rungs = collections.defaultdict(dict)\n    for r in rows:\n        if r[\"family\"] != family or not r[\"active\"]:\n            continue\n        rungs[(r[\"book\"], r[\"handicap\"])][r[\"outcome\"]] = r\n    return {k: v for k, v in rungs.items() if len(v) == 2}\n\ndef margin(rung):\n    return (sum(1 \/ r[\"price\"] for r in rung.values()) - 1) * 100\n\nspreads = ladder(rows, \"Handicap (incl. overtime)\")\ntotals  = ladder(rows, \"Total (incl. overtime)\")\nprint(len(spreads), \"two-sided spread rungs,\", len(totals), \"total rungs\")\n# 2467 two-sided spread rungs, 3229 total rungs   (this fixture)\n<\/code><\/pre>\n<p>That is 2,467 spread rungs and 3,229 total rungs on the opener alone. Across all 16 fixtures it comes to <strong>19,790 two-sided active spread rungs and 24,895 total rungs<\/strong>. That is the real board.<\/p>\n<h2>The board splits into ladder-walkers and single-line books<\/h2>\n<p>On the opener, <strong>41 of 135 books quoting a two-sided spread quote exactly one rung<\/strong> and 94 walk a ladder. Across the full slate the balance flips: <strong>92 of 146 books show a median of exactly one spread rung<\/strong>. Books open a wider menu on the marquee game than on the Sunday slate around it. Some of those ladders are very long.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Book<\/th>\n<th>Spread rungs (median)<\/th>\n<th>Total rungs (median)<\/th>\n<th>Widest span seen<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>betnacional<\/code><\/td>\n<td>28<\/td>\n<td><strong>61<\/strong><\/td>\n<td>totals 30.0 to 59.5<\/td>\n<\/tr>\n<tr>\n<td><code>draftkings<\/code><\/td>\n<td>44<\/td>\n<td>39.5<\/td>\n<td>spreads -24.5 to +19.5<\/td>\n<\/tr>\n<tr>\n<td><code>jazzsports<\/code><\/td>\n<td>44<\/td>\n<td>39.5<\/td>\n<td>spreads -24.5 to +19.5<\/td>\n<\/tr>\n<tr>\n<td><code>betsson<\/code><\/td>\n<td><strong>45<\/strong><\/td>\n<td>\u2014<\/td>\n<td>spreads, 13 of 16 fixtures<\/td>\n<\/tr>\n<tr>\n<td><code>betano<\/code> (+6 skins)<\/td>\n<td>40<\/td>\n<td>38<\/td>\n<td>\u2014<\/td>\n<\/tr>\n<tr>\n<td><code>kalshi<\/code><\/td>\n<td>25<\/td>\n<td>16<\/td>\n<td>spreads -20.5 to +14.5<\/td>\n<\/tr>\n<tr>\n<td><code>pinnacle<\/code><\/td>\n<td>9<\/td>\n<td>13<\/td>\n<td>spreads -10.5 to +3.5<\/td>\n<\/tr>\n<tr>\n<td><code>circasports<\/code><\/td>\n<td>1<\/td>\n<td>1<\/td>\n<td>the consensus line only<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The split matters because it changes what a book is telling you. DraftKings quoting 43 rungs from -24.5 to +19.5 is a retail product: most of those rungs will never be bet. Pinnacle quoting 9 rungs around the number is a trading position. Circa quoting exactly one rung is a statement about where the line is.<\/p>\n<h3>Pinnacle&#8217;s ladder is U-shaped, and its limit ranks the rungs<\/h3>\n<p>On the opener, Pinnacle&#8217;s spread margin is tightest at <strong>2.88% on -3.5<\/strong>, the consensus line, and widens toward both wings. Its totals ladder bottoms out at <strong>3.86% on 44.5<\/strong>, again the consensus number.<\/p>\n<p>Pinnacle also publishes <code>limit<\/code>, which almost no other sportsbook does. It is a capped max <em>win<\/em>, not a capped stake, so recover the underlying base with <code>limit = max(base, base \/ (price - 1))<\/code>. On the opener that returns an <strong>implied base of $2,250 on the spread ladder and $1,500 on totals<\/strong> \u2014 the book will take 50% more on a spread than on a total, which is its own ranking of the two markets.<\/p>\n<pre class=\"wp-block-code\"><code>def implied_base(row):\n    \"\"\"Pinnacle's limit is a capped max win. Recover the per-market base.\"\"\"\n    lim = row.get(\"limit\")\n    if lim is None:\n        return None\n    return lim if row[\"price\"] >= 2 else lim * (row[\"price\"] - 1)\n<\/code><\/pre>\n<h2>The <code>mainLine<\/code> flag is wrong more often than it is right<\/h2>\n<p>Every price object carries <code>mainLine<\/code>, and it is tempting to use it to find the headline number. Measured against the consensus line across all 16 fixtures:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Family<\/th>\n<th>Flags set<\/th>\n<th>Matching the consensus line<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Handicap (incl. overtime)<\/td>\n<td>5,245<\/td>\n<td><strong>46.1%<\/strong><\/td>\n<\/tr>\n<tr>\n<td>Total (incl. overtime)<\/td>\n<td>6,025<\/td>\n<td><strong>35.7%<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>The failures are not spread evenly. <code>1xbet<\/code> and <code>22bet<\/code> score <strong>0 for 34<\/strong> on spreads, all seven <code>betano<\/code> skins score <strong>0 for 40<\/strong>, and <code>bcgame<\/code> 0 for 33 \u2014 these books set the flag on a rung that is never the line. At the other end <code>7bet.lt<\/code>, <code>betinia.dk<\/code>, <code>estrelabet<\/code>, <code>fezbet<\/code> and <code>winpot.mx<\/code> all land 28 of 32. A flag that is reliable at one book and never right at another is not a flag you can build on.<\/p>\n<p>This is the fourth sport where the same measurement fails. It runs 41% on NFL team totals, 17% on rugby, 8.6% on tennis. Treat <code>mainLine<\/code> as decoration.<\/p>\n<h3>&#8220;Closest to even money&#8221; does not work either<\/h3>\n<p>The obvious replacement is to take each book&#8217;s most balanced rung. On its own that misfires badly, because books leave stale wing rungs priced near even. On the opener, SBOBet&#8217;s <em>tightest<\/em> total is <strong>71.5<\/strong>, which is 27 points above the real number, and Kalshi&#8217;s tightest spread is <strong>-10.5<\/strong> against a -3.5 line. Bet365 quotes exactly one total on the whole fixture and it is <strong>37.0<\/strong>, seven and a half points off consensus.<\/p>\n<h3>What does work: balanced rung per book, then the mode<\/h3>\n<p>Take each book&#8217;s most balanced rung, then take the mode across all books. The individual errors above get outvoted.<\/p>\n<pre class=\"wp-block-code\"><code>def consensus_line(rungs):\n    \"\"\"Each book's most balanced rung, then the mode across books.\"\"\"\n    by_book = collections.defaultdict(list)\n    for (book, handicap) in rungs:\n        by_book[book].append(handicap)\n\n    picks = []\n    for book, handicaps in by_book.items():\n        def imbalance(h):\n            legs = sorted(rungs[(book, h)])\n            a, b = rungs[(book, h)][legs[0]], rungs[(book, h)][legs[1]]\n            return abs(1 \/ a[\"price\"] - 1 \/ b[\"price\"])\n        picks.append(min(handicaps, key=imbalance))\n\n    line, votes = collections.Counter(picks).most_common(1)[0]\n    return line, votes, len(picks)\n\nprint(consensus_line(spreads))   # (-3.5, 131, 135)\nprint(consensus_line(totals))    # (44.5, 121, 144)\n<\/code><\/pre>\n<p>Across the slate that resolver reaches a <strong>median 84% agreement on spreads and 81% on totals<\/strong>. Week 1 NFL sides and totals have converged hard: on the opener 131 of 135 books agree the spread is -3.5. Compare tennis, where the same method tops out around 71%.<\/p>\n<h2>The wing tax, and the whole-number discount that is not a discount<\/h2>\n<p>Margin rises as you walk away from the consensus line, which is what you would expect. Spreads run <strong>4.76% at the line<\/strong> and settle around 6.5\u20136.9% once you are a few points out; totals go 4.77% to 7.24%.<\/p>\n<p>But the pattern has a saw-tooth in it, and the reason is worth knowing. Split every rung by whether the handicap is a whole number or a half:<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Family<\/th>\n<th>Half-point rungs<\/th>\n<th>Whole-number rungs<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Handicap (incl. overtime)<\/td>\n<td>7.14% (n=16,186)<\/td>\n<td><strong>6.37%<\/strong> (n=3,604)<\/td>\n<\/tr>\n<tr>\n<td>Total (incl. overtime)<\/td>\n<td>6.98% (n=19,689)<\/td>\n<td><strong>6.43%<\/strong> (n=5,206)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Whole-number rungs look about 0.6pp cheaper. They are not. <strong>A whole number can push<\/strong>, so the book keeps a share of the handle without paying out, and it prices that into a lower nominal margin. Sorting an alt-line scan by margin puts every whole-number rung at the top and it is an artefact.<\/p>\n<p>Filter whole handicaps out before de-vigging, or compare them only against each other. On NFL specifically <strong>no rung in the sample summed below 100%<\/strong>, so there are no false arbitrage signals here \u2014 but the ranking is still wrong.<\/p>\n<h2>What you should actually pull<\/h2>\n<p>A working screen for alt lines on an NFL board, two weeks out:<\/p>\n<pre class=\"wp-block-code\"><code>def tradeable(rungs, min_books=3):\n    \"\"\"Handicaps with a two-sided active quote from at least min_books books.\"\"\"\n    votes = collections.defaultdict(set)\n    for (book, handicap) in rungs:\n        votes[handicap].add(book)\n    return {h: bs for h, bs in votes.items() if len(bs) >= min_books}\n\nline, _, _ = consensus_line(spreads)\nfor h, books in sorted(tradeable(spreads).items()):\n    quotes = [margin(spreads[(b, h)]) for b in books]\n    flag = \"  &lt;-- consensus\" if h == line else \"\"\n    print(f\"{h:>7}  {len(books):>3} books  median margin {sorted(quotes)[len(quotes)\/\/2]:5.2f}%{flag}\")\n<\/code><\/pre>\n<p>That is the difference between &#8220;the NFL board has 1,679 markets&#8221; and &#8220;the NFL board has 295 markets I can price-check against three independent books&#8221;. Build against the second number.<\/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 sportsbooks<\/th>\n<th>OddsPapi<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Alt-line ladders<\/td>\n<td>One scraper per book, breaks weekly<\/td>\n<td>169 books, one JSON call<\/td>\n<\/tr>\n<tr>\n<td>Quarter and half markets<\/td>\n<td>Usually behind a separate tab or endpoint<\/td>\n<td>Same payload, resolved by <code>marketName<\/code><\/td>\n<\/tr>\n<tr>\n<td>Suspended lines<\/td>\n<td>Rendered the same as live ones<\/td>\n<td>Explicit <code>active<\/code> flag per price<\/td>\n<\/tr>\n<tr>\n<td>Stake ceilings<\/td>\n<td>Not exposed<\/td>\n<td><code>limit<\/code> on Pinnacle and every exchange<\/td>\n<\/tr>\n<tr>\n<td>History<\/td>\n<td>Build it yourself from day one<\/td>\n<td>Free tier, retained for months<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<h2>Where to go next<\/h2>\n<ul>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/free-nfl-odds-api-guide\/\">NFL odds API guide<\/a> \u2014 moneylines, spreads and totals from a standing start.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/nfl-team-totals-api\/\">NFL team totals API<\/a> \u2014 derive team totals from the spread and total when only two books quote them directly.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/nfl-key-numbers-half-point-cost\/\">NFL key numbers<\/a> \u2014 what a half point around 3 and 7 is actually worth.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/nfl-schedule-api\/\">NFL schedule API<\/a> \u2014 pull the full season, and the two date traps that break a season loop.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/nfl-prediction-market-liquidity\/\">NFL prediction market liquidity<\/a> \u2014 the same board, measured on depth instead of breadth.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/college-football-odds-api\/\">College football odds API<\/a> \u2014 where the suspended-board problem is even worse.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/middle-bets-middling-python\/\">Middle bets in Python<\/a> \u2014 the main reason to walk an alt-line ladder in the first place.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/vig-calculator-python-sportsbook-margin\/\">Vig calculator in Python<\/a> \u2014 the margin maths used throughout this post.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/line-shopping-python-best-odds\/\">Line shopping in Python<\/a> \u2014 best price across the full board.<\/li>\n<li><a href=\"https:\/\/oddspapi.io\/blog\/betting-limits-api-stake-sizing\/\">Betting limits API<\/a> \u2014 how far the <code>limit<\/code> field goes.<\/li>\n<\/ul>\n<h2>Count what you can bet, not what you can see<\/h2>\n<p>A market count is the easiest number to publish and the least useful one to build on. The board that matters on an NFL Sunday is the subset that is two-sided, active, and quoted by enough independent books to check. On OddsPapi that subset is one <code>active<\/code> filter and one group-by away, across 350+ bookmakers including Pinnacle, SBOBET, Circa, DraftKings and Kalshi, with free historical odds behind it.<\/p>\n<p><strong><a href=\"https:\/\/oddspapi.io\/\">Get your free API key<\/a><\/strong> and run the ladder walk on this week&#8217;s slate.<\/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 do I get NFL alternate spreads and totals from an API?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Call OddsPapi's \/odds endpoint with a fixtureId and no bookmaker filter, then group prices by market family name and handicap. American football uses one market ID per line, so resolve families by marketName from \/v4\/markets rather than hardcoding IDs. The NFL Week 1 opener returns 1,679 distinct market IDs across 169 bookmakers.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why are most NFL alternate lines showing as inactive?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"Books load the full derivative menu weeks before kick-off and suspend nearly all of it until the game is close. Measured 14 days out across 16 NFL Week 1 fixtures, the moneyline was 98.3% active, full-game totals 67.2%, first-half totals 4.8% and fourth-quarter handicaps 1.0%. Filter on the price-level active flag, not on marketActive or suspended.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Is the mainLine flag reliable for finding the NFL main spread?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"No. Across 16 NFL Week 1 fixtures the mainLine flag matched the consensus line on 46.1% of 5,245 spread flags and 35.7% of 6,025 total flags. Several books, including 1xbet, 22bet and every betano skin, never set it on the real line. Resolve the line by taking each book's most balanced rung and then the mode across books, which reaches 84% agreement on spreads.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Why do whole-number NFL totals show a lower margin?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"A whole-number handicap or total can push, so the book retains a share of the handle without paying out and prices that into a lower nominal margin. Across the Week 1 slate whole-number rungs showed 6.37% on spreads against 7.14% on half-point rungs. Filter whole numbers out before de-vigging, or compare them only against each other.\"\n      }\n    },\n    {\n      \"@type\": \"Question\",\n      \"name\": \"Which bookmakers offer the deepest NFL alternate line ladders?\",\n      \"acceptedAnswer\": {\n        \"@type\": \"Answer\",\n        \"text\": \"On the NFL Week 1 slate, betnacional walked a median 61 total rungs, betsson 45 spread rungs, and DraftKings and jazzsports 44 spread rungs spanning -24.5 to +19.5. Pinnacle walks a much shorter 9-rung spread ladder centred on the consensus line, and 92 of 146 books quote exactly one spread rung.\"\n      }\n    }\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: nfl alternate lines api\nSEO Title: NFL Alternate Lines API: Find the 295 Markets You Can Price-Check\nMeta Description: Pull every NFL alt spread, total and quarter line in Python. We measured 422,141 Week 1 prices and show how to keep the 295 markets three books are trading.\nSlug: nfl-alternate-lines-api\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pull every NFL alt spread, total and quarter line in Python. We measured 422,141 Week 1 prices and show how to keep the 295 markets three books are trading.<\/p>\n","protected":false},"author":2,"featured_media":3717,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[8,52,9,11,10],"class_list":["post-3716","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-free-api","tag-nfl","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>NFL Alternate Lines API: Find the 295 Markets You Can Price-Check | 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\/nfl-alternate-lines-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"Pull every NFL alt spread, total and quarter line in Python. We measured 422,141 Week 1 prices and show how to keep the 295 markets three books are trading.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-07T10:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-07T14:01:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-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=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check\",\"datePublished\":\"2026-09-07T10:00:00+00:00\",\"dateModified\":\"2026-09-07T14:01:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\"},\"wordCount\":1597,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp\",\"keywords\":[\"Free API\",\"NFL\",\"Odds API\",\"Python\",\"Sports Betting API\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\",\"name\":\"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp\",\"datePublished\":\"2026-09-07T10:00:00+00:00\",\"dateModified\":\"2026-09-07T14:01:46+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"NFL Alternate Lines - OddsPapi API Blog\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check\"}]},{\"@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":"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check | 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\/nfl-alternate-lines-api\/","og_locale":"en_US","og_type":"article","og_title":"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check | OddsPapi Blog","og_description":"Pull every NFL alt spread, total and quarter line in Python. We measured 422,141 Week 1 prices and show how to keep the 295 markets three books are trading.","og_url":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-09-07T10:00:00+00:00","article_modified_time":"2026-09-07T14:01:46+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-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":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check","datePublished":"2026-09-07T10:00:00+00:00","dateModified":"2026-09-07T14:01:46+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/"},"wordCount":1597,"commentCount":0,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp","keywords":["Free API","NFL","Odds API","Python","Sports Betting API"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/","url":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/","name":"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp","datePublished":"2026-09-07T10:00:00+00:00","dateModified":"2026-09-07T14:01:46+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-alternate-lines-api-scaled.webp","width":2560,"height":1429,"caption":"NFL Alternate Lines - OddsPapi API Blog"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"NFL Alternate Lines API: Find the 295 Markets You Can Price-Check"}]},{"@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\/3716","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=3716"}],"version-history":[{"count":3,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3716\/revisions"}],"predecessor-version":[{"id":3891,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3716\/revisions\/3891"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/3717"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=3716"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=3716"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=3716"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}