Data for a PrizePicks prop model.
For developers choosing the data for a PrizePicks prop model: labeled lines, grades where available, game logs and matchup stats.
A prop model needs what the line was at the time you could have acted, and what actually happened. The API gives you both, keyed to the same projection, so you can build training rows without hand-joining box scores.
Not for

Base rates to beat, NBA graded lines
| Market | Standard over rate | Standard rows | All tier rows |
|---|---|---|---|
| Points | 43.9% | 726 | 5,417 |
| Pts+Rebs | 46.0% | 695 | 5,042 |
| Pts+Rebs+Asts | 44.4% | 723 | 4,633 |
| Rebounds | 47.9% | 422 | 4,037 |
| Pts+Asts | 46.2% | 563 | 4,011 |
| Rebs+Asts | 49.7% | 459 | 3,643 |
| Assists | 44.8% | 281 | 3,026 |
| 3-PT Made | 53.9% | 165 | 2,753 |
Games from 2026-10-28 to 2026-11-02. Pushes excluded. A short sample, so expect these to move. Every market and player
What one training row looks like
GET /api/v1/results returns one row per line. Use line as the target threshold: it is the last line observed before the start, and closing.gap_seconds says how long before. Treat actual_value and result as labels only.
| Field | Use in a model |
|---|---|
| line | The threshold you predict against, known before the game. |
| opening_line | Feature: how far the line moved before the start. |
| closing.gap_seconds | Filter: drop rows where the last observation is too old for your use. |
| sides | The tier on each side: standard, goblin or demon. |
| market.stat, player, event.opponent | Keys to join your own features. |
| actual_value, result, minutes | Labels. Never use these as features. |
Pull every graded row with Python
This writes one CSV row per graded line, paging with the numeric cursor. It uses only the standard library, so it runs anywhere.
import csv, json, os, time
from urllib.parse import urlencode
from urllib.request import Request, urlopen
KEY = os.environ["PRIZEPICKS_API_KEY"]
def results(league="NBA"):
cursor = None
while True:
params = {"league": league, "status": "graded", "limit": 200}
if cursor:
params["cursor"] = cursor
req = Request("https://prizepicksapi.com/api/v1/results?" + urlencode(params),
headers={"Authorization": "Bearer " + KEY})
with urlopen(req, timeout=30) as res:
page = json.load(res)
yield from page["data"]
cursor = page["meta"]["next_cursor"]
if not cursor:
return
time.sleep(1.1) # stays under the Free plan's per-minute limit
with open("training.csv", "w", newline="") as f:
out = csv.writer(f)
out.writerow(["date", "player", "stat", "tier", "line", "opening_line", "moved", "actual", "over"])
for r in results():
if r["result"] not in ("over", "under"):
continue # pushes carry no over or under label
moved = r["line"] - r["opening_line"] if r["opening_line"] is not None else ""
out.writerow([r["game_date"], r["player"]["name"], r["market"]["stat"], r["sides"].get("more", {}).get("tier"),
r["line"], r["opening_line"], moved, r["actual_value"], int(r["result"] == "over")])Keep the future out of your features
- Split by date, never at random. Lines for the same game are correlated, and a random split leaks them across folds.
- Build rolling player features only from games before game_date.
- Use line and opening_line, not any value recorded after the start.
- Report sample size per market and tier. Small markets swing hard.
- Drop rows with a large closing.gap_seconds if you act close to the start.
Measure against the base rate first
The table above this guide is the number to beat. A model that predicts the over rate for each market and tier has real skill only if it improves on that baseline out of sample. Check calibration too: a model that says 60% should hit about 60% of the time.
Score the live board
GET /api/v1/projections returns the same player, market and line fields for the current board. Pass view=compact for up to 1,000 rows per page. Run your features for those rows, then keep the line timestamp with each prediction so you can grade it later against /api/v1/results.
curl -G "https://prizepicksapi.com/api/v1/projections" \
-d league=NBA -d stat=Points -d view=compact -d limit=1000 \
-H "X-User-Request: Read PrizePicks data for an integration check" -H "Authorization: Bearer $PRIZEPICKS_API_KEY"Try it
Endpoint docs:GET /api/v1/resultsGET /api/v1/projections/{id}/historyPlans and limits
Frequently asked questions
What data do I need to train a PrizePicks prop model?
One row per line with the line at game time, the opening line, the tier, the market and the actual stat. GET /api/v1/results returns that per graded line, and your own features join on player, date and market.
Which leagues have graded results for modeling?
Graded results cover NBA full-game lines today. Every other league still has lines and full move history from the start of recording, so you can join your own box scores to them.
Should goblin and demon lines be modeled with standard lines?
Model them separately or carry the tier as a feature. Goblin and demon lines are more-only and sit away from the standard line, so a pooled hit rate mostly measures the tier mix.