We have a subreddit! Questions, feedback, and feature requests welcome. Join r/StatsGuyFantasy

Developers

API Documentation

Reference for the Stats Guy Fantasy dynasty and redraft values API

Getting started

Free and open, no API key required
View as Markdown

The Stats Guy Fantasy API serves player and pick values derived from real dynasty and redraft trades across thousands of Sleeper leagues. Values are recalculated on a regular run cadence (roughly daily), and historical snapshots are archived per run. See our methodology for how values are computed.

All endpoints are served over HTTPS from a single base URL. There is no authentication and no API key. If other people see the data in your product, include a visible credit such as “Data from Stats Guy Fantasy”, linked to statsguyfantasy.com; see the terms of service.

Base URL
https://api.statsguyfantasy.com/api/v1

Fetch the top of the superflex dynasty board:

Quick start
curl "https://api.statsguyfantasy.com/api/v1/rankings?format=sf_dynasty&limit=5"

The API root (GET https://api.statsguyfantasy.com/api/v1) is a discovery endpoint that lists every endpoint and its parameters as JSON. CORS is open, so you can call the API directly from browser apps.

Optional: set a descriptive User-Agent, such as MyApp/1.0 (+https://myapp.com), to identify your integration and help us contact you about API changes.

This reference is also available as a single plain-markdown file at /developers/docs.md for use with AI coding agents and LLM tools; a site index for LLMs lives at /llms.txt.

Rate limits & caching

Requests are rate limited per IP address, currently 60 requests per minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (unix seconds) headers. When you exceed the limit you get a 429 response with a Retry-After header. Back off until then.

Responses are gzip-compressed and may be served from a cache for up to an hour, so don't depend on sub-hour freshness. Because values only change when a calculation run completes (roughly daily), polling faster than that gains nothing anyway. For bulk consumers, one GET /players sync per day is plenty. If you need more headroom than the per-IP limit, email contact@statsguyfantasy.com.

League formats

Values are calculated independently for four league formats:

FormatDescription
sf_dynastySuperflex dynasty (default)
non_sf_dynastySingle-QB dynasty
sf_redraftSuperflex redraft
non_sf_redraftSingle-QB redraft

List endpoints are format-scoped: ?format= (or the format body field) picks the lens. Entity endpoints are format-complete: player detail and picks return value (and related fields) as per-format maps, so one call covers every league type.

Values cover offensive players (QB, RB, WR, TE) and draft picks. Defenders (DL, LB, DB) are added for IDP leagues with the idp parameter (IDP leagues); without it a defender's ID resolves as not found.

TE premium

TE values default to a blend of standard and TE-premium (TEP) leagues. To price TEs for one kind of league, pass the tep parameter to GET /rankings, GET /players, GET /players/:id, GET /players/:id/value-history, and the trade evaluate endpoints:

tepDescription
stdNo TE reception bonus
tepTE bonus of up to 1.0 per reception
bigtepTE bonus above 1.0 per reception, or 2+ TE starting slots
blendAverage across standard and TE-premium leagues (default)

Only TE values change, and ranks are recomputed from the adjusted values. Every response includes tep, the tier it was priced at.

IDP leagues

IDP values are dynasty only and sit on the same scale as offense. To price a league that starts defenders, pass idp with the league's roster-depth tier to GET /rankings, GET /players, GET /players/:id, GET /players/:id/value-history, and the trade evaluate endpoints. Without it, responses are for a league without IDP.

idpDescription
light1–4 IDP starting slots (DL, LB, DB, and IDP flex)
std5–9 IDP starting slots
heavy10 or more IDP starting slots
blendAverage across all three tiers
idpScoringDescription
tackleScoring ratio below 8
balancedRatio 8–13 (Sleeper's default scoring is 10)
bigplayRatio above 13 (Big 3 scoring is 17)
blendAverage across all three styles (default)

The scoring ratio is the points a sack earns, counting the solo tackle, tackle for loss, and QB hit it also scores, plus the points for an interception and a pass defended, divided by the points for a solo tackle. In Sleeper's scoring keys: (idp_tkl_solo + idp_sack + idp_tkl_loss + idp_qb_hit + idp_int + idp_pass_def) / idp_tkl_solo, with idp_tkl added to both solo terms. A league that scores no solo tackles is bigplay if it scores any of the others. idpScoring requires idp.

With idp, a defender's value appears under both sf_dynasty and non_sf_dynasty (IDP values don't depend on the QB format) and he has no redraft values; combining idp with a redraft format returns 400. Rankings put offense and defenders on one board with one contiguous rank, so offense ranks shift once defenders are included. A player eligible on both sides of the ball (Travis Hunter, WR/DB) is a DB in an IDP league, priced from IDP-league trades; dates before he had an IDP value leave him out. Responses echo idp and idpScoring, and current-value responses add idpAsOf, the timestamp of the IDP value run.

Player & pick IDs

Player IDs are Sleeper player IDs, returned by every endpoint as id and accepted anywhere a player ID is expected (path parameters, trade-evaluate sides) — pass IDs straight from Sleeper rosters and transactions. Every player also carries url, its player page on statsguyfantasy.com (null if the player isn't in our database).

Fetch a player by Sleeper ID
curl "https://api.statsguyfantasy.com/api/v1/players/7564"

Rookie draft picks use structured IDs in three forms:

Pick IDDescription
pick:2027:1Round-only: a 2027 1st, valued as a generic pick (slot unknown)
pick:2027:1:earlyEarly/mid/late variant of a round-only pick
pick:2026:2.08Slot-specific (current draft class): 2026 pick 2.08

Player metadata (names, teams, positions, ages) is synced from the Sleeper API; position eligibility (fantasyPositions) follows Sleeper's classification. Values and rankings are Stats Guy Fantasy's own trade-derived data.

Dates & history

Dates are always strict YYYY-MM-DD; other spellings are rejected with 400. Historical lookups resolve to the latest snapshot on or before the requested date, looking back at most 14 days; the snapshot date actually used is echoed back as asOf. Daily snapshots go back to 2022-08-01 for all formats; rankings requests with no snapshot in range return an empty board with an earliestAvailable hint. IDP history starts on the same date but is thinner in its first season: about 170 defenders were valued in August 2022, against roughly 230 from 2023 on, and their values moved more from day to day.

The asOf / valuesAsOf fields on current-value responses are the timestamp of the value-calculation run that produced the data (per format), not the request time. Formats update independently: dynasty values recompute year-round, while redraft values only recompute during the fantasy season and freeze at their last computed level through the offseason — so a redraft asOf can trail dynasty by months. That gap is deliberate (there is no meaningful redraft trade market in the offseason), not a data outage.

Errors

Errors are JSON with the shape { "error": "...", "message": "..." }:

StatusDescription
400Bad input: invalid parameters, malformed dates, or malformed JSON bodies
404Not found: unknown player or route
413Request body over 100kb
429Rate limit exceeded; respect the Retry-After header
500Internal server error

Rankings

GET
/api/v1/rankings

Player rankings for a format, current or historical. Use /rankings for display views, slices (position, pagination), and historical boards; use /players when you want the complete current dataset in one call.

Query parametersDescription
formatLeague format (default sf_dynasty)
positionQB, RB, WR, or TE; DL, LB, or DB with idp
tepstd, tep, bigtep, or blend (default). TE-premium tier (see TE premium)
idplight, std, heavy, or blend. IDP league roster-depth tier; dynasty formats only (see IDP leagues)
idpScoringtackle, balanced, bigplay, or blend (default). With idp only
dateYYYY-MM-DD. Historical board (omit for current). Resolves to the latest snapshot on or before this date (14-day lookback); asOf is the snapshot date served.
limit1-1000, default 500
offsetPagination offset
Request
curl "https://api.statsguyfantasy.com/api/v1/rankings?format=sf_dynasty&position=WR&limit=1"
Response
{
  "format": "sf_dynasty",
  "tep": "blend",
  "asOf": "2026-08-04T13:01:35.221Z",
  "total": 147,
  "limit": 1,
  "offset": 0,
  "rankings": [
    {
      "rank": 3,
      "id": "7564",
      "name": "Ja'Marr Chase",
      "url": "https://statsguyfantasy.com/player/jamarr-chase-7usy7y",
      "team": "CIN",
      "position": "WR",
      "positionRank": 1,
      "value": 9466,
      "age": 26.4,
      "yearsExperience": 5
    }
  ]
}

rank and positionRank rank players against other players only, computed from the served values. With ?date=, values (and the ranks computed from them) come from the historical snapshot, but player metadata (name, team, age) reflects the current player record.

All players (bulk sync)

GET
/api/v1/players

All players with calculated values, as format-complete cards (same shape as GET /players/:id), sorted by sf_dynasty value. This is the bulk sync endpoint: one call gives you a complete Sleeper-ID-keyed values map for local caching.

Response (truncated)
{
  "total": 397,
  "tep": "blend",
  "valuesAsOf": {
    "sf_dynasty": "2026-08-04T13:01:35.221Z",
    "non_sf_dynasty": "2026-08-04T13:01:35.221Z",
    "sf_redraft": "2026-08-04T13:01:35.221Z",
    "non_sf_redraft": "2026-08-04T13:01:35.221Z"
  },
  "players": [
    {
      "id": "9509",
      "name": "Bijan Robinson",
      "url": "https://statsguyfantasy.com/player/bijan-robinson-6v82sl",
      "team": "ATL",
      "position": "RB",
      "value": {
        "sf_dynasty": 10000,
        "non_sf_dynasty": 10000,
        "sf_redraft": 7458,
        "non_sf_redraft": 9823
      }
    }
  ]
}

Use valuesAsOf to decide when to resync: if it hasn't changed, neither have the values. Takes tep (TE premium) and idp / idpScoring (IDP leagues); players stay sorted by sf_dynasty value, using the adjusted values.

Player detail

GET
/api/v1/players/:id

A player card across all formats: values, ranks, and value changes (7- and 30-day windows) as per-format maps. There is no format parameter; one call covers every league type. The :id path takes the Sleeper player ID. tep sets the TE-premium tier (TE premium); idp and idpScoring price an IDP league (IDP leagues), which a defender's card requires.

Request
curl "https://api.statsguyfantasy.com/api/v1/players/7564"
Response
{
  "id": "7564",
  "name": "Ja'Marr Chase",
  "url": "https://statsguyfantasy.com/player/jamarr-chase-7usy7y",
  "team": "CIN",
  "position": "WR",
  "fantasyPositions": ["WR"],
  "age": 26.4,
  "yearsExperience": 5,
  "rookieYear": 2021,
  "dataUpdatedAt": "2026-08-04T18:00:02.821Z",
  "value": {
    "sf_dynasty": 9466,
    "non_sf_dynasty": 9117,
    "sf_redraft": 9794,
    "non_sf_redraft": 8680
  },
  "rank": {
    "sf_dynasty": 3,
    "non_sf_dynasty": 3,
    "sf_redraft": 2,
    "non_sf_redraft": 3
  },
  "positionRank": {
    "sf_dynasty": 1,
    "non_sf_dynasty": 1,
    "sf_redraft": 1,
    "non_sf_redraft": 1
  },
  "valueChange": {
    "sf_dynasty": { "days7": -148, "days30": -80 },
    "non_sf_dynasty": { "days7": -17, "days30": -626 },
    "sf_redraft": { "days7": 543, "days30": 543 },
    "non_sf_redraft": { "days7": 35, "days30": 35 }
  },
  "tep": "blend",
  "valuesAsOf": {
    "sf_dynasty": "2026-08-04T13:01:35.221Z",
    "non_sf_dynasty": "2026-08-04T13:01:35.221Z",
    "sf_redraft": "2026-08-04T13:01:35.221Z",
    "non_sf_redraft": "2026-08-04T13:01:35.221Z"
  }
}

valuesAsOf is when each format's values were computed; dataUpdatedAt only tracks the player's metadata record (name, team, injury status), which syncs daily year-round.

Value history

GET
/api/v1/players/:id/value-history

Full value history for a player in one format, newest first.

Query parametersDescription
formatLeague format (default sf_dynasty)
windowMax number of history entries (default: all)
sinceYYYY-MM-DD. Only entries on or after this date (for incremental sync)
tepstd, tep, bigtep, or blend (default). TE-premium tier (see TE premium)
idplight, std, heavy, or blend. IDP league roster-depth tier; dynasty formats only (see IDP leagues)
idpScoringtackle, balanced, bigplay, or blend (default). With idp only
Request
curl "https://api.statsguyfantasy.com/api/v1/players/7564/value-history?format=sf_dynasty&window=2"
Response
{
  "id": "7564",
  "name": "Ja'Marr Chase",
  "url": "https://statsguyfantasy.com/player/jamarr-chase-7usy7y",
  "format": "sf_dynasty",
  "tep": "blend",
  "history": [
    { "date": "2026-08-04", "value": 9466 },
    { "date": "2026-08-03", "value": 9545 }
  ]
}

Draft picks

GET
/api/v1/picks

Rookie draft pick values across all formats. Every year returns early/mid/late variants per round (variant); years with slot-specific data (the current draft class) additionally return one entry per slot (slot), and their variants are computed from the real slot values.

Query parametersDescription
yearFilter by draft year (e.g. 2027)
Response (truncated)
{
  "total": 120,
  "valuesAsOf": {
    "sf_dynasty": "2026-08-04T13:01:35.221Z",
    "non_sf_dynasty": "2026-08-04T13:01:35.221Z",
    "sf_redraft": "2026-08-04T13:01:35.221Z",
    "non_sf_redraft": "2026-08-04T13:01:35.221Z"
  },
  "picks": [
    {
      "id": "pick:2026:2.08",
      "year": 2026,
      "round": 2,
      "slot": 8,
      "value": {
        "sf_dynasty": 246,
        "non_sf_dynasty": 316
      }
    },
    {
      "id": "pick:2027:1:early",
      "year": 2027,
      "round": 1,
      "variant": "early",
      "value": {
        "sf_dynasty": 3762,
        "non_sf_dynasty": 3658
      }
    }
  ]
}

Pick values exist for dynasty formats only — redraft keys are omitted from value, not returned as 0. (Rookie draft picks are a dynasty asset; redraft trades involving picks are excluded from the value engine.)

Evaluate a trade

POST
/api/v1/trades/evaluate

Compare the total value of two trade sides. Sides accept Sleeper player IDs and pick IDs (any pick ID form), with up to 20 assets per side. Response entries are positional (same order as the request arrays) and echo the canonical id.

An optional date (YYYY-MM-DD) evaluates the trade using that date's values, for retro trade grading. Each asset resolves to its latest snapshot on or before the date (14-day lookback); assets with no snapshot in that window come back found: false. Historical entries include asOf, the snapshot date actually used.

tep sets the TE-premium tier (TE premium) and idp / idpScoring price defender IDs for an IDP league (IDP leagues); both combine with date.

Early/mid/late variants price from the round's real slot values once a draft year has slot data (current and historical evaluations alike); for years without slots they apply the variant shape table to the round-only base value. A bare round-only ID prices a generic pick of unknown slot; pass :mid when you just mean a typical pick.

Request
curl -X POST "https://api.statsguyfantasy.com/api/v1/trades/evaluate" \
  -H "Content-Type: application/json" \
  -d '{
    "format": "sf_dynasty",
    "sideA": ["7564", "pick:2027:1:early"],
    "sideB": ["4984", "pick:2026:2.08"]
  }'
Response
{
  "format": "sf_dynasty",
  "tep": "blend",
  "asOf": "2026-08-04T13:01:35.221Z",
  "sideA": {
    "assets": [
      {
        "id": "7564",
        "type": "player",
        "name": "Ja'Marr Chase",
        "url": "https://statsguyfantasy.com/player/jamarr-chase-7usy7y",
        "position": "WR",
        "team": "CIN",
        "value": 9466,
        "found": true
      },
      {
        "id": "pick:2027:1:early",
        "type": "pick",
        "name": "2027 Round 1 (early)",
        "value": 3762,
        "found": true
      }
    ],
    "totalValue": 13228
  },
  "sideB": {
    "assets": [
      {
        "id": "4984",
        "type": "player",
        "name": "Josh Allen",
        "url": "https://statsguyfantasy.com/player/josh-allen-ntn4px",
        "position": "QB",
        "team": "BUF",
        "value": 9246,
        "found": true
      },
      {
        "id": "pick:2026:2.08",
        "type": "pick",
        "name": "2026 Pick 2.08",
        "value": 246,
        "found": true
      }
    ],
    "totalValue": 9492
  },
  "differential": 3736
}

Unknown IDs come back with found: false and value: 0 (they still count toward the totals as zero) — as do picks in redraft formats, which carry no pick values, and defender IDs without idp. The response reports side totals and the differential only.

Evaluate trades in batch

POST
/api/v1/trades/evaluate/batch

Evaluate up to 25 trades in one request. A batch counts as a single request against the rate limit. The body is { "trades": [ ... ] } where each entry has the same shape as a single evaluate body (its own format, date, tep, idp, idpScoring, sideA, sideB). Results return positionally.

Request
curl -X POST "https://api.statsguyfantasy.com/api/v1/trades/evaluate/batch" \
  -H "Content-Type: application/json" \
  -d '{
    "trades": [
      {
        "format": "sf_dynasty",
        "date": "2026-03-01",
        "sideA": ["7564"],
        "sideB": ["4984", "pick:2027:1"]
      },
      {
        "format": "non_sf_dynasty",
        "sideA": ["pick:2026:1.04"],
        "sideB": ["9509"]
      }
    ]
  }'
Response (truncated)
{
  "total": 2,
  "results": [
    {
      "format": "sf_dynasty",
      "tep": "blend",
      "date": "2026-03-01",
      "sideA": { "assets": [ ... ], "totalValue": 9479 },
      "sideB": { "assets": [ ... ], "totalValue": 12052 },
      "differential": -2573
    },
    {
      "format": "non_sf_dynasty",
      "tep": "blend",
      "asOf": "2026-08-04T13:01:35.221Z",
      "sideA": { "assets": [ ... ], "totalValue": 2501 },
      "sideB": { "assets": [ ... ], "totalValue": 10000 },
      "differential": -7499
    }
  ]
}

Validation is atomic: any invalid entry fails the whole request with a 400 that includes the offending index. Unresolvable assets within a valid entry still come back per-asset as found: false.

Most-traded players

GET
/api/v1/trades/most-traded

Top 10 most-traded players per league type over a trailing window. Aggregate counts only.

Query parametersDescription
daysTrailing window, 1-365 (default 30)
Response (truncated)
{
  "days": 30,
  "mostTraded": {
    "dynasty_sf": [
      {
        "id": "11631",
        "name": "Brian Thomas",
        "url": "https://statsguyfantasy.com/player/brian-thomas-h7h68x",
        "team": "JAX",
        "position": "WR",
        "tradeCount": 604
      }
    ],
    "dynasty_non_sf": [ ... ],
    "redraft_sf": [ ... ],
    "redraft_non_sf": [ ... ]
  }
}

MCP server

The same values are available through a Model Context Protocol server, so ChatGPT, Claude, and other MCP hosts can look up players and evaluate trades by name. Add it as a remote MCP server or connector:

MCP server URL
https://api.statsguyfantasy.com/mcp

Streamable HTTP transport, no authentication. Every tool is read-only and wraps the REST endpoints above. Players and picks can be given by name ("Bijan Robinson", "early 2027 1st", "2026 1.03") or by ID. Coverage matches the REST API: the same tep tiers, and defenders when a tool call passes idp (defender names only match then).

ToolsDescription
evaluate_tradePrice both sides of a trade, with a verdict
get_rankingsRankings for one format, optionally one position; up to 50 per call
get_playerOne player's values, ranks, and recent change in every format
get_pick_valuesRookie pick values for one dynasty format, optionally one year
search_playersFind players by name (defenders with includeIdp); returns IDs for the other tools

MCP requests are limited to 150 per minute per IP, separately from the REST API. For bulk data, use the REST API.

Questions, bug reports, or need higher rate limits? Email contact@statsguyfantasy.com. Recent changes are listed in the changelog. For update and breaking-change notices, join the update list. To understand what the numbers mean, read the methodology articles. API usage is covered by the terms of service.