API Documentation
Getting started
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. Every endpoint is open to everyone, including for commercial use. Publicly distributed products that display the data must include a visible credit linking back to Stats Guy Fantasy; see the terms of service.
https://api.statsguyfantasy.com/api/v1
Fetch the top of the superflex dynasty board:
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.
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 support@leaguebeat.com.
League formats
Values are calculated independently for four league formats:
| Format | Description |
|---|---|
sf_dynasty | Superflex dynasty (default) |
non_sf_dynasty | Single-QB dynasty |
sf_redraft | Superflex redraft |
non_sf_redraft | Single-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.
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.
curl "https://api.statsguyfantasy.com/api/v1/players/7564"
Rookie draft picks use structured IDs in three forms:
| Pick ID | Description |
|---|---|
pick:2027:1 | Round-only: a 2027 1st |
pick:2027:1:early | Early/mid/late variant of a round-only pick |
pick:2026:2.08 | Slot-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.
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.
Errors
Errors are JSON with the shape { "error": "...", "message": "..." }:
| Status | Description |
|---|---|
400 | Bad input: invalid parameters, malformed dates, or malformed JSON bodies |
404 | Not found: unknown player or route |
413 | Request body over 100kb |
429 | Rate limit exceeded; respect the Retry-After header |
500 | Internal server error |
Rankings
/api/v1/rankingsPlayer 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 parameters | Description |
|---|---|
format | League format (default sf_dynasty) |
position | QB, RB, WR, or TE |
date | YYYY-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. |
limit | 1-1000, default 500 |
offset | Pagination offset |
curl "https://api.statsguyfantasy.com/api/v1/rankings?format=sf_dynasty&position=WR&limit=1"
{
"format": "sf_dynasty",
"asOf": "2026-07-24T13:23:13.724Z",
"total": 214,
"limit": 1,
"offset": 0,
"rankings": [
{
"rank": 1,
"id": "7564",
"name": "Ja'Marr Chase",
"team": "CIN",
"position": "WR",
"positionRank": 1,
"value": 10874,
"age": 26.4,
"yearsExperience": 5
}
]
}
With ?date=, values and ranks come from the historical snapshot, but player metadata (name, team, age) reflects the current player record.
All players (bulk sync)
/api/v1/playersAll 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.
{
"total": 376,
"valuesAsOf": {
"sf_dynasty": "2026-07-24T13:23:13.724Z",
"non_sf_dynasty": "2026-07-24T13:20:41.238Z",
"sf_redraft": "2026-07-24T13:26:02.881Z",
"non_sf_redraft": "2026-07-24T13:28:19.454Z"
},
"players": [
{
"id": "7564",
"name": "Ja'Marr Chase",
"team": "CIN",
"position": "WR",
"value": {
"sf_dynasty": 10874,
"non_sf_dynasty": 10422,
"sf_redraft": 9100,
"non_sf_redraft": 8944
}
}
]
}
Use valuesAsOf to decide when to resync: if it hasn't changed, neither have the values.
Player detail
/api/v1/players/:idA player card across all formats: values, ranks, and change metrics (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.
curl "https://api.statsguyfantasy.com/api/v1/players/7564"
{
"id": "7564",
"name": "Ja'Marr Chase",
"team": "CIN",
"position": "WR",
"fantasyPositions": ["WR"],
"age": 26.4,
"yearsExperience": 5,
"rookieYear": 2021,
"dataUpdatedAt": "2026-07-24T18:00:03.162Z",
"value": {
"sf_dynasty": 10874,
"non_sf_dynasty": 10422,
"sf_redraft": 9100,
"non_sf_redraft": 8944
},
"rank": {
"sf_dynasty": 1,
"non_sf_dynasty": 1,
"sf_redraft": 4,
"non_sf_redraft": 5
},
"positionRank": {
"sf_dynasty": 1,
"non_sf_dynasty": 1,
"sf_redraft": 1,
"non_sf_redraft": 1
},
"rankChange": {
"sf_dynasty": { "days7": 0, "days30": -1 },
"non_sf_dynasty": { "days7": 0, "days30": 0 },
"sf_redraft": { "days7": 1, "days30": 2 },
"non_sf_redraft": { "days7": 0, "days30": 1 }
},
"positionRankChange": {
"sf_dynasty": { "days7": 0, "days30": 0 },
"non_sf_dynasty": { "days7": 0, "days30": 0 },
"sf_redraft": { "days7": 0, "days30": 0 },
"non_sf_redraft": { "days7": 0, "days30": 0 }
},
"valueChange": {
"sf_dynasty": { "days7": 121, "days30": 340 },
"non_sf_dynasty": { "days7": 98, "days30": 287 },
"sf_redraft": { "days7": 45, "days30": 122 },
"non_sf_redraft": { "days7": 51, "days30": 130 }
}
}
Value history
/api/v1/players/:id/value-historyFull value history for a player in one format, newest first.
| Query parameters | Description |
|---|---|
format | League format (default sf_dynasty) |
window | Max number of history entries (default: all) |
since | YYYY-MM-DD. Only entries on or after this date (for incremental sync) |
curl "https://api.statsguyfantasy.com/api/v1/players/7564/value-history?format=sf_dynasty&window=2"
{
"id": "7564",
"name": "Ja'Marr Chase",
"format": "sf_dynasty",
"history": [
{ "date": "2026-07-24", "value": 10874, "rank": 1, "positionRank": 1 },
{ "date": "2026-07-23", "value": 10851, "rank": 1, "positionRank": 1 }
]
}
Draft picks
/api/v1/picksRookie draft pick values across all formats. Years with slot-specific data (the current draft class) return one entry per slot (slot); future years return early/mid/late variants per round (variant).
| Query parameters | Description |
|---|---|
year | Filter by draft year (e.g. 2027) |
{
"total": 63,
"picks": [
{
"id": "pick:2026:2.08",
"year": 2026,
"round": 2,
"slot": 8,
"value": {
"sf_dynasty": 2100,
"non_sf_dynasty": 1900,
"sf_redraft": 0,
"non_sf_redraft": 0
}
},
{
"id": "pick:2027:1:early",
"year": 2027,
"round": 1,
"variant": "early",
"value": {
"sf_dynasty": 5400,
"non_sf_dynasty": 4800,
"sf_redraft": 0,
"non_sf_redraft": 0
}
}
]
}
Evaluate a trade
/api/v1/trades/evaluateCompare 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. Note: early/mid/ late pick variants apply the current variant shape table to the historical base value, an approximation for past dates.
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"]
}'
{
"format": "sf_dynasty",
"sideA": {
"assets": [
{
"id": "7564",
"type": "player",
"name": "Ja'Marr Chase",
"position": "WR",
"team": "CIN",
"value": 10874,
"found": true
},
{
"id": "pick:2027:1:early",
"type": "pick",
"name": "2027 Round 1 (early)",
"value": 5400,
"found": true
}
],
"totalValue": 16274
},
"sideB": {
"assets": [
{
"id": "4984",
"type": "player",
"name": "Josh Allen",
"position": "QB",
"team": "BUF",
"value": 9950,
"found": true
},
{
"id": "pick:2026:2.08",
"type": "pick",
"name": "2026 Pick 2.08",
"value": 2100,
"found": true
}
],
"totalValue": 12050
},
"differential": 4224
}
Unknown IDs come back with found: false and value: 0 (they still count toward the totals as zero). The response reports side totals and the differential only.
Evaluate trades in batch
/api/v1/trades/evaluate/batchEvaluate 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, sideA, sideB). Results return positionally.
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"]
}
]
}'
{
"total": 2,
"results": [
{
"format": "sf_dynasty",
"date": "2026-03-01",
"sideA": { "assets": [ ... ], "totalValue": 10534 },
"sideB": { "assets": [ ... ], "totalValue": 13890 },
"differential": -3356
},
{
"format": "non_sf_dynasty",
"sideA": { "assets": [ ... ], "totalValue": 3450 },
"sideB": { "assets": [ ... ], "totalValue": 3120 },
"differential": 330
}
]
}
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
/api/v1/trades/most-tradedTop 10 most-traded players per league type over a trailing window. Aggregate counts only.
| Query parameters | Description |
|---|---|
days | Trailing window, 1-365 (default 30) |
{
"days": 30,
"mostTraded": {
"dynasty_sf": [
{
"id": "7564",
"name": "Ja'Marr Chase",
"team": "CIN",
"position": "WR",
"tradeCount": 412
}
],
"dynasty_non_sf": [ ... ],
"redraft_sf": [ ... ],
"redraft_non_sf": [ ... ]
}
}
Questions, bug reports, or need higher rate limits? Email support@leaguebeat.com. 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.
