Stop drafting off someone else's cheat sheet. In ~30 lines of Python you'll rank every player by Value Over Replacement Player (VORP) using live 2026 PPR projections — tuned to your exact league.
/api/v1/players?position={POS} — every player at a position, with seasons.2026.season_projectionsEvery player profile carries season-long PPR projections under seasons.2026.season_projections. The MISC_FPTS field is the projected total fantasy points (for K and DST it's FPTS).
curl -H "x-api-key: YOUR_KEY" \
"https://api.gridirondata.com/api/v1/players?position=RB"
Each player looks like this (trimmed):
{
"player_id": "Bijan Robinson#RB",
"player_name": "Bijan Robinson",
"position": "RB",
"seasons": {
"2026": {
"team": "ATL",
"season_projections": { "MISC_FPTS": 373.3, "RUSHING_YDS": 1380, ... }
}
}
}
A 280-point RB and a 280-point QB are not equal. There are far more startable QBs than RBs, so the RB is scarcer — and scarcity is what wins drafts. VORP measures each player against the last startable player at their position:
VORP = player_points − replacement_points[position]
"Replacement" is the player ranked at roughly the number of starters your league rosters at that position. For an 8-team league we use these ranks (tune to your league):
REPLACEMENT_RANK = {"QB": 14, "RB": 30, "WR": 30, "TE": 10, "K": 8, "DST": 8}
import requests
API = "https://api.gridirondata.com/api/v1"
KEY = "YOUR_KEY"
H = {"x-api-key": KEY}
REPLACEMENT_RANK = {"QB": 14, "RB": 30, "WR": 30, "TE": 10, "K": 8, "DST": 8}
def points(p):
sp = p["seasons"]["2026"]["season_projections"]
return float(sp.get("MISC_FPTS", sp.get("FPTS", 0)))
# 1. Pull every position
players = []
for pos in REPLACEMENT_RANK:
rows = requests.get(f"{API}/players", headers=H, params={"position": pos}).json()
rows = rows.get("players", rows) if isinstance(rows, dict) else rows
for p in rows:
if p.get("seasons", {}).get("2026", {}).get("season_projections"):
players.append({"id": p["player_id"], "pos": pos, "pts": points(p)})
# 2. Replacement baseline per position
repl = {}
for pos, rank in REPLACEMENT_RANK.items():
ranked = sorted((p["pts"] for p in players if p["pos"] == pos), reverse=True)
repl[pos] = ranked[min(rank - 1, len(ranked) - 1)]
# 3. VORP + sorted board
for p in players:
p["vorp"] = round(p["pts"] - repl[p["pos"]], 1)
board = sorted(players, key=lambda x: -x["vorp"])
for i, p in enumerate(board[:24], 1):
print(f"{i:2}. {p['id']:24} {p['pos']:3} proj {p['pts']:6.1f} VORP {p['vorp']:6.1f}")
/api/v1/stats/{player_id}/2025 to fade injury-prone or unproven players, or change REPLACEMENT_RANK for a 10- or 12-team league. Add an OP/superflex slot and QB value jumps.