Esports line gaps API.
Same prop. Different DFS lines.
What does the line gaps API return?
The line gaps API returns the spread between DFS books for the same player, event and market, as line_min, line_max and line_gap in one row. It is GET /v6/esports/{sport}/gaps on Hobby and above. If one book posts 31.5, another 32.5 and a third 30.5, the gap is 2.
| Field | Meaning |
|---|---|
line_min | The lowest line any book posts for that player, event and market |
line_max | The highest line any book posts for it |
line_gap | The spread between them: 2 for lines of 30.5, 31.5 and 32.5 |
Updated
Why book-vs-book gaps matter
DFS apps do not share a clearing price. The same kill market on the same map window can sit a full kill (or more) apart. If you only read one book, you never see the softest line. If you scrape five apps, you rebuild player/event joins forever.
Practical rule: line_gap is arithmetic on posted floats — max minus min. We do not invent lines or average books into a fake “true” number.
What we normalize
One gap row = one player, one event, one exact stat_type, two or more DFS books with parseable lines. Over/under pairs on the same book collapse to one book entry (prefer over).
What does line mean?
line is the median of the DFS lines in that row. Soft and hard prints stay explicit as line_min / line_max.
Core endpoint
Path-style GET /v6/esports/{sport}/gaps. Default min_gap=0.5. Filter with player, market, market_contains, or book (book must appear in the row; full books[] still returned).
| Endpoint | Purpose | Key filters |
|---|---|---|
| GET /v6/esports/{sport}/gaps | DFS book-vs-book line spreads (Hobby+) | min_gap, player, market, book, limit |
| GET /v6/esports/{sport}/props | Full live board per book | book=prizepicks|underdog|… |
| GET /v6/esports/{sport}/lines | Consensus mainlines (not DFS gaps) | Hobby+ |
| MCP get_gaps | Same surface from Cursor/Claude | Hobby+ |
Identity and join keys
- —player_key prefers canonical player id, then slug, then name
- —event_key prefers sorted matchup_key so books still join when event ids diverge
- —exact canonicalize_stat_type — Map 1 does not merge into Maps 1–2
- —gap_id = sha1(sport|event_key|player_key|stat_type)[:12]
Sample JSON (live DFS board)
Live CS2 maps 1–2 kills for khaN: Sleeper 30.5 through Underdog 32.5 → line_gap: 2.0 from /v6/esports/cs2/gaps.
| Field | Example | Used for |
|---|---|---|
| line_gap | 2.0 | line_max − line_min across DFS books |
| line | 31.5 | Median of the DFS lines in the row |
| line_min / line_max | 30.5 / 32.5 | Softest and hardest posted lines |
| books[] | sleeper…underdog | One entry per book, sorted by line |
| stat_type | CS2_KILLS_MAPS_1_2 | Exact market — map1 ≠ maps 1–2 |
| gap_id | gap_ce3fbab1ef1e | Stable hash of sport|event|player|stat |
{
"source": "kashrock",
"sport": "cs2",
"min_gap": 0.5,
"total": 70,
"returned": 1,
"offset": 0,
"limit": 1,
"has_more": true,
"gaps": [
{
"gap_id": "gap_ce3fbab1ef1e",
"player_id": "kr_pl_6b8fc7792bfe",
"player_name": "khaN",
"team": "Nemiga",
"opponent": "Just_Players",
"event_id": "kr_ev_5886cc9220e5",
"event_time": "2026-09-12T17:00:00.000Z",
"stat_type": "CS2_KILLS_MAPS_1_2",
"market": "kills",
"line": 31.5,
"line_min": 30.5,
"line_max": 32.5,
"line_gap": 2,
"book_count": 5,
"books": [
{
"book": "sleeper",
"line": 30.5,
"propId": "kr_prop_aa230791ff25",
"direction": "over"
},
{
"book": "betr",
"line": 31.5,
"propId": "kr_prop_0a7fec48daa2",
"direction": "over"
},
{
"book": "boom",
"line": 31.5,
"propId": "kr_prop_0a7fec48daa2",
"direction": "over"
},
{
"book": "prizepicks",
"line": 31.5,
"propId": "kr_prop_0a7fec48daa2",
"direction": "over"
},
{
"book": "underdog",
"line": 32.5,
"propId": "kr_prop_67030b9dbc0f",
"direction": "over"
}
]
}
]
}Which books count
Only DFS apps with float player props. Zero or null lines (including moneyline rows) never enter the gap math. Promo sentinel lines ≤ 0 are excluded.
| Source | Schema | Best use |
|---|---|---|
| Scrape each DFS app | Fragile, blocked, drift | DIY line shopping |
| Props-only API | You join books yourself | Custom scanners |
| KashRock /gaps | Joined + line_gap ready | Boards, bots, research |
Using gaps responsibly
A large line_gap is a shopping signal, not automatic edge. Grade against settled results and your own model — do not confuse this with stack gap (model − app line).
Practical rule: sort is line_gap desc, then book_count desc — softest spreads surface first.
Operational practices
- —Hobby+ required; sandbox returns 403 on /gaps
- —Computed on-request from Redis prop boards — no upstream scrape
- —Prefer MCP get_gaps so agents do not invent endpoints
- —Empty board → gaps: [] — never mock rows
Quick reference
Curl: /v6/esports/cs2/gaps?min_gap=0.5. Docs: /docs/endpoints/gaps. DFS hub: /dfs-esports-api.
If you need a normalized feed instead of another UI wrapper, the Esports API exposes live boards, schedules, and history on one schema — with the IDs and outcome patterns that keep backtests and grading honest. Start free on Sandbox, or see published pricing.