Racing API endpoints
The full Australian racing stack — thoroughbred, harness and greyhound. Meetings and runner fields, form, sectionals, ratings, market movers, exchange arbs, tote pools and results.
9 of 23 endpoints · all categories · get a free API key
GET/api/v1/racing/arbsFree tier
Live cross-bookmaker arbitrage opportunities on Australian racing (win markets), read from the pre-aggregated opportunity doc/arbs doc (primary store first, secondary fallback).
Reads a single pre-aggregated doc (the pre-aggregated opportunity doc/arbs), not a live scan; filters applied in JS after fetch. Arbs whose `detected_at` is more than 10 minutes old are dropped (RACING_OPP_STALE_MS — two cycles of the 5-min syncRacingArbs writer), so a doc the writer stopped refreshing is served as empty rather than as live opportunities; rows carrying no usable stamp are dropped too. Cache 60s both tiers. Legacy inline auth boilerplate (not using shared authorizeRacing helper).
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| venue | string | No | – | Case-insensitive substring match on meeting venue name. |
| race_type | string | No | – | Exact match on race type code (e.g. T/H/G) as stored on the arb record. |
| minedge | number | No | 0 | Minimum arb edge (as a fraction, e.g. 0.03 = 3%) to include. |
| limit | integer | No | 50 | Max rows returned; capped at 100 (free) / 500 (api). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/arbs?venue=Randwick"{
"success": true,
"data": [
{
"id": "arb_20260903_randwick_r5_furioustempo",
"venue": "Randwick",
"race_number": 5,
"race_name": "Group 3 Show County Quality",
"race_type": "T",
"jump_time": "2026-09-03T04:35:00.000Z",
"runner": "Furious Tempo",
"arb_type": "win",
"leg1_bookmaker": "Sportsbet",
"leg1_odds": 4.8,
"leg1_bet_link": "https://www.sportsbet.com.au/search?q=Furious%20Tempo",
"leg2_bookmaker": "Betfair",
"leg2_odds": 5.4,
"leg2_bet_link": "https://www.betfair.com.au/exchange/plus/search?q=Furious%20Tempo",
"edge": 0.0231,
"stake1_pct": 52.9,
"stake2_pct": 47.1,
"all_legs": null,
"detected_at": "2026-09-03T03:58:12.000Z"
}
],
"meta": {
"count": 1,
"tier": "free",
"limit": 50,
"requested_limit": 50,
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 100,
"remaining": 942,
"reset": "2026-10-01"
}
}
}GET/api/v1/racing/bookmakers→ alias of /api/v1/bookmakersFree tier
Alias of /api/v1/bookmakers.
Tier detail: free (no tierAllowsFeature gate at all - any valid key of any tier can call it)
Directly re-exports { GET, OPTIONS } from ../../bookmakers/route - same handler, not a redirect. The racing board labels its price rows with the platform catalogue, so this path serves the identical 21 rows, brands[] and bookmaker_type included: a byte-for-byte comparison of the two responses matches on sha256 once meta.timestamp is normalised (measured). Query options (region, provider, include_aggregators) and the full field list are documented on /api/v1/bookmakers, which is also where this catalog sits in the Infrastructure group. Like the parent it is key-gated but feature-free - any valid key of any tier can call it - and it costs the parent's 1 credit. Prediction-market venues are catalogued on their own group and are not in this list.
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/bookmakers"GET/api/v1/racing/futuresFree tier
Upcoming major-race futures (Melbourne Cup, Cox Plate, Golden Rose etc.) merged from a licensed book's futures markets and third-party racing feeds.
Venue is GUESSED from race/competition name text via a hardcoded RACE_VENUE map — not authoritative. Only future dates (startTime >= today) are queried. Uses shared authorizeRacing() helper (../_shared.ts).
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| venue | string | No | – | Substring match on inferred venue (mapped from race/competition name via a well-known-race lookup table). |
| race_type | string enum | No | – | One of T | H | G. |
| date | string (YYYY-MM-DD) | No | – | Filter to a specific date. When omitted, returns all meetings across all dates. |
| lite | boolean | No | false | When '1' or 'true', skips heavy enrichments (form, stats, sectionals, videos) for faster responses. |
| limit | integer | No | 50 | Max rows returned; capped at 50 (free) / 200 (api). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/futures?venue=Randwick"{
"success": true,
"data": [
{
"date": "2026-11-03",
"venue": "Flemington",
"race_name": "Melbourne Cup",
"race_type": "T",
"runners": [
{
"name": "Vauban",
"odds": 8.5,
"bookmaker": "PointsBet",
"bookmaker_type": "fixed"
},
{
"name": "Absurde",
"odds": 12,
"bookmaker": "PointsBet",
"bookmaker_type": "fixed"
}
],
"prize_money": null,
"distance": null,
"conditions": null,
"bookmakers": [
"PointsBet",
"Amused"
]
}
],
"meta": {
"count": 1,
"sources": [
"PointsBet",
"Amused"
],
"tier": "free",
"limit": 50,
"requested_limit": 50,
"timestamp": "2026-09-03T04:00:00.000Z"
}
}GET/api/v1/racing/meetingsFree tier
The full racing board \u2014 today's (or filtered) AU/NZ/UK-IE race meetings with races and runners, heavily enriched (racecards, sectionals/videos, form analysis/stats, results, exchange snapshots, cross-book market movers).
By far the heaviest endpoint — up to 6 sequential/parallel enrichment joins per meeting (racecards, intl racecards, sectionals/videos, form, stats, results, exchange). Cache 120s free / 60s api (the declared 30s api window is raised to the 60s v1Revalidate floor). Full runner object has ~80 optional keys — stripped of nulls by default; use ?full=1 to restore. UK/IE meetings synthesized as type 'R' but counted as 'T' unless H/G explicitly requested. Default board includes international meetings; use country=AU for Australian only. Every runner can carry `notes[]` — one entry per note, each `{provenance, type, text, captured_at}` — `provenance` is `krok` (house) or `aggregated`, Krok's own notes first and then the others newest-first. The key is ABSENT on a runner with no notes, never an empty array, so a reader must treat a missing `notes` as no notes. Measured 2026-10-05 on the full board: 1062 of 1922 runner slots (55.3%) served notes across three feeds; tomorrow's card fills through the day (439 of 2034 by 08:00Z), so a low count on tomorrow is a writer still filling, not a serving fault.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| date | string (YYYY-MM-DD) | No | – | Filter to a specific date. When omitted, returns all meetings across all dates. |
| race_type | string enum | No | – | One of T | H | G. Alias: `type`. |
| type | string enum | No | – | Alias for race_type. |
| venue | string | No | – | Case-insensitive substring match on venue name. |
| country | string (ISO 3166-1 alpha-2) | No | – | Filter meetings by country, e.g. `AU`. Default board includes international meetings; use `country=AU` for Australian only. |
| jurisdiction | string | No | – | State/tote-jurisdiction code (e.g. NSW, VIC). Alias: `state`. |
| state | string | No | – | Alias for jurisdiction. |
| limit | integer | No | 50 | Max meetings returned; capped at 50 (free) / 1000 (api). |
| full | boolean ("1") | No | 0 | When '1', returns the explicit-null shape (all 104 runner keys present even if null — measured 2 Oct 2026); default strips null/empty-array fields to shrink payload. Across 3,710 runners measured the same day, the default populated 6-50 keys, most commonly 33. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/meetings?date=2026-09-01"{
"success": true,
"data": [
{
"id": "tab_1234567",
"meeting_key": "2026-09-03_flemington",
"venue": "Flemington",
"state": "VIC",
"country": null,
"tote_jurisdiction": "VIC",
"type": "T",
"date": "2026-09-03",
"race_count": 8,
"next_jump": "2026-09-03T04:35:00.000Z",
"weather": {
"summary": "Partly cloudy",
"temp_c": 16,
"rain_24h_mm": 0,
"wind_kmh": 14,
"wind_dir": "SW"
},
"track_hint": "Good 4",
"prize_money": 180000,
"races": [
{
"id": "1234567_5",
"race_key": "2026-09-03_flemington_5",
"number": 5,
"jump_time": "2026-09-03T04:35:00.000Z",
"name": "Turnbull Stakes",
"distance": 2000,
"race_class": "Group 1",
"status": "open",
"track_condition": "Good 4",
"runner_count": 10,
"allowed_bet_types": [
"WIN",
"PLC",
"EXA",
"TRI"
],
"runners": [
{
"id": "r1",
"number": 3,
"name": "Zaaki",
"barrier": 6,
"bib": null,
"gear": null,
"jockey": "J Bowman",
"trainer": "A Freedman",
"weight": 58.5,
"is_scratched": false,
"notes": [
{
"provenance": "krok",
"type": "drawn_wide",
"text": "Drawn wide in barrier 8 of 9.",
"captured_at": "2026-10-05T07:59:57.998+00:00"
}
],
"best_win": 3.2,
"best_win_bookmaker": "Sportsbet",
"bookmakers_priced": 2,
"fixed_win": 3.1,
"odds": [
{
"bookmaker": "Sportsbet",
"win": 3.2,
"place": 1.5,
"bet_link": "https://www.sportsbet.com.au/search?q=Zaaki"
},
{
"bookmaker": "Betfair",
"win": 3.4,
"matched": 42000,
"bet_link": "https://www.betfair.com.au/exchange/plus/search?q=Zaaki"
}
]
}
]
}
]
}
],
"meta": {
"count": 1,
"tier": "free",
"limit": 50,
"requested_limit": 50,
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 50,
"remaining": 942,
"reset": "2026-10-01"
}
}
}GET/api/v1/racing/meetings/{date}Free tier
The racing board for one date, supplied as a URL path segment. Same handler, auth, tier, credit cost, enrichment and response shape as /api/v1/racing/meetings - it exists so a day-scoped board is reachable without a query string.
Re-exports the /api/v1/racing/meetings GET handler and sets `?date=` from the path segment, passing every other query option and header through unchanged, so the two paths are interchangeable apart from the date. The segment is validated strictly before the hand-off: anything that is not a real YYYY-MM-DD calendar date - e.g. a meeting key such as `2026-10-22_angle-park` - returns 400 `Invalid date - expected YYYY-MM-DD`, never 404. Credit cost is the handler's own: 1 credit (measured, internal key, 3 calls moved `credits_used` by 3 after a 1-credit reading overhead). `cache-control: private, no-store` on the wire - revalidation happens inside the handler, not in an HTTP cache. Like the parent it is the heaviest v1 route: one full date ran 1.36 MB / 0.81 s at `limit=3`, so narrow with `venue` and a low `limit` when you want a single meeting. The example below is abridged to one meeting, one race and two runners; every value in it was served by production.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| date | string (YYYY-MM-DD) | Yes | – | The date to return, as the URL path segment. Strict YYYY-MM-DD; anything else is 400. |
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| race_type | string enum | No | – | One of T | H | G. Alias: `type`. |
| type | string enum | No | – | Alias for race_type. |
| venue | string | No | – | Case-insensitive substring match on venue name. |
| country | string (ISO 3166-1 alpha-2) | No | – | Filter meetings by country, e.g. `AU`. Default board includes international meetings; use `country=AU` for Australian only. |
| jurisdiction | string | No | – | State/tote-jurisdiction code (e.g. NSW, VIC). Alias: `state`. |
| state | string | No | – | Alias for jurisdiction. |
| limit | integer | No | 50 | Max meetings returned; capped at 50 (free) / 1000 (api). |
| full | boolean ("1") | No | 0 | When '1', returns the explicit-null shape (all 104 runner keys present even if null — measured 2 Oct 2026); default strips null/empty-array fields to shrink payload. Across 3,710 runners measured the same day, the default populated 6-50 keys, most commonly 33. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/meetings/2026-09-01?race_type=value"{
"success": true,
"data": [
{
"id": "28376485",
"meeting_key": "2026-10-22_angle-park",
"venue": "Angle Park",
"state": "SA",
"country": "AU",
"type": "G",
"date": "2026-10-22T00:00:00.000Z",
"race_count": 12,
"next_jump": "2026-10-22T08:04:00.000Z",
"data_quality": {
"books_count": 20,
"single_source": false,
"has_results": false,
"last_price_update": "2026-10-22T05:12:28.194Z"
},
"races": [
{
"id": "28405445",
"race_key": "2026-10-22_angle-park_G_1",
"race_key_v2": "2026-10-22_angle-park_G_1",
"source_id": "406037807dd865ed",
"number": 1,
"jump_time": "2026-10-22T08:04:00.000Z",
"name": "FRESH PET FOOD CO MIXED STAKE",
"distance": 530,
"status": "open",
"field_hold_pct": 0.28871216502795427,
"track_condition": "Good",
"weather": "FINE",
"track_direction": "Left",
"entrant_count": 10,
"positions_paid": 3,
"prize_monies": {
"1st": 3100,
"2nd": 880,
"3rd": 440,
"total_value": 4420
},
"distance_m": 530,
"liquidity_tier": "thin",
"exchange_total_matched": 10,
"data_quality": {
"books": 20,
"has_result": false,
"last_price_update": "2026-10-22T05:12:28.194Z"
},
"runner_count": 10,
"runners": [
{
"id": "271944751",
"number": 1,
"entry_id": "2026-10-22_angle-park_G_1_1",
"name": "Proclivity",
"barrier": 1,
"box": 1,
"trainer": "B Oakey",
"weight": 0,
"form": "1328412113",
"is_scratched": false,
"best_win": 1.8,
"best_win_bookmaker": "BetBunker",
"bookmakers_priced": 20,
"implied_prob": 0.47619047619047616,
"fixed_win": 2.1,
"fixed_place": 1.22,
"flucs": [
{
"win": 2.15
},
{
"win": 2.1
},
{
"win": 2.15
},
{
"win": 2.1
}
],
"speedmap": {
"label": "Leader",
"settlingLengths": 8
}
},
{
"id": "271944752",
"number": 2,
"entry_id": "2026-10-22_angle-park_G_1_2",
"name": "Ritza Wotton",
"barrier": 2,
"box": 2,
"trainer": "T Richards",
"weight": 0,
"form": "2364212143",
"is_scratched": false,
"best_win": 7.5,
"best_win_bookmaker": "Ladbrokes",
"bookmakers_priced": 20,
"implied_prob": 0.13333333333333333,
"fixed_win": 7.5,
"fixed_place": 2,
"flucs": [
{
"win": 7.5
},
{
"win": 7
},
{
"win": 7.5
}
],
"speedmap": {
"label": "Off Pace",
"settlingLengths": 6
}
}
]
}
]
}
],
"meta": {
"count": 1,
"total": 1,
"truncated": false,
"has_more": false,
"next_cursor": null,
"shape": "full",
"tier": "api",
"limit": 1,
"requested_limit": 1,
"timestamp": "2026-10-22T05:20:14.750Z",
"rate_limit": {
"limit": 200,
"remaining": 439313,
"reset": "2026-11-01T00:00:00.000Z"
}
}
}GET/api/v1/racing/moversFree tier
Live odds steamers/drifters (significant price movements) across AU racing markets, read from the pre-aggregated opportunity doc/movers.
Reads a single doc combining `movers` + `drifters` arrays. Falls back the secondary store→the primary store if the primary store doc is missing or both arrays are empty. Legacy inline auth (not shared _shared.ts helper).
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| venue | string | No | – | Case-insensitive substring match on meeting venue. |
| race_type | string | No | – | Exact match on race type code. |
| movement_type | string enum | No | – | One of steamer | drifter. |
| min_movement | number | No | 0 | Minimum absolute movement percentage to include. |
| limit | integer | No | 50 | Max rows returned; capped at 100 (free) / 500 (api). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/movers?venue=Randwick"{
"success": true,
"data": [
{
"race_id": "1234567_5",
"venue": "Caulfield",
"race_number": 5,
"race_name": "Memsie Stakes",
"race_type": "T",
"jump_time": "2026-09-03T05:10:00.000Z",
"runner": "Alligator Blood",
"runner_number": 4,
"bookmaker": "Ladbrokes",
"bookmaker_type": "fixed",
"bet_link": "https://www.ladbrokes.com.au/search?q=Alligator%20Blood",
"opening_odds": 6.5,
"current_odds": 4.2,
"movement_pct": -35.4,
"movement_type": "steamer"
}
],
"meta": {
"count": 1,
"tier": "free",
"limit": 50,
"requested_limit": 50,
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 100,
"remaining": 942,
"reset": "2026-10-01"
}
}
}GET/api/v1/racing/odds-historyFree tier
Per-runner price-movement curves (open \u2192 every fluctuation \u2192 close/SP/BSP) per bookmaker for a meeting/race/runner, built from race card data, historical results and odds snapshots.
Tier detail: free (but >14 days back requires api tier)
Free tier is hard-clamped to the last 14 days regardless of the account's `historicalDays` window (extra check beyond the standard historical-clamp gate) — returns 402 with X-Krok-Feature: historical. Tote/SP book keys (tote, vrc, racenet, etc.) are excluded from bookFlucs. Falls back card→historical-results→live-snapshot-only in that order per meeting. Uses shared _shared.ts auth (feature the premium racing feature, cost 5). A whole-day response serialises a day of the capture mirror (measured 2026-10-05: 7,781 rows / 28 MB; 2026-10-11: 15,544 rows / 108 MB), so an unbounded day is inherently a multi-second build. The default response is therefore one page of up to 25 meetings (limit), and the snapshot read behind a page covers only that page's venues, capped at 6 snapshot-covered venues per page - a page may hold any number of meetings whose venue has no captures, because those cost nothing. Pages therefore differ in length between days: walk meta.next_cursor until meta.has_more is false rather than computing pages from limit. meta.total counts the whole day and is independent of the page, so a caller always knows how much is left. limit=all returns the complete day in a single response (the old behaviour). A snapshot read that fails, comes back short, or exceeds its row cap is never served or cached: the request returns 503 so a caller cannot mistake a partial day for a complete one. A paged response is byte-bounded as well as venue-bounded: meetings stop being added once the serialised page would pass 3 MB, and meta.next_cursor then points at the meeting after the last one actually served, so the byte cap is walked exactly like the venue cap. A single meeting larger than the budget is still served whole — the cap never reduces a page to nothing — so a page can still exceed 3 MB when one venue's card is that heavy. bookFlucs is what makes a venue that heavy — measured 2026-10-16, one meeting held 9 races and 93 runners in 4,371,737 bytes, of which 99.99% was per-book fluc history. A page therefore returns bookFlucs as a SUMMARY by default: every book, with its latest quote. ?flucs=full returns the history unchanged, meta.flucs says which body you received, and meta.flucs_points_omitted says how many points the summary left out (80,407 on that meeting: 4,371,737 bytes becomes 259,557). A single-runner read and limit=all keep the full history. The body is gzipped whenever the caller sends Accept-Encoding: gzip (with Vary: Accept-Encoding) — the same compression /racing/meetings has always had. limit=all is not byte-capped and still returns the whole day in one response.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| date | string (YYYY-MM-DD) | No | today (Sydney meeting date) | Meeting date to fetch. |
| venue | string | No | – | Case-insensitive substring match on venue. |
| raceNumber | integer | No | – | Filter to a single race number. Alias: `race`. |
| race | integer | No | – | Alias for raceNumber. |
| runner_slug | string | No | – | Filter to a single runner by slugified name. |
| limit | integer (1-200) or the word all | No | 25 | Meetings per response. `all` (or `0`) returns the whole day in one response — that is the pre-pagination behaviour and is still supported. Either way the response is complete for what it claims: a page is never a partial day. |
| cursor | string | No | – | Opaque cursor from meta.next_cursor. Walk it until meta.has_more is false to collect the complete day. Ignored on filtered (venue/raceNumber/runner_slug) calls, which stay single-response. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/odds-history?date=today%20(Sydney%20meeting%20date)"{
"success": true,
"data": [
{
"id": "tab_1234567",
"venue": "Flemington",
"date": "2026-09-03",
"races": [
{
"number": 5,
"name": "Turnbull Stakes",
"status": "closed",
"start_time": "2026-09-03T04:35:00.000Z",
"runners": [
{
"number": 3,
"name": "Zaaki",
"is_scratched": false,
"open": 3.6,
"sp": 3.2,
"bsp": 3.15,
"flucs": [
{
"timestamp": "2026-09-03T02:00:00.000Z",
"odds": 3.6
},
{
"timestamp": "2026-09-03T04:30:00.000Z",
"odds": 3.2
}
],
"bookFlucs": {
"sportsbet": [
{
"timestamp": "2026-09-03T02:00:00.000Z",
"odds": 3.7
},
{
"timestamp": "2026-09-03T04:30:00.000Z",
"odds": 3.3
}
]
}
}
]
}
]
}
],
"meta": {
"count": 1,
"date": "2026-09-03",
"venue": null,
"race_number": 5,
"runner_slug": null,
"tier": "free",
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 50,
"remaining": 942,
"reset": "2026-10-01"
},
"source": "card",
"limit": 25,
"total": 1,
"has_more": false,
"next_cursor": null
}
}GET/api/v1/racing/flucsFree tier
Per-runner price fluctuation history for ONE race, kept per bookmaker (every capture of the race, oldest first), read straight from the odds capture mirror.
Tier detail: free (up to 20 captures per request; api tier returns up to 200)
A snapshot row's id does NOT carry the meeting type, and a venue can run two meetings at the same race numbers on the same day (2026-10-01_warrnambool_7 holds 42 thoroughbred + 13 greyhound captures), so pass race_type — or race_key_v2, which carries it — or the series follows the newest capture with meta.ambiguous_race_type=true and race_types_available listing both. Captures that cannot confirm the requested type are dropped, never guessed into it. Served from the odds-snapshot store, the append-only capture mirror: one point per capture per book, oldest first. Series are PER BOOK because a blended line cannot answer 'did one book shorten while another drifted?'. A book absent from a capture is absent from its series — nothing is interpolated, so gaps are real gaps. Every licensed book lands in the mirror (verified 2026-10-01: 113 captures for one race with all three on every capture); BetEngine does not appear at all, and its own table is 8 days stale, so it is not offered. Tote pools (tote, puntsport) are excluded — they are pari-mutuel, not fixed-odds flucs. The card-oriented /api/v1/racing/odds-history carries the same mirror data inside a whole-meeting payload; this endpoint answers one race without the meeting.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| race_key | string | No | – | {date}_{venueSlug}_{raceNo}, or the race_key_v2 form with the meeting type ({date}_{venueSlug}_{type}_{raceNo}). Required unless date, venue and race_no are all supplied. |
| date | string (YYYY-MM-DD) | No | – | Race date — long-form alternative to race_key. |
| venue | string | No | – | Venue slug (e.g. illawarra-grange) — long-form alternative to race_key. |
| race_no | number | No | – | Race number — long-form alternative to race_key. `race` is accepted as an alias. |
| race_type | string (T|H|G) | No | – | Meeting type. Required when the venue ran two meetings at the same race number (thoroughbred + greyhound); when omitted the series follows the newest capture and meta.ambiguous_race_type is true. |
| book | string | No | – | Comma-separated book keys to return (tab,betright,palmerbet). All books when omitted. |
| limit | number | No | 20 | Most recent captures to return, per book (max 20 free, 200 api). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/flucs?race_key=value"{
"success": true,
"data": {
"race_key": "2026-10-01_illawarra-grange_1",
"race_id": "tabnz_2026-10-01_illawarra-grange_T_1",
"date": "2026-10-01",
"venue_slug": "illawarra-grange",
"race_no": 1,
"captures": 3,
"first_capture": "2026-10-01T06:20:34.418Z",
"last_capture": "2026-10-01T08:55:06.452Z",
"books": [
"betright",
"palmerbet",
"sportsbet",
"tab",
"tabtouch"
],
"runners": [
{
"number": 1,
"name": "Classic Two",
"scratched": false,
"books": {
"tab": [
{
"t": 1780294834418,
"win": 6,
"place": null,
"lay": null
},
{
"t": 1780309436452,
"win": 8,
"place": null,
"lay": null
}
],
"betright": [
{
"t": 1780294834418,
"win": 9,
"place": null,
"lay": null
}
]
}
}
]
},
"meta": {
"count": 1,
"captures": 3,
"limit": 20,
"requested_limit": 0,
"book_filter": [],
"books_available": [
"betright",
"palmerbet",
"sportsbet",
"tab",
"tabtouch"
],
"ambiguous_race_type": false,
"tier": "free",
"timestamp": "2026-10-01T09:20:00.000Z",
"rate_limit": {
"limit": 50,
"remaining": 942,
"reset": "2026-11-01"
}
}
}GET/api/v1/racing/tote-poolsFree tier
Parimutuel (tote) pool totals, dividends and multi-leg exotic pools per race for a meeting day.
Cache is 60s (v1Revalidate() enforces a 60s floor at the framework level regardless of the declared constant). Dividends array is typically empty pre-race and only populates once the pool settles. Honest current state (measured 14 Oct 2026): coverage is driven by the live tote feed — every race the live feed has priced is served, whether or not the post-race daily pass has run. Pool totals, jackpots and settled dividends are joined from that daily pass, so a race can legitimately appear with prices and an empty `exotic_pools` or `dividends` array until the pass completes. Do not read an empty pools array as "no meeting": re-check after the daily pass, or use `venue` to narrow to a meeting you know is priced.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| date | string (YYYY-MM-DD) | No | today (Sydney meeting date) | Meeting date to fetch tote pool data for. |
| venue | string | No | – | Case-insensitive substring match on venue. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/tote-pools?date=today%20(Sydney%20meeting%20date)"{
"success": true,
"data": [
{
"id": "tab_1234567",
"venue": "Flemington",
"state": "VIC",
"type": "T",
"date": "2026-09-03",
"tote_jurisdiction": "VIC",
"exotic_pools": [
{
"type": "QUADDIE",
"legs": [
4,
5,
6,
7
],
"total": 612400,
"jackpot": false
}
],
"races": [
{
"number": 5,
"name": "Turnbull Stakes",
"distance": 2000,
"status": "open",
"start_time": "2026-09-03T04:35:00.000Z",
"pools": [
{
"pool_type": "WIN",
"total": 184200
},
{
"pool_type": "PLACE",
"total": 96700
}
],
"dividends": []
}
]
}
],
"meta": {
"count": 1,
"date": "2026-09-03",
"venue": null,
"tier": "free",
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 50,
"remaining": 942,
"reset": "2026-10-01"
}
}
}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.
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.
Odds history, steam-move detection, player prop stats/results, injuries, weather and other supporting feeds.
Polymarket and Kalshi sentiment plus a universal prediction-market catalogue and resolutions feed.