{"id":3871,"date":"2026-09-09T10:00:00","date_gmt":"2026-09-09T10:00:00","guid":{"rendered":"https:\/\/oddspapi.io\/blog\/?p=3871"},"modified":"2026-08-31T14:21:27","modified_gmt":"2026-08-31T14:21:27","slug":"nfl-player-props-api","status":"publish","type":"post","link":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/","title":{"rendered":"NFL Player Props API: Fifteen Yardage Lines on One Receiver"},"content":{"rendered":"<p>You want NFL player props in JSON: anytime touchdown scorers, receiving yards, quarterback passing totals. You pull the fixture, walk the odds payload the way every game-line tutorial shows you, and the prop board comes back empty. Then you group what you do find by market ID and the numbers refuse to line up.<\/p>\n<p>Both problems have the same root. The NFL prop board is not shaped like the moneyline board, and the code that reads one cannot read the other. This post walks the real structure using the Week 1 opener, Seattle Seahawks v New England Patriots, pulled live from the OddsPapi API on 31 August 2026. Every number below comes out of that payload.<\/p>\n<h2>Two Traps Before You Write a Line of Code<\/h2>\n<p>The first trap is the parser. On a game line, each outcome holds a <code>players<\/code> dict with a single key, <code>\"0\"<\/code>. On a player prop, that same dict is keyed by player ID, and one outcome carries the whole depth chart at once. Hardcode <code>players[\"0\"]<\/code> and the entire prop board reads as zero. We hit the same wall on <a href=\"https:\/\/oddspapi.io\/blog\/mlb-player-props-api\/\">MLB props<\/a> and again on <a href=\"https:\/\/oddspapi.io\/blog\/college-football-player-props-api\/\">college football props<\/a>.<\/p>\n<p>The second trap is the one that costs you money, and it is specific to yardage markets. Cooper Kupp&#8217;s receiving yards carried <strong>15 distinct active rungs<\/strong> on this fixture. DraftKings posted 33.5. Caesars and FanDuel posted 32.5. ESPNBet and theScore posted 34.5. Forty-six books sat on 29.5. Each rung is a separate market ID. Group your scanner by market ID and DraftKings gets compared to two offshore books and nobody else, while the 46-book rung looks like a deep consensus when it is mostly one European feed wearing a lot of brand names.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Cooper Kupp, receiving yards<\/th>\n<th>Books on the rung<\/th>\n<th>Two-sided and active<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>9.5<\/td>\n<td>6<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td>19.5<\/td>\n<td>15<\/td>\n<td>0<\/td>\n<\/tr>\n<tr>\n<td><strong>29.5<\/strong><\/td>\n<td><strong>46<\/strong><\/td>\n<td><strong>31<\/strong><\/td>\n<\/tr>\n<tr>\n<td>32.5 (Caesars, FanDuel)<\/td>\n<td>5<\/td>\n<td>5<\/td>\n<\/tr>\n<tr>\n<td>33.5 (DraftKings)<\/td>\n<td>3<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<td>34.5 (ESPNBet, theScore)<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>39.5 and above<\/td>\n<td>12 to 16 each<\/td>\n<td>1 to 2 each<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<h2>The Old Way vs the OddsPapi Way<\/h2>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Task<\/th>\n<th>Scraping or a single-book API<\/th>\n<th>OddsPapi<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Prop coverage<\/td>\n<td>One book per integration, per sport<\/td>\n<td>99 books priced props on this one fixture, from a catalogue of 350+<\/td>\n<\/tr>\n<tr>\n<td>Ladder rungs<\/td>\n<td>Whatever that book posts<\/td>\n<td>Every rung every book posts, with the handicap attached<\/td>\n<\/tr>\n<tr>\n<td>Suspended lines<\/td>\n<td>Usually invisible in the HTML<\/td>\n<td><code>active<\/code> on the price, <code>suspended<\/code> on the book<\/td>\n<\/tr>\n<tr>\n<td>When the board opened<\/td>\n<td>Not recorded anywhere<\/td>\n<td>Free <code>\/historical-odds<\/code>, full snapshot history<\/td>\n<\/tr>\n<tr>\n<td>Duplicate feeds<\/td>\n<td>Counted as separate opinions<\/td>\n<td>Detectable by comparing the price tuple<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<h2>Step 1: Authenticate and Find the Fixture<\/h2>\n<p>The API key is a query parameter, never a header. <code>tournamentId=31<\/code> filters <code>\/fixtures<\/code> to the NFL server-side and cuts the payload by roughly twenty times.<\/p>\n<pre class=\"wp-block-code\"><code>import requests, time\nfrom collections import defaultdict\n\nAPI_KEY = \"YOUR_API_KEY\"\nBASE_URL = \"https:\/\/api.oddspapi.io\/v4\"\n\ndef call(path, **params):\n    \"\"\"apiKey is a query parameter. Honour retryMs on a 429.\"\"\"\n    params[\"apiKey\"] = API_KEY\n    for _ in range(5):\n        r = requests.get(f\"{BASE_URL}\/{path}\", params=params, timeout=600)\n        if r.status_code == 429:\n            time.sleep(r.json()[\"error\"][\"retryMs\"] \/ 1000 + 0.3)\n            continue\n        r.raise_for_status()\n        return r.json()\n    raise RuntimeError(\"rate limited\")\n\nfixtures = call(\"fixtures\", sportId=14, tournamentId=31,\n                **{\"from\": \"2026-09-09\", \"to\": \"2026-09-13\"})\nopener = sorted(fixtures, key=lambda f: f[\"startTime\"])[0]\nprint(opener[\"fixtureId\"], opener[\"startTime\"])\n# id1400003171515752 2026-09-10T00:20:00.000Z<\/code><\/pre>\n<p>Set <code>to<\/code> to the day after the last day you want. The window runs from midnight UTC to midnight UTC, so a same-day query returns only the fixtures that kick off at exactly 00:00Z.<\/p>\n<h3>Step 2: Build the Name Lookup<\/h3>\n<p>Market IDs and outcome IDs are integers. Names live in <code>\/markets<\/code>. The <code>sportId<\/code> parameter does nothing there, so treat the response as one global lookup table.<\/p>\n<pre class=\"wp-block-code\"><code>catalog = call(\"markets\", sportId=14)\nmarket_name  = {m[\"marketId\"]: m[\"marketName\"] for m in catalog}\nhandicap     = {m[\"marketId\"]: m.get(\"handicap\") for m in catalog}\noutcome_name = {(m[\"marketId\"], o[\"outcomeId\"]): o[\"outcomeName\"]\n                for m in catalog for o in m.get(\"outcomes\", [])}<\/code><\/pre>\n<h3>Step 3: Walk the Prop Tree<\/h3>\n<p>This generator is the whole parser. It skips the <code>\"0\"<\/code> key, drops the internal test feeds, and drops any book that has pulled the market while still returning prices.<\/p>\n<pre class=\"wp-block-code\"><code>odds  = call(\"odds\", fixtureId=opener[\"fixtureId\"])\nboard = odds[\"bookmakerOdds\"]\n\ndef prop_prices(board):\n    for slug, book in board.items():\n        if slug.startswith(\"pinnacle+\") or slug == \"demo\":\n            continue                      # internal test feeds\n        if book.get(\"suspended\"):\n            continue                      # book pulled the market\n        for mid, market in book[\"markets\"].items():\n            for oid, outcome in market[\"outcomes\"].items():\n                for player_id, price in outcome[\"players\"].items():\n                    if player_id == \"0\":\n                        continue          # \"0\" is the game line\n                    yield slug, int(mid), int(oid), price\n\nrows   = list(prop_prices(board))\nactive = [r for r in rows if r[3][\"active\"]]\nprint(f\"{len(rows)} prop prices, {len(active)} active, {len(board)} books on the fixture\")\n# 8508 prop prices, 5391 active, 259 books on the fixture<\/code><\/pre>\n<p>Two hundred and fifty-nine books quote this fixture. Ninety-nine of them price player props. The rest stop at game lines.<\/p>\n<h3>Step 4: Resolve the Ladder<\/h3>\n<p>Key on the player name and the handicap together, and the rungs separate cleanly. The <code>mainLine<\/code> flag will not do this for you; it agreed with the consensus spread on only 46% of NFL flags when we <a href=\"https:\/\/oddspapi.io\/blog\/nfl-alternate-lines-api\/\">measured it across the alt-line board<\/a>.<\/p>\n<pre class=\"wp-block-code\"><code>FAMILY = \"Over Under Player Receiving Yards (incl. overtime)\"\n\nrungs = defaultdict(lambda: defaultdict(dict))\nfor slug, mid, oid, price in prop_prices(board):\n    if market_name.get(mid) != FAMILY or not price[\"active\"]:\n        continue\n    side = outcome_name.get((mid, oid))\n    rungs[price[\"playerName\"]][handicap[mid]].setdefault(slug, {})[side] = price[\"price\"]\n\nplayer = \"Kupp, Cooper\"\nprint(f\"{player}: {len(rungs[player])} distinct active rungs\")\nfor line in sorted(rungs[player]):\n    books = rungs[player][line]\n    two   = [s for s, v in books.items() if \"Over\" in v and \"Under\" in v]\n    print(f\"  {line:>6}  {len(books):>3} books, {len(two):>2} two-sided\")\n\n# Kupp, Cooper: 15 distinct active rungs\n#     9.5    6 books,  0 two-sided\n#    14.5    2 books,  1 two-sided\n#    19.5   15 books,  0 two-sided\n#    24.5    2 books,  1 two-sided\n#    29.5   46 books, 31 two-sided\n#    32.5    5 books,  5 two-sided\n#    33.5    3 books,  3 two-sided\n#    34.5    2 books,  2 two-sided\n#    39.5   16 books,  2 two-sided\n#    ...<\/code><\/pre>\n<p>Note the two-sided column. Most rungs carry an Over and no Under, because books run a wide one-sided alt ladder around the line they actually want. You can only de-vig a rung that has both sides active.<\/p>\n<h3>Step 5: Dedupe Before You Average<\/h3>\n<p>Compare each book&#8217;s full prop tuple against every other book&#8217;s. Identical tuples mean one feed, several brands.<\/p>\n<pre class=\"wp-block-code\"><code>sig = defaultdict(list)\nfor slug in board:\n    tup = tuple(sorted((m, o, p[\"playerName\"], p[\"price\"])\n                       for s, m, o, p in prop_prices({slug: board[slug]})))\n    if tup:\n        sig[tup].append(slug)\n\nprint(f\"{sum(len(g) for g in sig.values())} prop books -> {len(sig)} independent\")\nfor g in sorted(sig.values(), key=len, reverse=True)[:3]:\n    print(f\"  {len(g)}x {sorted(g)[:5]}\")\n\n# 99 prop books -> 39 independent\n#   21x ['7bet.co.uk', '7bet.lt', 'allbritishcasino', 'alphawin', 'betinia.dk']\n#   10x ['leovegas.es', 'paf.es', 'prolineplus', 'scooore.be', 'unibet.be']\n#    9x ['betcity.nl', 'betmgm.co.uk', 'betparx', 'betplay', 'betuk']<\/code><\/pre>\n<p>Ninety-nine books collapse to 39 independent prop opinions, a 60.6% reduction. The largest group runs 21 slugs deep. Eight Betano skins ship 180 identical prices each. Skip this step and a consensus line counts one trading desk twenty-one times.<\/p>\n<p>The catalogue will not do the work for you. Of the 259 books on this fixture, 96 carry a <code>cloneOf<\/code> value, and they appear in the payload alongside their parents rather than hiding behind them. Plenty of the identical groups above are flagged <code>cloneOf: null<\/code> on every member. Compare the prices, not the metadata.<\/p>\n<h3>Step 6: De-Vig a Rung<\/h3>\n<pre class=\"wp-block-code\"><code>line   = 29.5\nquotes = {s: v for s, v in rungs[player][line].items()\n          if \"Over\" in v and \"Under\" in v}\nscored = sorted(((1\/v[\"Over\"] + 1\/v[\"Under\"]), s, v) for s, v in quotes.items())\noverround, book, v = scored[0]\n\nprint(f\"{player} {line} receiving yards, {len(quotes)} two-sided quotes\")\nprint(f\"  tightest {book}: Over {v['Over']} \/ Under {v['Under']} = {100*(overround-1):.2f}% margin\")\nprint(f\"  fair Over  {1\/(1\/v['Over']\/overround):.3f}  ({100\/v['Over']\/overround:.1f}%)\")\nprint(f\"  fair Under {1\/(1\/v['Under']\/overround):.3f}  ({100\/v['Under']\/overround:.1f}%)\")\n\n# Kupp, Cooper 29.5 receiving yards, 31 two-sided quotes\n#   tightest apuestatotal: Over 1.87 \/ Under 1.87 = 6.95% margin\n#   fair Over  2.000  (50.0%)\n#   fair Under 2.000  (50.0%)<\/code><\/pre>\n<p>Thirty-one two-sided quotes on that rung, and the tightest still charges 6.95%. Props are expensive compared with the 2% to 4% you see on an NFL moneyline. Our <a href=\"https:\/\/oddspapi.io\/blog\/no-vig-odds-api\/\">no-vig guide<\/a> covers the shift and multiplicative methods if the proportional one above is too blunt for your model.<\/p>\n<h3>Step 7: Anytime Touchdown, and the Second Market ID<\/h3>\n<p>Anytime touchdown scorer ships under <strong>two<\/strong> market IDs on this fixture, 14388 and 144637, with outcome names split across <code>Yes<\/code>, <code>1+<\/code>, <code>2+<\/code> and <code>3+<\/code>. Resolve on the market name and collect every ID that maps to it. Hardcode 14388 and you drop part of the board.<\/p>\n<pre class=\"wp-block-code\"><code>TD_IDS = {mid for mid, n in market_name.items()\n          if n == \"Player To Score TD (incl. overtime)\"}\n\ntd = defaultdict(dict)\nfor slug, mid, oid, price in prop_prices(board):\n    if mid in TD_IDS and outcome_name.get((mid, oid)) == \"Yes\" and price[\"active\"]:\n        td[price[\"playerName\"]][slug] = price[\"price\"]\n\nfor name, books in sorted(td.items(), key=lambda x: -len(x[1]))[:5]:\n    hi = max(books.items(), key=lambda x: x[1])\n    lo = min(books.items(), key=lambda x: x[1])\n    print(f\"  {name:<22} {len(books):>2} books  best {hi[1]:>5} ({hi[0]})\"\n          f\"  worst {lo[1]:>5} ({lo[0]})  +{100*(hi[1]\/lo[1]-1):.1f}%\")\n\n#   Shaheed, Rashid        25 books  best  4.36 (betfirst.be)  worst  3.25 (betano)  +34.2%\n#   Maye, Drake            25 books  best  5.51 (betfirst.be)  worst   4.2 (superbet.bet.br)  +31.2%\n#   Henry, Hunter          25 books  best 4.545 (kalshi)  worst   3.4 (betano)  +33.7%\n#   Holani, George         25 books  best  3.66 (betfirst.be)  worst   2.5 (betano)  +46.4%\n#   Kupp, Cooper           25 books  best  4.37 (betfirst.be)  worst   3.0 (fanduel)  +45.7%<\/code><\/pre>\n<p>Kupp to score at any point ran 3.00 at FanDuel and 4.37 at betfirst.be. That is a 45.7% gap in payout on the same bet. Anytime touchdown is a single-outcome market, so this is the best available price rather than a proven edge, and the two books may disagree because one has newer injury information. Either way, taking 3.00 when 4.37 is on the board is a decision you made by not looking. The same arithmetic drives our <a href=\"https:\/\/oddspapi.io\/blog\/line-shopping-python-best-odds\/\">line shopping walkthrough<\/a>.<\/p>\n<h2>Which Books Actually Price NFL Props<\/h2>\n<p>Ninety-nine of the 259 books on this fixture quoted at least one player prop. The list is US retail and European soft books. The sharps and the exchanges sat it out.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Book<\/th>\n<th>Prop prices<\/th>\n<th>Active<\/th>\n<th>Families<\/th>\n<th>Players<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>fanduel<\/code><\/td>\n<td>321<\/td>\n<td>91.6%<\/td>\n<td>9<\/td>\n<td>17<\/td>\n<\/tr>\n<tr>\n<td><code>caesars<\/code> \/ <code>williamhill<\/code><\/td>\n<td>250<\/td>\n<td>84.8%<\/td>\n<td>8<\/td>\n<td>17<\/td>\n<\/tr>\n<tr>\n<td><code>espnbet<\/code> \/ <code>thescore<\/code><\/td>\n<td>233<\/td>\n<td>96.1%<\/td>\n<td>8<\/td>\n<td>16<\/td>\n<\/tr>\n<tr>\n<td><code>draftkings<\/code><\/td>\n<td>200<\/td>\n<td>88.5%<\/td>\n<td>8<\/td>\n<td>16<\/td>\n<\/tr>\n<tr>\n<td><code>betano<\/code> (8 skins)<\/td>\n<td>180 each<\/td>\n<td>85.0%<\/td>\n<td>13<\/td>\n<td>21<\/td>\n<\/tr>\n<tr>\n<td><code>novig.us<\/code><\/td>\n<td>174<\/td>\n<td>86.2%<\/td>\n<td>7<\/td>\n<td>18<\/td>\n<\/tr>\n<tr>\n<td><code>kalshi<\/code><\/td>\n<td>110<\/td>\n<td>100.0%<\/td>\n<td>5<\/td>\n<td>7<\/td>\n<\/tr>\n<tr>\n<td><code>fanatics<\/code><\/td>\n<td>81<\/td>\n<td>66.7%<\/td>\n<td>4<\/td>\n<td>18<\/td>\n<\/tr>\n<tr>\n<td><code>pinnacle<\/code>, <code>bet365<\/code>, <code>betmgm<\/code>, <code>betfair-ex<\/code>, <code>polymarket<\/code>, <code>sbobet<\/code><\/td>\n<td>0<\/td>\n<td>n\/a<\/td>\n<td>n\/a<\/td>\n<td>n\/a<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Pinnacle, Bet365 and BetMGM all quote this fixture. They quote the moneyline, the spread and the totals, and they stop there. If your model needs a sharp reference price on a receiving-yards line, the NFL prop board will not give you one. Kalshi is the interesting entry: a prediction market pricing 110 player props, and it posted the best anytime-touchdown number on Hunter Henry.<\/p>\n<h2>The Prop Board Runs on a Different Clock<\/h2>\n<p>Here is the finding that explains why your first pull came back empty. On this fixture, FanDuel&#8217;s game lines entered the feed on <strong>9 August<\/strong>. Its player props entered on <strong>31 August at 00:27:16 UTC<\/strong>, ten days before kickoff. Twenty-two days separate the two boards at the same book on the same game.<\/p>\n<p>The free <code>\/historical-odds<\/code> endpoint keeps the full snapshot history, so you can measure this yourself rather than guess.<\/p>\n<pre class=\"wp-block-code\"><code>hist = call(\"historical-odds\", fixtureId=opener[\"fixtureId\"], bookmakers=\"fanduel\")\nfirst = {}\nfor mid, market in hist[\"bookmakers\"][\"fanduel\"][\"markets\"].items():\n    for oid, outcome in market[\"outcomes\"].items():\n        for player_id, snaps in outcome[\"players\"].items():\n            if not snaps:\n                continue\n            key = \"game line\" if player_id == \"0\" else market_name.get(int(mid))\n            opened = min(s[\"createdAt\"] for s in snaps)\n            first[key] = min(first.get(key, opened), opened)\n\nfor key, opened in sorted(first.items(), key=lambda x: x[1]):\n    print(opened, key)\n\n# 2026-08-09T00:27:50.819Z game line\n# 2026-08-31T00:27:16.241Z Player To Score TD (incl. overtime)\n# 2026-08-31T00:27:16.241Z Over Under Player Receiving Yards (incl. overtime)\n# 2026-08-31T00:27:16.241Z Over Under Rush Yards (incl. overtime)\n# 2026-08-31T00:27:16.241Z Over Under Pass Yards (incl. overtime)\n# 2026-08-31T00:27:16.241Z Over Under Player Receptions (incl. overtime)\n# 2026-08-31T00:27:16.241Z Over Under Player TD Passes (incl. overtime)\n# 2026-08-31T00:27:16.241Z To Score TD First Half (incl. overtime)\n# 2026-08-31T08:04:56.055Z Player To Score First TD (incl. overtime)<\/code><\/pre>\n<p>Seven families landed in the same second. That is a scheduled job firing, not a trader building a board market by market. First touchdown scorer followed 7.6 hours later.<\/p>\n<p>Four more books did the same thing that morning. DraftKings opened at 00:31:48 UTC, Caesars and ESPNBet at 00:34:19, Kalshi at 00:57:40. Five independent operators put NFL Week 1 props up inside thirty minutes of each other.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Book<\/th>\n<th>Game lines first seen<\/th>\n<th>Props first seen<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>draftkings<\/code><\/td>\n<td>2 Jun 2026 00:28 UTC<\/td>\n<td>2 Jun 2026 00:48 UTC, pulled 4 Jun, back 31 Aug 00:31 UTC<\/td>\n<\/tr>\n<tr>\n<td><code>fanduel<\/code><\/td>\n<td>9 Aug 2026 00:27 UTC<\/td>\n<td>31 Aug 2026 00:27 UTC<\/td>\n<\/tr>\n<tr>\n<td><code>caesars<\/code><\/td>\n<td>2 Jun 2026 00:45 UTC<\/td>\n<td>31 Aug 2026 00:34 UTC<\/td>\n<\/tr>\n<tr>\n<td><code>espnbet<\/code><\/td>\n<td>2 Jun 2026 00:45 UTC<\/td>\n<td>31 Aug 2026 00:34 UTC<\/td>\n<\/tr>\n<tr>\n<td><code>kalshi<\/code><\/td>\n<td>2 Jun 2026 00:41 UTC<\/td>\n<td>31 Aug 2026 00:57 UTC<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>DraftKings leaves one earlier fragment, and it is worth reading properly. It posted an anytime-touchdown board on 2 June, held it for three days, and pulled it: 60 snapshots across 2 to 4 June, then nothing at all until 31 August. That 2 June date is also exactly where NFL price collection begins, 100 days before kickoff, so treat it as the edge of the recording window rather than the moment a trader opened the board.<\/p>\n<p>The gap is the part that matters. For the twelve weeks between those two dates, this fixture had no player props at any book. Pull it in mid-August and you get 259 books, a full game-line board and an empty prop board, which is exactly what the other fifteen Week 1 fixtures still returned on 31 August. The 31 August timestamps carry no ambiguity, because those markets appeared inside a window we were already recording.<\/p>\n<p>The practical rule: schedule your prop scanner against kickoff, not against the calendar. Poll a fixture ten days out and you will find the board mid-build. Poll it two weeks out and you will find game lines only, which is exactly what the other fifteen Week 1 fixtures returned on the same afternoon. Our <a href=\"https:\/\/oddspapi.io\/blog\/when-do-nfl-odds-open\/\">272-fixture study of the NFL game-line board<\/a> maps the same clock for spreads and totals.<\/p>\n<h2>The Twenty-One Prop Families, and How Alive They Are<\/h2>\n<p>Active rate splits the board in two. Touchdown markets stay open. Yardage ladders sit mostly suspended, because a book posts twenty rungs and takes bets on three.<\/p>\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>Family<\/th>\n<th>Prices<\/th>\n<th>Active<\/th>\n<th>Books<\/th>\n<th>Players<\/th>\n<th>Market IDs<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Over Under Player Receiving Yards<\/td>\n<td>2,176<\/td>\n<td>62.5%<\/td>\n<td>91<\/td>\n<td>8<\/td>\n<td>41<\/td>\n<\/tr>\n<tr>\n<td>Over Under Rush Yards<\/td>\n<td>1,147<\/td>\n<td>53.9%<\/td>\n<td>91<\/td>\n<td>5<\/td>\n<td>31<\/td>\n<\/tr>\n<tr>\n<td>Over Under Pass Yards<\/td>\n<td>888<\/td>\n<td>41.1%<\/td>\n<td>90<\/td>\n<td>2<\/td>\n<td>35<\/td>\n<\/tr>\n<tr>\n<td>Player To Score TD<\/td>\n<td>830<\/td>\n<td>91.1%<\/td>\n<td>32<\/td>\n<td>23<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>Over Under Player Receptions<\/td>\n<td>801<\/td>\n<td>49.8%<\/td>\n<td>52<\/td>\n<td>8<\/td>\n<td>10<\/td>\n<\/tr>\n<tr>\n<td>Player To Score First TD<\/td>\n<td>581<\/td>\n<td>92.8%<\/td>\n<td>34<\/td>\n<td>23<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Over Under Player TD Passes<\/td>\n<td>410<\/td>\n<td>60.0%<\/td>\n<td>88<\/td>\n<td>2<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<td>Rush Yards (threshold ladder)<\/td>\n<td>338<\/td>\n<td>16.9%<\/td>\n<td>37<\/td>\n<td>5<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Over Under Rush TD<\/td>\n<td>330<\/td>\n<td>100.0%<\/td>\n<td>38<\/td>\n<td>5<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Pass Yards (threshold ladder)<\/td>\n<td>275<\/td>\n<td>23.6%<\/td>\n<td>38<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Over Under Player TD<\/td>\n<td>153<\/td>\n<td>94.8%<\/td>\n<td>6<\/td>\n<td>20<\/td>\n<td>3<\/td>\n<\/tr>\n<tr>\n<td>To Score TD Second Half<\/td>\n<td>132<\/td>\n<td>100.0%<\/td>\n<td>7<\/td>\n<td>18<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>To Score TD First Half<\/td>\n<td>126<\/td>\n<td>100.0%<\/td>\n<td>7<\/td>\n<td>17<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>To Score TD First Quarter<\/td>\n<td>75<\/td>\n<td>86.7%<\/td>\n<td>5<\/td>\n<td>13<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Over Under Player Interceptions<\/td>\n<td>56<\/td>\n<td>100.0%<\/td>\n<td>14<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Over Under Longest Rush Yards<\/td>\n<td>48<\/td>\n<td>100.0%<\/td>\n<td>8<\/td>\n<td>3<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>Over Under Longest Pass Completion<\/td>\n<td>48<\/td>\n<td>66.7%<\/td>\n<td>8<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>Over Under Field Goals<\/td>\n<td>36<\/td>\n<td>100.0%<\/td>\n<td>9<\/td>\n<td>2<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<td>Over Under Kicking Points<\/td>\n<td>32<\/td>\n<td>100.0%<\/td>\n<td>8<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>Over Under Pass Attempts<\/td>\n<td>22<\/td>\n<td>0.0%<\/td>\n<td>6<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<\/tr>\n<tr>\n<td>Over Under Pass Completions<\/td>\n<td>22<\/td>\n<td>0.0%<\/td>\n<td>6<\/td>\n<td>2<\/td>\n<td>2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n<p>Read the players column next to the books column. Receiving yards runs 91 books deep and 8 players wide. Anytime touchdown runs 32 books deep and 23 players wide. Books price the whole roster for a binary touchdown question and only the primary targets for a continuous yardage question, because a yardage line on a fourth receiver is a liability with no volume behind it.<\/p>\n<p>Two families ship with every price suspended. Pass attempts and pass completions are posted and closed. Filter on <code>active<\/code> at the price level or your scanner will report 44 quotes that nobody will take.<\/p>\n<p>Note the two naming conventions. <code>Over Under Rush Yards<\/code> is a two-sided market with a handicap, and you can de-vig it. Bare <code>Rush Yards<\/code> is a one-sided threshold ladder on a single market ID, with outcomes like <code>60+<\/code> and <code>90+<\/code>, and you cannot. Treat them as different market types even though the names look almost identical.<\/p>\n<h2>What to Build With This<\/h2>\n<p>The ladder resolver and the dedupe pass are the two pieces most prop scanners skip, and they are the two that decide whether your output means anything. Once both are in place the rest is arithmetic: de-vig the deepest two-sided rung to get a fair line, compare each book&#8217;s own rung against it, and rank by the gap. Our <a href=\"https:\/\/oddspapi.io\/blog\/player-props-value-scanner-python\/\">player props value scanner<\/a> walks that loop end to end, and <a href=\"https:\/\/oddspapi.io\/blog\/backtest-betting-model-free-historical-odds\/\">the backtesting guide<\/a> shows how to grade it against closing prices from the free historical endpoint. If you want a ready-made screener rather than your own, <a href=\"https:\/\/jedibets.com\" rel=\"nofollow\">jedibets.com<\/a> runs one over player props with Discord alerts.<\/p>\n<p>Point it at the right fixture, at the right time, and check what the board is actually made of. Ninety-nine books, 39 opinions, and a receiver with fifteen different lines on him.<\/p>\n<h2>FAQ<\/h2>\n<h3>Is there an official NFL player props API?<\/h3>\n<p>No. The NFL does not publish odds, and the sportsbooks that price props closed their public feeds years ago. DraftKings, FanDuel and Caesars all require a commercial partnership. OddsPapi aggregates the prop board from 99 books on a single Week 1 fixture through one REST call, with a free tier.<\/p>\n<h3>Which bookmakers price NFL player props?<\/h3>\n<p>On the Seattle v New England opener, FanDuel led with 321 prop prices, followed by Caesars and William Hill at 250, ESPNBet and theScore at 233, and DraftKings at 200. Eight Betano skins carried 180 each. Kalshi priced 110 props, which is unusual for a prediction market. Pinnacle, Bet365 and BetMGM quoted the game lines on this fixture and left the prop board alone.<\/p>\n<h3>Why do NFL props from different books look impossible to compare?<\/h3>\n<p>Because each rung of a yardage ladder is its own market ID. Cooper Kupp&#8217;s receiving yards carried 15 distinct active rungs on one fixture, with DraftKings on 33.5, Caesars and FanDuel on 32.5, and ESPNBet on 34.5. Group by market ID and you compare books that are not quoting the same bet. Key on the player name plus the handicap value instead.<\/p>\n<h3>When do NFL player props open?<\/h3>\n<p>Later than the game lines, and by a wide margin. On the Week 1 opener, FanDuel posted game lines on 9 August and props on 31 August at 00:27 UTC, ten days before kickoff. DraftKings followed at 00:31 UTC, Caesars and ESPNBet at 00:34, and Kalshi at 00:57, all on the same morning. Schedule any prop job relative to kickoff rather than on a fixed calendar.<\/p>\n<h3>How do I get the player name out of the odds payload?<\/h3>\n<p>On a player prop the <code>players<\/code> dict is keyed by player ID, not by <code>\"0\"<\/code>, and each entry carries a <code>playerName<\/code> field formatted as <code>\"Last, First\"<\/code>. One outcome holds the whole set of priced players. Iterating the dict and skipping the <code>\"0\"<\/code> key returns everything.<\/p>\n<h3>Can I backtest NFL props with free historical data?<\/h3>\n<p>Yes. <code>\/historical-odds<\/code> returns the full snapshot history for a fixture on the free tier, capped at three bookmakers per call. That is how the open times in this post were measured. Snapshots keep recording past kickoff, so filter on <code>createdAt<\/code> before <code>startTime<\/code> to get a genuine closing line.<\/p>\n<h2>Get Your Free API Key<\/h2>\n<p>Stop scraping prop pages that change their DOM every fortnight. One REST call returns 99 prop books, 21 families and 144 market IDs on a single NFL fixture, alongside 350+ bookmakers across every other sport, plus historical snapshots that competitors charge for. <a href=\"https:\/\/oddspapi.io\/\">Get your free OddsPapi API key<\/a> and read the <a href=\"https:\/\/oddspapi.io\/blog\/free-odds-api-350-bookmakers\/\">free tier guide<\/a> to see what fits inside it.<\/p>\n<p><script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\"@type\":\"Question\",\"name\":\"Is there an official NFL player props API?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"No. The NFL does not publish odds, and the sportsbooks that price props require a commercial partnership. OddsPapi aggregates the prop board from 99 bookmakers on a single Week 1 fixture through one REST call, with a free tier.\"}},\n    {\"@type\":\"Question\",\"name\":\"Which bookmakers price NFL player props?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"On the Seattle v New England Week 1 opener, FanDuel led with 321 prop prices, then Caesars and William Hill at 250, ESPNBet and theScore at 233, and DraftKings at 200. Eight Betano skins carried 180 each, and Kalshi priced 110 player props.\"}},\n    {\"@type\":\"Question\",\"name\":\"Why do NFL props from different books look impossible to compare?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Each rung of a yardage ladder is its own market ID. Cooper Kupp's receiving yards carried 15 distinct active rungs on one fixture, with DraftKings on 33.5, Caesars and FanDuel on 32.5, and ESPNBet on 34.5. Key on the player name plus the handicap value instead of the market ID.\"}},\n    {\"@type\":\"Question\",\"name\":\"When do NFL player props open?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Later than the game lines. On the Week 1 opener, FanDuel posted game lines on 9 August and player props on 31 August at 00:27 UTC, ten days before kickoff. DraftKings followed at 00:31 UTC, Caesars and ESPNBet at 00:34, and Kalshi at 00:57, all the same morning.\"}},\n    {\"@type\":\"Question\",\"name\":\"How do I get the player name out of the odds payload?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"On a player prop the players dict is keyed by player ID rather than by the string zero, and each entry carries a playerName field formatted as Last, First. One outcome holds every priced player, so iterate the dict and skip the zero key.\"}},\n    {\"@type\":\"Question\",\"name\":\"Can I backtest NFL props with free historical data?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Yes. The historical-odds endpoint returns full snapshot history for a fixture on the free tier, capped at three bookmakers per call. Snapshots keep recording past kickoff, so filter on createdAt before startTime to get a genuine closing line.\"}}\n  ]\n}\n<\/script><\/p>\n<p><!--\nFocus Keyphrase: NFL player props API\nSEO Title: NFL Player Props API: Fifteen Yardage Lines on One Receiver\nMeta Description: NFL player props run 15 active yardage rungs on one receiver across 100 books. Group by market ID and DraftKings at 33.5 gets compared to nobody.\nSlug: nfl-player-props-api\n--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>NFL player props run 15 active yardage rungs on one receiver across 100 books. Group by market ID and DraftKings at 33.5 gets compared to nobody.<\/p>\n","protected":false},"author":2,"featured_media":3872,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[52,9,51,11,10],"class_list":["post-3871","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-nfl","tag-odds-api","tag-player-props","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 Player Props API: Fifteen Yardage Lines on One Receiver | 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-player-props-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"NFL Player Props API: Fifteen Yardage Lines on One Receiver | OddsPapi Blog\" \/>\n<meta property=\"og:description\" content=\"NFL player props run 15 active yardage rungs on one receiver across 100 books. Group by market ID and DraftKings at 33.5 gets compared to nobody.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/\" \/>\n<meta property=\"og:site_name\" content=\"OddsPapi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-09T10:00:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-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=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/\"},\"author\":{\"name\":\"Odds API Writer\",\"@id\":\"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13\"},\"headline\":\"NFL Player Props API: Fifteen Yardage Lines on One Receiver\",\"datePublished\":\"2026-09-09T10:00:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/\"},\"wordCount\":2229,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp\",\"keywords\":[\"NFL\",\"Odds API\",\"Player Props\",\"Python\",\"Sports Betting API\"],\"articleSection\":[\"How To Guides\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/\",\"url\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/\",\"name\":\"NFL Player Props API: Fifteen Yardage Lines on One Receiver | OddsPapi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp\",\"datePublished\":\"2026-09-09T10:00:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage\",\"url\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp\",\"contentUrl\":\"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp\",\"width\":2560,\"height\":1429,\"caption\":\"NFL Player Props API - OddsPapi API Blog\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/oddspapi.io\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"NFL Player Props API: Fifteen Yardage Lines on One Receiver\"}]},{\"@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 Player Props API: Fifteen Yardage Lines on One Receiver | 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-player-props-api\/","og_locale":"en_US","og_type":"article","og_title":"NFL Player Props API: Fifteen Yardage Lines on One Receiver | OddsPapi Blog","og_description":"NFL player props run 15 active yardage rungs on one receiver across 100 books. Group by market ID and DraftKings at 33.5 gets compared to nobody.","og_url":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/","og_site_name":"OddsPapi Blog","article_published_time":"2026-09-09T10:00:00+00:00","og_image":[{"width":2560,"height":1429,"url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-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":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#article","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/"},"author":{"name":"Odds API Writer","@id":"https:\/\/oddspapi.io\/blog\/#\/schema\/person\/b6f21e649c4f556f0a95c23a0f1efa13"},"headline":"NFL Player Props API: Fifteen Yardage Lines on One Receiver","datePublished":"2026-09-09T10:00:00+00:00","mainEntityOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/"},"wordCount":2229,"commentCount":0,"publisher":{"@id":"https:\/\/oddspapi.io\/blog\/#organization"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp","keywords":["NFL","Odds API","Player Props","Python","Sports Betting API"],"articleSection":["How To Guides"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/","url":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/","name":"NFL Player Props API: Fifteen Yardage Lines on One Receiver | OddsPapi Blog","isPartOf":{"@id":"https:\/\/oddspapi.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage"},"image":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage"},"thumbnailUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp","datePublished":"2026-09-09T10:00:00+00:00","breadcrumb":{"@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#primaryimage","url":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp","contentUrl":"https:\/\/oddspapi.io\/blog\/wp-content\/uploads\/2026\/08\/nfl-player-props-api-scaled.webp","width":2560,"height":1429,"caption":"NFL Player Props API - OddsPapi API Blog"},{"@type":"BreadcrumbList","@id":"https:\/\/oddspapi.io\/blog\/nfl-player-props-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/oddspapi.io\/blog\/"},{"@type":"ListItem","position":2,"name":"NFL Player Props API: Fifteen Yardage Lines on One Receiver"}]},{"@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\/3871","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=3871"}],"version-history":[{"count":2,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3871\/revisions"}],"predecessor-version":[{"id":3874,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/posts\/3871\/revisions\/3874"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media\/3872"}],"wp:attachment":[{"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/media?parent=3871"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/categories?post=3871"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oddspapi.io\/blog\/wp-json\/wp\/v2\/tags?post=3871"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}