STAT-API
DFS Cookbook

Read the lineup that won a contest

Winning lineups are the record of what actually worked. This recipe walks the whole contest chain: pick a contest on a slate, page its lineups, take first place, and read the players it rostered. Each hop uses that endpoint's own required filter, so the chain is the only way through — there is no single call that returns a contest's rosters.

What it is
Walks the full contest chain to the roster that finished first — the nine players, their salaries, and the prize.
When to use it
Use it to study what actually won, to measure how much salary winners left unspent, or to build a corpus of winning constructions.
What you get back
The winning entry's rank, score, and payout in cents, then one row per roster slot naming the player and the salary that lineup paid.

1.List the contests on the slate

A main slate carries a few dozen contests, from single-entry qualifiers to mass-entry tournaments. entry_fee and prize_pool are integer CENTS — 3300 is $33.00 and 12500000 is $125,000.

const contests = (await api.dfs.contests.list({ slate_id: 129036, limit: 100 })).contests

The complete program

Every step as one runnable file. It reads STAT_API_KEY from the environment, and is the same file that ships in the cookbook project for each SDK.

import { StatApi, type DFSContestUserLineup, type DFSContestUserLineupPlayerEntry, type DFSSlatePlayer } from '@stat-api/client'

const api = new StatApi() // reads STAT_API_KEY from the environment

// List the contests on the slate
const contests = (await api.dfs.contests.list({ slate_id: 129036, limit: 100 })).contests

// Keep the single-entry contests
const single = contests.filter((row) => row.max_entries_per_user === 1)

// Take the smallest one
const bysize = [...single].sort((a, b) => a.entry_count - b.entry_count)

// One contest
const contest = bysize.slice(0, 1)

// Page every lineup in that contest
const lineups: DFSContestUserLineup[] = []
for await (const row of api.dfs.contest_user_lineups.iter({ contest_id: contest[0].id })) lineups.push(row)

// Keep the lineups that were scored
const ranked = lineups.filter((row) => row.rank !== null && row.rank !== undefined)

// First place first
const byrank = [...ranked].sort((a, b) => (a.rank ?? 0) - (b.rank ?? 0))

// Take the winner
const winner = byrank.slice(0, 1)

// Show the winning entry
console.log("Winning entry")
console.log(["rank", "points", "winnings"].join('\t'))
for (const row of winner) {
  console.log([String(row.rank ?? ''), String(row.points ?? ''), String(row.winnings ?? '')].join('\t'))
}

// Read the nine players it rostered
const roster: DFSContestUserLineupPlayerEntry[] = []
for await (const row of api.dfs.contest_user_lineup_player_entries.iter({ contest_user_lineup_id: winner[0].id })) roster.push(row)

// Page the player pool to resolve names
const pool: DFSSlatePlayer[] = []
for await (const row of api.dfs.slate_players.iter({ slate_id: 129036 })) pool.push(row)

// Index the pool by its own id
const players = new Map<number, DFSSlatePlayer>()
for (const row of pool) players.set(row.id, row)

// Print the winning roster
console.log("The winning lineup")
console.log(["display_name", "roster_position", "position", "salary"].join('\t'))
for (const row of roster) {
  console.log([String(players.get(row.slate_player_id)?.display_name ?? row.slate_player_id), String(row.roster_position ?? ''), String(players.get(row.slate_player_id)?.position ?? row.slate_player_id), String(players.get(row.slate_player_id)?.salary ?? row.slate_player_id)].join('\t'))
}