Additional Data — Player props & player profiles
The player props & player profiles half of the Additional Data reference — every route with its parameters, credit cost and a worked example.
8 of 19 endpoints · all categories · get a free API key
GET/api/v1/player-props-resultsFree tier
Settled player-prop outcomes (hit/miss/actual value) per event.
Truth source is `player_props_results.outcomes[]` per repo memory (the prop backtest model). event_id path is a single doc fetch keyed on eventId (slashes replaced with underscores, capped at 1500 chars); without event_id it's a settled_at-ordered scan.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| sport_key | string | No | – | Post-filtered in memory (sportKey has no extracted column). |
| event_id | string | No | – | If set, does a direct doc lookup by id instead of a scan. |
| player_name | string | No | – | Case-insensitive partial match, filters within each event's outcomes array. |
| market | string | No | – | Exact match (lowercased) on outcome market_key. |
| since | string (ISO date) | No | – | Clamped by clampHistoricalFrom(); filters/orders on the indexed settled_at column. |
| limit | integer | No | 50 | Capped at 50 on free tier, 2000 on api tier. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/player-props-results?sport_key=aussierules_afl"{
"success": true,
"data": [
{
"event_id": "b7c3d9",
"sport_key": "basketball_nba",
"event_name": "Boston Celtics vs Denver Nuggets",
"commence_time": "2026-09-02T00:10:00Z",
"completed_at": "2026-09-02T02:45:00Z",
"outcomes": [
{
"market_key": "player_points",
"player_name": "Jayson Tatum",
"line": 27.5,
"side": "over",
"hit": true,
"actual_value": 31
}
],
"outcome_count": 1,
"updated_at": "2026-09-02T03:00:00.000Z"
}
],
"meta": {
"count": 1,
"tier": "free",
"limit": 50,
"requested_limit": 50,
"sport_key": null,
"event_id": null,
"player_name": null,
"market": null,
"since": null,
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 50,
"remaining": 998,
"reset": "2026-10-01T00:00:00.000Z"
}
}
}GET/api/v1/player-props-statsFree tier
Aggregate hit/miss/push counts and hit rate per player/market/line/side.
Backed by the primary store collection the prop-stats store (same table used by /api/v1/players/compare for its per-player prop breakdown). hit_rate = hits / (hits+misses), pushes excluded from denominator.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| sport_key | string | No | – | |
| player_slug | string | No | – | Exact match, post-filtered in memory after fetch. |
| player_canonical | string | No | – | |
| market_key | string | No | – | |
| side | string | No | – | Must be "over" or "under" or it is ignored. |
| limit | integer | No | 50 | Capped at 50 on free tier, 2000 on api tier. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/player-props-stats?sport_key=aussierules_afl"{
"success": true,
"data": [
{
"id": "player_props_stats-jayson-tatum-player_points-27.5-over",
"sport_key": "basketball_nba",
"market_key": "player_points",
"player_name": "Jayson Tatum",
"player_slug": "jayson-tatum",
"canonical_key": "nba_jayson-tatum",
"line": 27.5,
"side": "over",
"hits": 34,
"misses": 21,
"pushes": 2,
"total": 57,
"decided": 55,
"hit_rate": 0.6182,
"last_result_at": "2026-09-02T03:00:00.000Z",
"updated_at": "2026-09-02T03:05:00.000Z"
}
],
"meta": {
"count": 1,
"tier": "free",
"limit": 50,
"requested_limit": 50,
"sport_key": null,
"player_slug": null,
"player_canonical": null,
"market_key": null,
"side": null,
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 50,
"remaining": 998,
"reset": "2026-10-01T00:00:00.000Z"
}
}
}GET/api/v1/player-props/projectionsFree tier
AFL player projections branded as Krok Odds Projections, sourced from an advanced statistical model feed.
Route comment mandates branding this 'Krok Odds Projections' — never the underlying source name. Backed by the primary store collection the player-stats store (AFL only). `confidence` is a derived field = min(1, |Rating|/10), not a true model confidence. Cache TTL fixed at 3600s regardless of tier (not tier-scaled like most other v1 routes).
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| season | integer | No | current year | Season year filter; 400 if non-numeric. |
| round | integer | No | – | Round number filter; 400 if non-numeric. |
| team | string | No | – | Exact match, case-insensitive, on team. |
| player | string | No | – | Case-insensitive partial match on player name. |
| limit | integer | No | 100 | Clamped 1-500 (MAX_LIMIT). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/player-props/projections?season=current%20year"{
"success": true,
"data": [
{
"id": "fryzigg_2026_r23_marcus-bontempelli",
"player_name": "Marcus Bontempelli",
"team": "Western Bulldogs",
"season": 2026,
"round": 23,
"game": "WB_vs_GEE_R23",
"date": "2026-08-30",
"opposition": "Geelong",
"kicks": 18,
"marks": 6,
"handballs": 12,
"tackles": 5,
"goals": 1,
"behinds": 0,
"hit_outs": 0,
"inside_50s": 4,
"clearances": 7,
"clangers": 2,
"rebound_50s": 1,
"frees_for": 2,
"frees_against": 1,
"time_on_ground_pct": 88,
"rating": 132.4,
"disposal_rating": 27.1,
"confidence": 1
}
],
"meta": {
"count": 1,
"tier": "free",
"license": "krokodds-derived",
"season": 2026,
"round": null,
"team": null,
"player": null,
"source": "Krok Odds Projections",
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 500,
"remaining": 999,
"reset": "2026-10-01T00:00:00.000Z"
}
}
}GET/api/v1/players/compareFree tier
Compare 2-5 players' prop hit rates and season stats side by side; adds tennis H2H record and Elo when both players are ATP/WTA.
H2H + Elo enrichment only fires when sport_key contains 'tennis' AND exactly 2 players given; Elo is looked up only for the first player's slug in the current code (second player's Elo (_eloB) is fetched but discarded/unused). Elo source table is the tennis player store, tried under id `atp_{slug}` then `wta_{slug}`. Uses the standard auth guard/v1Success pattern.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| players | string (comma-separated slugs) | Yes | – | Min 2, max 5 slugs/canonical keys; 400 if <2 or >5. |
| sport_key | string | No | – | |
| season | string | No | – | Accepted but currently unused inside loadPlayerStats (param name is _season). |
| metrics | string (comma-separated) | No | – | Documented in the file header comment but not read/implemented in the current GET handler. |
| limit | integer | No | 20 | Max prop rows fetched per player, clamped 1-100. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/players/compare?players=lebron-james"{
"success": true,
"data": [
{
"slug": "novak-djokovic",
"name": "Novak Djokovic",
"sport_key": "tennis_atp",
"props": [
{
"market_key": "total_games_over_under",
"line": 21.5,
"side": "over",
"hit_rate": 62.5,
"sample": 16,
"hits": 10,
"misses": 6
}
],
"season_stats": {
"wins": 38,
"losses": 6
},
"h2h": {
"opponent_slug": "carlos-alcaraz",
"opponent_name": "Carlos Alcaraz",
"wins": 6,
"losses": 5,
"meetings": [
{
"date": "2026-07-14",
"winner": "Carlos Alcaraz",
"loser": "Novak Djokovic",
"score": "6-4 6-7 7-6",
"surface": "grass"
}
],
"surface_split": {
"hard": {
"a": 3,
"b": 3
},
"clay": {
"a": 2,
"b": 1
},
"grass": {
"a": 1,
"b": 1
}
},
"elo": {
"overall": 2231,
"hard": 2240,
"clay": 2180,
"grass": 2260
}
}
},
{
"slug": "carlos-alcaraz",
"name": "Carlos Alcaraz",
"sport_key": "tennis_atp",
"props": [
{
"market_key": "total_games_over_under",
"line": 21.5,
"side": "over",
"hit_rate": 58.3,
"sample": 12,
"hits": 7,
"misses": 5
}
],
"season_stats": {
"wins": 41,
"losses": 5
}
}
],
"meta": {
"count": 2,
"tier": "free",
"players": [
"novak-djokovic",
"carlos-alcaraz"
],
"sport_key": "tennis_atp",
"season": null,
"limit": 20,
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 20,
"remaining": 999,
"reset": "2026-10-01T00:00:00.000Z"
}
}
}GET/api/v1/players/{sport}/{id}/profileAPI plan
One player-season profile: identity, position, coverage, form badges, season stats, game log, line history, matchup, splits and similar players in a single payload.
Tier detail: api (paid)
The richest of the three player routes and the only one that returns camelCase keys - `sportKey`, `playerSlug`, `seasonStats`, `gameLog`, `lineHistory`, `altLines`, `formTable`, `splitRows`, `quickReads` - where `/frame` and `/hit-rates` return snake_case. Cost is 5 credits, `Cache-Control: private, no-store` with `x-cache-age: 600` and `x-ratelimit-tier: api`. An unlinked or empty player-season still answers **200**, not 404: `playerName` is null, `identity.state` is `pending` with a `note`, `analyticsOpen` is false and `coverage` is all zeros, so treat `identity.state`/`coverage.graded` as the presence signal rather than the status code. Section-level `state` values are `ready` or `building` with a per-section `n`. A read that fails behind the route answers 400/500 (`frame unavailable`) rather than an empty page. The example is the live, unmodified response for `rugbyleague_nrl` / `latrell_mitchell`, trimmed to two rows per array; it names no data source.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| sport | string | Yes | – | Sport key, lower-cased before matching. An unknown key is a 404 (`unknown sport`), and a key that exists but has no frame contract yet answers **200** with a single `{status: 'pending', sport_key, sport_state, reason}` row instead of data. |
| id | string | Yes | – | Player slug from any slug-carrying route (e.g. `meta.player_slug` on `/api/v1/insights/leaders`), lower-cased before matching and validated against `^[a-z0-9][a-z0-9_-]{0,119}$`. A slug that fails that pattern is a 400 (`invalid player id`). A well-formed slug for a player we have no rows for is **not** a 404 - see the notes. |
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| X-API-Key | string | Yes | – | API key. Without one the route is a 401 (`API key required`) - unlike `/frame` it has no open teaser. |
| season | string | No | – | Four-digit year, default the current calendar year. This filter is real, not decorative: `rugbyleague_nrl` / `latrell_mitchell` returns 85 rows, 13 graded and 10 markets for 2026 but 66 rows, 0 graded and 6 markets for 2025. Anything that is not a 4-digit year is a 400 (`season must be a 4-digit year`). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/players/aussierules_afl/abc123/profile?X-API-Key=value"{
"success": true,
"data": [
{
"sportKey": "rugbyleague_nrl",
"sportState": "configured",
"playerSlug": "latrell_mitchell",
"playerName": "Latrell Mitchell",
"identity": {
"state": "ready",
"canonicalId": "4703",
"note": ""
},
"position": {
"state": "pending",
"value": null,
"n": 3,
"source": null,
"note": "roster lists 2 positions (C, Centre)"
},
"analyticsOpen": false,
"season": 2026,
"builtAt": "2026-10-22T07:40:35.959Z",
"minSample": 8,
"coverage": {
"rows": 85,
"statValue": 85,
"graded": 13,
"events": 16,
"markets": 10
},
"headerBadges": [
{
"key": "form",
"label": "Form",
"value": "15%",
"n": 13,
"state": "ready"
},
{
"key": "dvp",
"label": "DvP",
"value": null,
"n": 0,
"state": "building",
"note": "position and DvP source not on the frame yet"
},
{
"key": "team",
"label": "Team",
"value": "South Sydney Rabbitohs",
"n": 3,
"state": "ready"
}
],
"seasonStats": [
{
"statKey": "runs",
"label": "Runs",
"mean": 10.833333333333334,
"median": 11,
"rollingSd": 3.8987177379235853,
"floorP25": 9,
"ceilingP75": 13.25,
"n": 12,
"band": null,
"state": "ready"
},
{
"statKey": "run_metres",
"label": "Run Metres",
"mean": 116.16666666666667,
"median": 108.5,
"rollingSd": 41.781574886545386,
"floorP25": 91.5,
"ceilingP75": 146.75,
"n": 12,
"band": null,
"state": "ready"
}
],
"gameLog": [
{
"eventId": "56e233da2c77b9d81506e5a412d1d43b",
"date": "2026-06-21T13:17:36.842+00:00",
"value": 0,
"line": 0.5,
"hit": "miss",
"opponent": null,
"homeAway": null,
"opponentLogoUrl": null,
"note": null
},
{
"eventId": "5133ad82356e44e66dee3264a7e15405",
"date": "2026-09-03T04:31:49.211+00:00",
"value": 0,
"line": 0.5,
"hit": "miss",
"opponent": null,
"homeAway": null,
"opponentLogoUrl": null,
"note": null
}
],
"gameChart": {
"marketLine": 0.5,
"projection": {
"value": null,
"n": 0,
"state": "pending",
"note": "opens when this sport passes the 95% player identity gate"
},
"notes": {
"state": "building",
"n": 0,
"note": "injury listings not read for this player"
}
},
"lineHistory": {
"title": "Line history",
"state": "building",
"note": "opening, current and close prices not on the frame yet",
"n": 13,
"paywalled": true
},
"matchup": {
"title": "Defence vs position",
"state": "building",
"note": "position and DvP not on the frame yet",
"n": 0,
"paywalled": true
},
"altLines": {
"title": "Alternate lines",
"state": "building",
"note": "book prices per rung not on the frame yet",
"n": 13,
"paywalled": false
},
"tabs": [
{
"key": "form",
"label": "Form",
"state": "ready"
},
{
"key": "game-logs",
"label": "Game logs",
"state": "ready"
},
{
"key": "splits",
"label": "Splits",
"state": "building"
}
],
"insights": [
{
"key": "coverage",
"text": "85 value rows across 16 fixtures and 10 markets",
"n": 85,
"score": 85
},
{
"key": "overall-hit",
"text": "Cleared the line in 15% of 13 graded props",
"n": 13,
"score": 13
},
{
"key": "sd:runs",
"text": "Runs: rolling-5 SD 3.9 against a mean of 10.8",
"n": 12,
"score": 12
}
],
"quickReads": {
"reads": [],
"note": "Not enough data: best sample n=0, rules need n≥8",
"bestN": 0
},
"formTable": {
"windows": [
{
"key": "l3",
"label": "L3",
"games": 3,
"mean": 27.333333333333332,
"median": 2,
"band": null
},
{
"key": "l5",
"label": "L5",
"games": 5,
"mean": 38.8,
"median": 5,
"band": null
},
{
"key": "l10",
"label": "L10",
"games": 10,
"mean": 29.7,
"median": 7,
"band": null
},
{
"key": "l15",
"label": "L15",
"games": 15,
"mean": 32.733333333333334,
"median": 9,
"band": null
},
{
"key": "season",
"label": "Season",
"games": 85,
"mean": 30.235294117647058,
"median": 8,
"band": {
"low": 0.043258178358081205,
"point": 0.15384615384615385,
"high": 0.4223463101948253,
"n": 13,
"hits": 2
}
}
],
"byStat": {
"runs": {
"l3": 9.333333333333334,
"l5": 9.8,
"l10": 10.6,
"l15": 10.833333333333334,
"season": 10.833333333333334
},
"run_metres": {
"l3": 117.33333333333333,
"l5": 110.2,
"l10": 120.3,
"l15": 116.16666666666667,
"season": 116.16666666666667
},
"tackles": {
"l3": 9.666666666666666,
"l5": 9.6,
"l10": 8.7,
"l15": 8.666666666666666,
"season": 8.666666666666666
},
"try_assists": {
"l3": 0.6666666666666666,
"l5": 0.4,
"l10": 0.8,
"l15": 0.8333333333333334,
"season": 0.8333333333333334
},
"line_breaks": {
"l3": 1.3333333333333333,
"l5": 1,
"l10": 1,
"l15": 0.9166666666666666,
"season": 0.9166666666666666
}
},
"medianRow": {
"runs": 11,
"run_metres": 108.5,
"tackles": 8.5,
"try_assists": 1,
"line_breaks": 1
},
"sdRow": {
"runs": 2.588435821108957,
"run_metres": 34.17162565638339,
"tackles": 3.8470768123342687,
"try_assists": 0.894427190999916,
"line_breaks": 0.7071067811865476
},
"state": "ready",
"note": ""
},
"splits": {
"title": "Splits",
"state": "building",
"note": "home/away, started/sub and minutes bands not on the frame yet",
"n": 0,
"paywalled": false
},
"splitRows": [],
"similar": {
"title": "Similar players",
"state": "pending",
"note": "similarity model not built",
"n": 0,
"paywalled": false
},
"compare": {
"state": "ready",
"note": "Compare any two players on the same stat and filters"
}
}
]
}GET/api/v1/players/{sport}/{id}/frameAPI plan
One player-season frame with an open teaser: keyless and free-tier callers get the summary, coverage, markets and game-log headline, paid keys get the rows too.
Tier detail: api (paid depth; free and keyless get the teaser)
Cheapest route in the family at 1 credit and the only one with an unauthenticated path. Keyless and teaser responses set `data` to a single **object** (not a one-element array), `teaser: true` and `meta.teaser: true`, ship a shared-cache header (`Cache-Control: public, s-maxage=600, stale-while-revalidate=600`) and carry no credit or rate-limit headers; the keyed response is `data: [...]` with `teaser: false`, `Cache-Control: private, no-store`, `x-credits-cost: 1` and `x-ratelimit-tier`. The teaser is a real redaction, not a page size: the same call returns `coverage.rows: 85`, `markets` 10 and `game_log` 4 with `rows: []` keyless, and 85 rows with a key. `frame_status` is `ready`, `empty` or `unavailable` - an unknown-but-well-formed player is `empty` at 200. Unknown sport is still a 404 keyless. The example is the live, unmodified paid response for `rugbyleague_nrl` / `latrell_mitchell`, trimmed; it names no data source.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| sport | string | Yes | – | Sport key, lower-cased before matching. An unknown key is a 404 (`unknown sport`), and a key that exists but has no frame contract yet answers **200** with a single `{status: 'pending', sport_key, sport_state, reason}` row instead of data. |
| id | string | Yes | – | Player slug from any slug-carrying route (e.g. `meta.player_slug` on `/api/v1/insights/leaders`), lower-cased before matching and validated against `^[a-z0-9][a-z0-9_-]{0,119}$`. A slug that fails that pattern is a 400 (`invalid player id`). A well-formed slug for a player we have no rows for is **not** a 404 - see the notes. |
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| X-API-Key | string | No | – | Optional - this is the one route in the family that answers without a key. Keyless is the open teaser, a `free` key is the same teaser, an `api` key gets full depth. |
| season | string | No | – | Four-digit year, default the current calendar year. This filter is real, not decorative: `rugbyleague_nrl` / `latrell_mitchell` returns 85 rows, 13 graded and 10 markets for 2026 but 66 rows, 0 graded and 6 markets for 2025. Anything that is not a 4-digit year is a 400 (`season must be a 4-digit year`). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/players/aussierules_afl/abc123/frame?X-API-Key=value"{
"success": true,
"data": [
{
"frame_status": "ready",
"sport_key": "rugbyleague_nrl",
"sport_state": "configured",
"sport_reason": null,
"player_slug": "latrell_mitchell",
"player_name": "Latrell Mitchell",
"season": 2026,
"built_at": "2026-10-22T07:40:35.959Z",
"min_sample": 8,
"summary": {
"headline": "Latrell Mitchell: NRL player profile",
"latest": "Latest line: Try Scorer Anytime 0.5 on 21 Sept 2026, result 0 (miss).",
"projection": "Projection: building (n=0).",
"coverage": "2026 season: 13 graded lines across 16 games."
},
"coverage": {
"rows": 85,
"stat_value": 85,
"graded": 13,
"events": 16,
"markets": 10
},
"primary_market_key": "player_try_scorer_anytime",
"markets": [
{
"market_key": "player_points_milestones",
"label": "Points Milestones"
},
{
"market_key": "player_tries_milestones",
"label": "Tries Milestones"
}
],
"game_log": [
{
"event_id": "56e233da2c77b9d81506e5a412d1d43b",
"date": "2026-06-21T13:17:36.842+00:00",
"value": 0,
"line": 0.5,
"hit": "miss",
"opponent": null,
"home_away": null
},
{
"event_id": "5133ad82356e44e66dee3264a7e15405",
"date": "2026-09-03T04:31:49.211+00:00",
"value": 0,
"line": 0.5,
"hit": "miss",
"opponent": null,
"home_away": null
}
],
"game_log_locked": 0,
"teaser": false,
"season_stats": [
{
"stat_key": "runs",
"label": "Runs",
"mean": 10.833333333333334,
"median": 11,
"rolling_sd": 3.8987177379235853,
"floor_p25": 9,
"ceiling_p75": 13.25,
"n": 12,
"band": null,
"state": "ready"
},
{
"stat_key": "run_metres",
"label": "Run Metres",
"mean": 116.16666666666667,
"median": 108.5,
"rolling_sd": 41.781574886545386,
"floor_p25": 91.5,
"ceiling_p75": 146.75,
"n": 12,
"band": null,
"state": "ready"
}
],
"form_table": {
"windows": [
{
"key": "l3",
"label": "L3",
"games": 3,
"mean": 27.333333333333332,
"median": 2,
"band": null
},
{
"key": "l5",
"label": "L5",
"games": 5,
"mean": 38.8,
"median": 5,
"band": null
},
{
"key": "l10",
"label": "L10",
"games": 10,
"mean": 29.7,
"median": 7,
"band": null
},
{
"key": "l15",
"label": "L15",
"games": 15,
"mean": 32.733333333333334,
"median": 9,
"band": null
},
{
"key": "season",
"label": "Season",
"games": 85,
"mean": 30.235294117647058,
"median": 8,
"band": {
"low": 0.043258178358081205,
"point": 0.15384615384615385,
"high": 0.4223463101948253,
"n": 13,
"hits": 2
}
}
],
"by_stat": {
"runs": {
"l3": 9.333333333333334,
"l5": 9.8,
"l10": 10.6,
"l15": 10.833333333333334,
"season": 10.833333333333334
},
"run_metres": {
"l3": 117.33333333333333,
"l5": 110.2,
"l10": 120.3,
"l15": 116.16666666666667,
"season": 116.16666666666667
},
"tackles": {
"l3": 9.666666666666666,
"l5": 9.6,
"l10": 8.7,
"l15": 8.666666666666666,
"season": 8.666666666666666
},
"try_assists": {
"l3": 0.6666666666666666,
"l5": 0.4,
"l10": 0.8,
"l15": 0.8333333333333334,
"season": 0.8333333333333334
},
"line_breaks": {
"l3": 1.3333333333333333,
"l5": 1,
"l10": 1,
"l15": 0.9166666666666666,
"season": 0.9166666666666666
}
},
"median_row": {
"runs": 11,
"run_metres": 108.5,
"tackles": 8.5,
"try_assists": 1,
"line_breaks": 1
},
"sd_row": {
"runs": 2.588435821108957,
"run_metres": 34.17162565638339,
"tackles": 3.8470768123342687,
"try_assists": 0.894427190999916,
"line_breaks": 0.7071067811865476
},
"state": "ready",
"note": ""
},
"volatility": {
"rolling_sd": 3.8987177379235853,
"median": 11,
"mean": 10.833333333333334,
"label": "volatile",
"n": 12,
"state": "ready"
},
"splits": [],
"rows": [
{
"sport_key": "rugbyleague_nrl",
"event_id": "3e6260ba3b7217715e6c4011f56c28cf",
"player_slug": "latrell_mitchell",
"player_name": "Latrell Mitchell",
"commence_time": "2026-09-20T22:58:19.577+00:00",
"opponent": null,
"venue": null,
"home_away": null,
"market_key": "player_try_scorer_anytime",
"stat_key": null,
"stat_value": 0,
"line": 0.5,
"side": "over",
"odds": null,
"bookmaker": "backfill:ppr",
"hit_result": "miss",
"computed_at": "2026-10-11T00:05:38.669+00:00"
},
{
"sport_key": "rugbyleague_nrl",
"event_id": "3e6260ba3b7217715e6c4011f56c28cf",
"player_slug": "latrell_mitchell",
"player_name": "Latrell Mitchell",
"commence_time": "2026-09-20T22:58:19.577+00:00",
"opponent": null,
"venue": null,
"home_away": null,
"market_key": "player_try_scorer_over",
"stat_key": null,
"stat_value": 0,
"line": 2.5,
"side": "over",
"odds": null,
"bookmaker": "backfill:ppr",
"hit_result": "miss",
"computed_at": "2026-10-11T00:05:38.669+00:00"
}
]
}
]
}GET/api/v1/players/{sport}/{id}/hit-ratesAPI plan
Overall and per-market hit rates for one player-season, plus a per-stat season band and the sample size behind each number.
Tier detail: api (paid)
The small, stable shape to poll when you only want numbers: `overall` (`value` as a percentage string, `n`, `state`), a `markets` array and `season_stats` with a `label`, `n`, `state` and `band` per stat. `min_sample` (8 on this route) is the threshold below which `state` stays `building` and `value` is null - read `n` and `state` rather than treating null as zero. `primary_market_key` is the market the route would headline and is null when nothing has cleared the sample. Same 5-credit cost, 600s cache and 400/404/401 behaviour as `/profile`, including the 200-with-empty-body answer for an unknown player slug. The example is the live, unmodified response for `rugbyleague_nrl` / `latrell_mitchell`, trimmed to two markets; it names no data source.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| sport | string | Yes | – | Sport key, lower-cased before matching. An unknown key is a 404 (`unknown sport`), and a key that exists but has no frame contract yet answers **200** with a single `{status: 'pending', sport_key, sport_state, reason}` row instead of data. |
| id | string | Yes | – | Player slug from any slug-carrying route (e.g. `meta.player_slug` on `/api/v1/insights/leaders`), lower-cased before matching and validated against `^[a-z0-9][a-z0-9_-]{0,119}$`. A slug that fails that pattern is a 400 (`invalid player id`). A well-formed slug for a player we have no rows for is **not** a 404 - see the notes. |
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| X-API-Key | string | Yes | – | API key. Without one the route is a 401 (`API key required`). |
| season | string | No | – | Four-digit year, default the current calendar year. This filter is real, not decorative: `rugbyleague_nrl` / `latrell_mitchell` returns 85 rows, 13 graded and 10 markets for 2026 but 66 rows, 0 graded and 6 markets for 2025. Anything that is not a 4-digit year is a 400 (`season must be a 4-digit year`). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/players/aussierules_afl/abc123/hit-rates?X-API-Key=value"{
"success": true,
"data": [
{
"sport_key": "rugbyleague_nrl",
"player_slug": "latrell_mitchell",
"player_name": "Latrell Mitchell",
"season": 2026,
"min_sample": 8,
"primary_market_key": "player_try_scorer_anytime",
"overall": {
"value": "15%",
"n": 13,
"state": "ready"
},
"markets": [
{
"market_key": "player_points_milestones",
"label": "Points Milestones",
"direction": "over",
"consensus_line": 9.5,
"consensus_n": 2,
"hit": {
"low": 0.09453120573423071,
"point": 0.5,
"high": 0.9054687942657693,
"n": 2,
"hits": 1
}
},
{
"market_key": "player_tries_milestones",
"label": "Tries Milestones",
"direction": "over",
"consensus_line": 2.5,
"consensus_n": 3,
"hit": {
"low": 4.8683609171202235e-17,
"point": 0,
"high": 0.5614970317550455,
"n": 3,
"hits": 0
}
}
],
"season_stats": [
{
"stat_key": "runs",
"label": "Runs",
"n": 12,
"state": "ready",
"band": null
},
{
"stat_key": "run_metres",
"label": "Run Metres",
"n": 12,
"state": "ready",
"band": null
},
{
"stat_key": "tackles",
"label": "Tackles",
"n": 12,
"state": "ready",
"band": null
}
]
}
]
}GET/api/v1/players/{sport}/rankerAPI plan
The Finder board for one sport as JSON: upcoming priced player props ranked per player, with the per-window hit-rate columns, the consensus line, the open-line move and the sport's quick-reads block.
Tier detail: api (paid)
Paid, 5 credits, 600s cache, same 401/404 behaviour as `/profile`. One data row: the whole board for the sport. `rows` is the priced-prop list - one entry per player x market x line x book, each carrying `odds`, `implied`, a `consensus` line with a book count, the `season` / `l5` / `l10` / `vsOpp` / `atVenue` hit-rate blocks (`low` / `point` / `high`, `n`, `hits`), a `projection`, a `dvp` block and a `valueScore`. `statKeys` and `bookmakers` say what the board covers; `players.scored` against `players.total` is how many players were ranked, and `notes` carries the truncation line when it bites (`soccer_epl` measured 2026-10-24: 260 rows, 856 quotes read, 60 of 209 players scored, `Scored the first 60 of 209 players by kick-off.`). `joins` and `quickReads` are coverage diagnostics - `joins` counts how many rows picked up the roster / open-line / DvP join, `quickReads.note` reports the sample size the rules need. Empty is a normal answer, not an error: a configured sport with nothing priced in the window returns `rows: []` with `notes: ['No priced props in the next 7 days.']` (`afl` and `rugbyleague_nrl`, measured 2026-10-24). The board is the upcoming window only - it takes no filters, and a `season` parameter is accepted and ignored. No quoted example here on purpose: every live `joins` string names an internal table, so the shape is described above rather than pasted.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| sport | string | Yes | – | Sport key, lower-cased before matching. An unknown key is a 404 (`unknown sport`), and a key that exists but has no frame contract yet answers **200** with a single `{status: 'pending', sport_key, sport_state, reason}` row instead of a board. |
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| X-API-Key | string | Yes | – | API key. Without one the route is a 401 (`API key required`). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/players/aussierules_afl/ranker?X-API-Key=value"Other categories
Per-event head-to-head odds, alternate lines, best prices across books, player props, live state and AI-generated summaries.
Krok's built-in scanners — arbitrage, positive EV, middles, low-holds, player props and same-game multi (SGM) picks, already devigged against a blended sharp baseline.
The full Australian racing stack — thoroughbred, harness and greyhound. Meetings and runner fields, form, sectionals, ratings, market movers, exchange arbs, tote pools and results.
Raw per-bookmaker prices as scraped, before any analysis layer. `/scraped-odds/*` paths are aliases of the equivalent `/odds-feed/*` route.
Sport reference data, team form guides, league standings, injury reports and weather-impact analysis.
AI-generated betting tips with confidence scores and historical accuracy tracking.
Ranked leaderboards built on top of the stat feeds — per-sport player leaders for a chosen stat, season and view.
ATP/WTA rankings, upcoming fixtures, match results, Elo ratings and surface-specific stats.
Deep archives — player and team game logs, shot charts, AFL/NRL historical data. Paid API plan only.
Static lookup data for building your own UI — players, venues, headshots, team logos and sport/league metadata.
Cricket, cycling, esports, Formula 1, golf, MMA, boxing, NFL and soccer coverage beyond the AU staples.
Account and billing endpoints, bulk export, SSE streaming, webhook management and API health.
Polymarket and Kalshi sentiment plus a universal prediction-market catalogue and resolutions feed.