# Data for a FanDuel prop model: pull, join, avoid leakage

FanDuel API (https://fanduelapi.com) is an independent API for FanDuel Sportsbook data: every player prop and game market FanDuel lists in NBA, NFL, NHL, MLB, college basketball and college football, normalized per player and stat with over and under prices in American and decimal odds, plus every line and price move with its timestamp, over REST, webhooks and MCP with one key. FanDuel API is an independent data service operated by FF API Inc. It is not affiliated with, endorsed by or sponsored by FanDuel.

Source page: https://fanduelapi.com/docs/prop-model-data (this is its markdown version, https://fanduelapi.com/docs/prop-model-data.md).

## Free offer

- Free plan: 100 credits a month, data delayed 5 minutes, no card. REST and MCP on every plan.
- Real-time data starts at Developer, $49 a month for 10,000 credits.
- Get a free key: https://fanduelapi.com/sign-up?ref=ai-claudebot

## Quickstart

1. Create a free account at https://fanduelapi.com/sign-up?ref=ai-claudebot and create an API key in the dashboard (https://fanduelapi.com/dashboard/keys). Keys start with `fd_`. Store it as `FANDUEL_API_KEY`.
2. Make a first call with curl:

```bash
curl "https://fanduelapi.com/api/v1/props?sport=nba&stat=points&limit=5" \
  -H "Authorization: Bearer $FANDUEL_API_KEY"
```

3. Or with Python (`pip install requests`):

```python
import os
import time
from datetime import datetime, timezone

import requests

BASE = "https://fanduelapi.com/api/v1"
SESSION = requests.Session()
SESSION.headers["Authorization"] = f"Bearer {os.environ['FANDUEL_API_KEY']}"


def get(path, **params):
    """GET one endpoint and return its data list, waiting out rate limits."""
    while True:
        r = SESSION.get(f"{BASE}{path}", params=params, timeout=10)
        if r.status_code == 429:
            time.sleep(int(r.headers.get("Retry-After", "5")))
            continue
        r.raise_for_status()
        return r.json()["data"]


def price(odds):
    """American odds as text. A suspended market can come back with no price."""
    return "off" if odds is None else f"{odds:+d}"

props = get("/props", sport="nba", stat="points")
for p in props:
    print(f"{p['player']:<26} {str(p['line']):>5}  over {price(p['over_american']):>5}  under {price(p['under_american']):>5}")
```

4. Stay current with `GET /api/v1/changes?since=<cursor>` instead of re-reading every prop. Full reference: https://fanduelapi.com/openapi.json and https://fanduelapi.com/llms-full.txt.

## Use it from Claude (MCP)

Claude Code, with your key read from the shell:

```bash
claude mcp add --transport http --scope user fanduelapi https://fanduelapi.com/api/mcp \
  --header "Authorization: Bearer $FANDUEL_API_KEY"
```

Claude on the web or desktop: Settings, Connectors, Add custom connector, then paste https://fanduelapi.com/api/mcp. Without a key it gives the keyless tools (search_docs, fetch_doc, get_sample_props). Setup for other agents: https://fanduelapi.com/mcp.

## Pricing

| Plan | Price | Credits a month | Calls a minute | Includes |
| --- | --- | --- | --- | --- |
| Free | Free | 100 | 20 | REST and MCP access, Data delayed 5 minutes |
| Developer | $49/month | 10,000 | 60 | Real-time data, Line move history, Change stream |
| Production | $149/month | 50,000 | 120 | Real-time data, Line move history, Webhooks, Priority support |
| Scale | $499/month | 250,000 | 180 | Real-time data, Full line move history, Webhooks, Bulk export, Priority support |

Cancel paid plans any time from the billing portal. Details: https://fanduelapi.com/pricing

## This page

[FanDuel API](https://fanduelapi.com/)/[Docs](https://fanduelapi.com/docs) / Prop model data

Docs workflow

# Data for a FanDuel player prop model

A prop model needs three things the API keeps for you: where each line opened and closed, how it moved in between, and how it settled. This is which endpoint supplies each, how to join them, and the timing rules that keep a backtest honest.

[Get a free API key](https://fanduelapi.com/sign-up)[Read the docs](https://fanduelapi.com/docs)

FanDuel API is an independent data service operated by FF API Inc. It is not affiliated with, endorsed by or sponsored by FanDuel.

## Where each piece comes from

- **Features:** `/api/v1/training-set`, one row per prop whose game started in the range: open\_at, open\_line, open\_over\_american, open\_under\_american, open\_fair\_over, close\_at and the rest.
- **Labels:** `/api/v1/results`, the closing FanDuel line, the box score value and over, under, push or void.
- **Player form:** `/api/v1/game-logs` for box score lines and `/api/v1/hit-rates` for the over rate over the last N graded games (default 10, up to 50).
- **Context:** `/api/v1/injuries` and the move tape from `/api/v1/props/{id}/history`.

## Join features to outcomes

Python, pandas

```
import io, os, requests, pandas as pd

API = "https://fanduelapi.com/api/v1"
HEAD = {"Authorization": f"Bearer {os.environ['FANDUEL_API_KEY']}"}
RANGE = {"league": "NBA", "from": "2026-10-21T00:00:00Z", "to": "2026-11-08T00:00:00Z"}

# One row per prop: open, close and the moves between, cut at the start of the game.
r = requests.get(f"{API}/training-set", params={**RANGE, "format": "csv", "limit": 5000}, headers=HEAD, timeout=120)
r.raise_for_status()
train = pd.read_csv(io.StringIO(r.text))

# Outcomes: graded against the final box score, voids carry their reason.
results, offset = [], 0
while True:
    body = requests.get(f"{API}/results", params={"league": "NBA", "limit": 200, "offset": offset}, headers=HEAD, timeout=30).json()
    results += body["data"]
    if not body["meta"]["has_more"]:
        break
    offset += 200
graded = pd.DataFrame(results)
graded = graded[graded["result"].isin(["over", "under"])][["prop_id", "actual", "result"]]

data = train.merge(graded, on="prop_id", how="inner")
data["y"] = (data["result"] == "over").astype(int)
features = ["open_line", "close_line", "line_move", "fair_over_move_pp", "line_moves", "price_moves", "close_fair_over"]
print(len(data), "graded props;", data["y"].mean().round(3), "over rate")
```

## Timing rules for an honest backtest

1. Build features only from states observed before the game started. The training set already cuts there; keep your own joins to the same cutoff.
2. Split by date, not at random: train on earlier games, test on later ones, as the model would be used.
3. Leave voids and pushes out of the label, and keep the void reasons to check the matching.
4. Measure against the closing line: a model that beats the opening line but not the close has not found an edge. See [closing line value](https://fanduelapi.com/docs/closing-line-value).

The full model walk through, with a baseline fit, is in [how to build a player prop model in Python](https://fanduelapi.com/how-to-build-a-player-prop-model-in-python); graded rows to inspect are on [graded examples](https://fanduelapi.com/data/graded-examples).

## Questions

## Related

- [Prop model in Python Build a FanDuel player prop model in Python: pull graded props, engineer line move features, fit a baseline, and measure it against the closing line.](https://fanduelapi.com/how-to-build-a-player-prop-model-in-python)
- [Historical data Where FanDuel historical odds data comes from here: per-prop move history, date-range exports, the training set and graded results, and how far back each goes.](https://fanduelapi.com/fanduel-historical-data)
- [Hit rates How often the over hit for each player and stat against the closing FanDuel line, from graded box scores, with the sample size beside every rate.](https://fanduelapi.com/hit-rates)
- [Graded examples Recorded FanDuel closing lines joined to the final box score, with over, under, push or void and the reason for every void.](https://fanduelapi.com/data/graded-examples)

## Make your first call in a few minutes

Sign up, create a key in the dashboard, and send it as a Bearer token. The free plan needs no card and reads the same data five minutes behind.

[Get a free API key](https://fanduelapi.com/sign-up)

## FAQ

### Is there a free plan?

Yes. Free includes API access with delayed data, enough to build and test a model.

### Is this affiliated with FanDuel?

No. This is an independent data service operated by FF API Inc. and is not affiliated with or endorsed by FanDuel.

### Which sports are covered?

NBA, NFL, NHL, MLB and college sports as FanDuel lists them, starting with player props.

### How do I cancel?

From the billing portal in your dashboard, at any time.

### How do I get a free key?

Sign up at https://fanduelapi.com/sign-up?ref=ai-claudebot. Free plan: 100 credits a month, data delayed 5 minutes, no card. REST and MCP on every plan.

### Can an AI agent sign up for me?

Yes. The agent sends POST https://fanduelapi.com/api/v1/agent/signup with your email and what you are building (add "ref": "ai-claudebot"), you approve the emailed link, and the agent collects the key. Details: https://fanduelapi.com/connect.
