Racing — Results & international
The results & international half of the Racing reference — every route with its parameters, credit cost and a worked example.
5 of 23 endpoints · all categories · get a free API key
GET/api/v1/racing/internationalAPI plan
UK/IE and other international racecards and results, from the licensed international racecards / results store.
Built on the shared the standard v1 route factory() factory (v1-collection-route.ts) with feature: 'historical' — this is the ONLY racing endpoint that is NOT free-tier (historical/bulk_export are the only two paid-only features). Empty result set returns 200 + `data: []` with the credit refunded; the internal request log labels that case 204, but the wire status is always 200. Runners expose the same derived price fields as /racing/meetings (`best_win`, `best_win_bookmaker`, `fixed_win`, `bookmakers_priced`) **only when the row carries an `odds[]` array**; The Racing API racecards/results rows carry no `odds[]`, so on today's data those four keys are absent — the documented example above shows the fields that are actually present. `type=results` rows swap in the result fields (`position`, `sp`, `sp_dec`, `bsp`, `time`, `btn`, `or`, `rpr`, `tsr`, `prize`, `ovr_btn`) and add `comments`, `non_runners`, `tote_win`, `tote_pl`, `winning_time_detail`, `distance_m`, `distance_y`. **Not served on this feed:** there is no runner `name` (the horse is `horse`) and no `or_rating` (the rating is `ofr` on racecards / `or` on results) — earlier drafts used those two names but the route never emits them. **Not yet available / always null:** `margin` is never served here; `comments`, `non_runners`, `tote_win`, `tote_pl` and `winning_time_detail` are carried but frequently `null`; there are no dividends and no starting-price/tote-dividend fields on this feed at all.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| type | string enum | No | racecards | One of racecards | results — which collection to query. |
| date | string (YYYY-MM-DD) | No | – | Exact-match filter on race date. |
| limit | integer | No | 100 | Max rows returned; capped at 50 (free) / 200 (api). Note: gated to api-tier anyway via the 'historical' feature. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/international?type=racecards"{
"success": true,
"data": [
{
"id": "intl_gb_20260903_ascot_1535",
"date": "2026-09-03",
"sport": "horse_racing",
"type": "racecards",
"region": "GB",
"country": "GB",
"venue": "Ascot",
"venue_slug": "ascot",
"race_id": "912345",
"race_number": 3,
"race_name": "3:35 Ascot - Handicap",
"race_class": "Class 4",
"race_status": "racecard",
"off_dt": "2026-09-03T15:35:00Z",
"off_time": "15:35",
"distance_f": 8,
"going": "Good",
"surface": "Turf",
"field_size": 8,
"runners": [
{
"number": 1,
"horse": "Northern Lad",
"horse_id": "123456",
"draw": 3,
"jockey": "R Moore",
"jockey_id": "987",
"trainer": "C Appleby",
"trainer_id": "42",
"age": 4,
"sex": "Gelding",
"weight_lbs": 126,
"ofr": 78,
"form": "2213",
"last_run": "2026-08-10"
}
]
}
],
"meta": {
"count": 1,
"tier": "api",
"limit": 100,
"requested_limit": 100,
"type": "racecards",
"date": null,
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 200,
"remaining": 1998,
"reset": "2026-10-01"
}
}
}GET/api/v1/racing/international/resultsAPI plan
Race results from the international (UK/IE and wider) store, for one date. The same handler, auth, tier and credit cost as /api/v1/racing/international with type=results fixed, so callers do not have to know the parameter shape.
Convenience sub-route: rewrites the URL to /api/v1/racing/international, injects type=results and forwards with the original headers, so every other query option and the whole response contract belong to the parent. Verified interchangeable with the parent query form - the two responses match on sha256 once meta.timestamp is normalised (measured, limit=2). Gated on the 'historical' feature, so api tier only, and priced as the parent is: x-credits-cost: 2 on the wire (measured). The default request is heavy - 100 rows / 1,031,665 bytes with meta.truncated: true and no total - so pass `date` and a low `limit`. Rows carry an internal _raw passthrough field alongside the parsed columns; it is omitted from the example below, which is abridged to one race and two runners. Every other value in the example was served by production.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| date | string (YYYY-MM-DD) | No | – | Exact-match filter on race date. |
| limit | integer | No | 100 | Max rows returned; capped at 50 (free) / 200 (api). Note: gated to api-tier anyway via the 'historical' feature. |
| type | string enum | No | results | Fixed to results by this path - it is set after the URL is rewritten, so a caller-supplied ?type= is overwritten. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/international/results?date=2026-09-01"{
"success": true,
"data": [
{
"id": "2026-10-19_wolverhampton-aw_1",
"date": "2026-10-19",
"type": "Flat",
"going": "Standard",
"sport": "racing",
"venue": "Wolverhampton (AW)",
"off_dt": "2026-10-19T16:45:00+01:00",
"region": "GB",
"country": "UK",
"pattern": "",
"race_id": "rac_32301595443",
"runners": [
{
"or": "56",
"sp": "",
"age": "2",
"bsp": null,
"btn": "",
"dam": "Silver Games (IRE)",
"rpr": "",
"sex": "F",
"tsr": "",
"draw": "1",
"sire": "Bated Breath (GB)",
"time": "",
"horse": "Miss You Nights (GB)",
"prize": "",
"dam_id": "dam_4968166",
"jockey": "Clifford Lee",
"number": "11",
"sp_dec": "",
"weight": "9-0",
"damsire": "Verglas",
"ovr_btn": "",
"sire_id": "sir_5178992",
"trainer": "Jack Channon",
"headgear": "",
"horse_id": "hrs_66527342",
"position": "1",
"jockey_id": "jky_280440",
"damsire_id": "dsi_3126837",
"trainer_id": "trn_361449",
"weight_lbs": "126"
},
{
"or": "65",
"sp": "",
"age": "2",
"bsp": null,
"btn": "",
"dam": "No More Regrets (IRE)",
"rpr": "",
"sex": "F",
"tsr": "",
"draw": "7",
"sire": "Space Traveller (GB)",
"time": "",
"horse": "Global Success (IRE)",
"prize": "",
"dam_id": "dam_13988023",
"jockey": "Oisin Murphy",
"number": "2",
"sp_dec": "",
"weight": "9-9",
"damsire": "Kodiac",
"ovr_btn": "",
"sire_id": "sir_13788215",
"trainer": "J. S. Moore",
"headgear": "b",
"horse_id": "hrs_63741895",
"position": "2",
"jockey_id": "jky_278184",
"damsire_id": "dsi_4080139",
"trainer_id": "trn_46089",
"weight_lbs": "135"
}
],
"surface": "AW",
"tote_pl": null,
"age_band": "2yo",
"comments": null,
"off_time": "4:45",
"tote_win": null,
"race_name": "Download The At The Races App Nursery Handicap Stakes (Div II)",
"distance_f": "7f",
"distance_m": "",
"distance_y": "",
"race_class": "Class 6",
"venue_slug": "wolverhampton-aw",
"non_runners": null,
"race_number": 1,
"rating_band": "0-65",
"sex_restriction": "",
"winning_time_detail": null
}
],
"meta": {
"count": 1,
"truncated": true,
"tier": "api",
"limit": 2,
"requested_limit": 2,
"type": "results",
"date": null,
"timestamp": "2026-10-22T05:34:14.020Z",
"rate_limit": {
"limit": 200,
"remaining": 439252,
"reset": "2026-11-01T00:00:00.000Z"
}
}
}GET/api/v1/racing/predictionsFree tier
AI-powered win/place probability predictions for AU/NZ races, from the racing predictions model.
Live (served 2026-10-13): per-race model ratings expanded to one row per runner. Each ratable horse in a modelled race becomes its own row — win_probability from the model's per-runner win probability, the model rank the horse's place INSIDE its own race (winProb desc, slug asc breaks ties), code derived from the race type (T/H/G → thoroughbred/harness/greyhound). Reads the picks model store mirror, bounded by the date prefix on data.date (an ISO timestamp, so a lexicographic range is used rather than equality). Cross-model consensus is merged when a matching race exists, adding ensemble_agreement_count and ensemble_pick. place_probability is null — the model publishes a win probability only, not a place model. Built on the standard v1 route factory() factory. Sorted by the model rank asc then win_probability desc. Fetches limit*4 rows (limit*8 when venue/code/horse filters are set, JS post-filter), capped at the requested limit on return. An unmodelled day still answers meta.status='not_yet_populated'.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| date | string (YYYY-MM-DD) | No | today | Race date to filter. |
| venue | string | No | – | Case-insensitive substring match on venue. |
| code | string enum | No | – | Racing code: thoroughbred | harness | greyhound. |
| horse | string | No | – | Case-insensitive substring match on horse name. |
| limit | integer | No | 200 | Max rows returned; capped at 200 (free) / 1000 (api). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/predictions?date=today"{
"success": true,
"data": [
{
"id": "2026-09-03_flemington_T_5_admiral-vos",
"date": "2026-09-03",
"venue": "Flemington",
"race_no": 5,
"horse_name": "Zaaki",
"win_probability": 0.31,
"place_probability": 0.58,
"model_rank": 1,
"code": "thoroughbred"
}
],
"meta": {
"count": 1,
"tier": "free",
"limit": 200,
"requested_limit": 200,
"date": "2026-09-03",
"venue": null,
"code": null,
"horse": null,
"source": "Krok Odds Predictions",
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 200,
"remaining": 942,
"reset": "2026-10-01"
}
}
}GET/api/v1/racing/resultsFree tier
Archive query across settled race results (exchange-SP-based, lighter fields than the date-specific endpoint) with filters by track, race type, runner and date range.
Tier detail: free (date-range filters `since`/`until` require api tier via the 'historical' feature)
Explicit the credit cost=5 archive endpoint; refunds the full credit cost when the result set is empty. Setting `since`/`until` on a free-tier key returns a 402 tier-gate error for the 'historical' feature BEFORE the per-key clamp runs. `track`/`runner_slug`/`race_name` filters are applied client-side after an over-fetch (up to 2000 rows). `data_quality.results_source` is a NEUTRAL provenance class (primary|secondary|exchange, or null) — it never names the feed. Derived by applying provenanceClass() to the source mix measured 2026-10-01 across a full 2026-09-30 day (200 rows: 193 secondary-token, 7 exchange-token). `has_result` is the reliable settled flag (`status` is free-text: the same day returned both `resulted` and `finished`). `books` counts per-book quote rows and is 0 on most settled races (198/200 that day), so treat it as "quotes captured", not "quality score". `last_price_update` is the newest quote timestamp and equals `ingested_at` when the result and the quotes arrived in the same write. Rows whose source is the fast path can carry a blank `track`/`race_key_v2` (6/200 that day) — fall back to `id` for those. Always-null / not yet available on today's data: `starting_price` (populated on 66.2% of the trailing-7-day runner rows, but most values are the last pre-jump market price rather than a settled SP), `tote_dividend` (15.5%) and `margin` (1.7%) - each is `null` when nothing has been reconciled, never guessed, and its `*_source` is `null` too. Measured 2026-10-14. `meeting_id` is the meeting's own identity, served beside `meeting_key` (the Sydney-day key the row is filed under) — the two differ for a UK/IE card that runs after midnight in Sydney. `is_final` collapses `status` to a boolean settled flag: `true` for `resulted`/`finished`/`Final`, `false` for `pending`/`abandoned`/`closed`. `meta.data_note` is always present — `null` when there is nothing to report, else a sentence naming the pending races or the `scheduled_time` fill count. All six (`meeting_id`, `meeting_key`, `local_date`, `jump_time_utc`, `meta.data_note`, `is_final`) verified served on prod 2026-10-23.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| race_type | string enum | No | – | One of T | H | G. |
| track_slug | string | No | – | Exact match on venue slug. |
| track | string | No | – | Case-insensitive substring match on track name. |
| race_name | string | No | – | Case-insensitive substring match on race name. |
| runner_slug | string | No | – | Exact match on a runner's slug within the race. |
| since | string (YYYY-MM-DD) | No | – | Results on/after this date. Requires 'historical' feature (api tier); also clamped per-key by verification.historicalDays. |
| until | string (YYYY-MM-DD) | No | – | Results on/before this date. Requires 'historical' feature (api tier). |
| limit | integer | No | 50 | Max rows returned; capped at 50 (free) / 2000 (api). |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/results?race_type=value"{
"success": true,
"data": [
{
"id": "2026-09-30_laval_H_1",
"race_key_v2": "2026-09-30_laval_H_1",
"meeting_id": "2026-09-30_laval",
"date": "2026-09-30",
"track": "Laval",
"track_slug": "laval",
"state": null,
"race_no": 1,
"race_type": "H",
"racing_type": "H",
"distance_m": 2850,
"race_name": "GRAND PRIX ANJOU-MAINE SS",
"scheduled_time": "2026-09-30 11:55:00",
"jump_time_utc": "2026-09-30T11:55:00Z",
"local_date": "2026-09-30",
"actual_off_time": null,
"win_market_id": null,
"place_market_id": null,
"winning_time": null,
"mile_rate": null,
"status": "finished",
"is_final": true,
"data_quality": {
"books": 0,
"has_result": true,
"results_source": "secondary",
"last_price_update": "2026-10-01T00:00:43.347Z"
},
"winner": {
"tab_number": 5,
"name": "Jilord Viva",
"slug": "jilord-viva",
"jockey": "E Raffin",
"trainer": "J Raffestin",
"win_bsp": null
},
"runners": [
{
"tab_number": 5,
"name": "Jilord Viva",
"slug": "jilord-viva",
"is_scratched": false,
"finish_position": 1,
"margin": null,
"win_result": "Winner",
"win_bsp": null,
"place_result": "Placed",
"place_bsp": null,
"jockey": "E Raffin",
"trainer": "J Raffestin",
"barrier": null,
"weight": null,
"rpr": null,
"or_rating": null,
"age": null,
"ts": null,
"mr": null,
"margin_source": null,
"finish_position_source": null,
"starting_price": null,
"starting_price_source": null,
"tote_dividend": null,
"tote_dividend_source": null
},
{
"tab_number": 9,
"name": "Ibiscus Man",
"slug": "ibiscus-man",
"is_scratched": false,
"finish_position": 2,
"margin": null,
"win_result": null,
"win_bsp": null,
"place_result": "Placed",
"place_bsp": null,
"jockey": "M Mottier",
"trainer": "R Larue",
"barrier": null,
"weight": null,
"rpr": null,
"or_rating": null,
"age": null,
"ts": null,
"mr": null
}
],
"going": null,
"race_class": null,
"ingested_at": "2026-10-01T00:00:43.347Z",
"non_tab": null
}
],
"meta": {
"count": 1,
"tier": "free",
"limit": 50,
"requested_limit": 50,
"race_type": null,
"track_slug": null,
"race_name": null,
"runner_slug": null,
"since": null,
"until": null,
"data_note": "This endpoint returns exchange-SP-based results (limited fields). For richer results including margins, times and full connections, use the date-specific endpoint /api/v1/racing/results/{date}.",
"timestamp": "2026-09-03T04:00:00.000Z",
"rate_limit": {
"limit": 50,
"remaining": 937,
"reset": "2026-10-01"
}
}
}GET/api/v1/racing/results/{date}Free tier
Full settled race results for every meeting on a single date — finishing order, margins, times, BSP, jockey/trainer — merged with national-tote pools and dividends.
Tier detail: free (subject to per-key historicalDays clamp)
Same `{date}_{venueSlug}_{raceNo}` race_key/meeting_key join keys as /racing/meetings. Sorts results by raceNo in JS (NOT in SQL) to avoid a full seq-scan on the unindexed data->>raceNo JSONB path — deliberate perf workaround. Cache 300s (respects the engineering notes floor). `source_id` is a deterministic 16-char hex id, `sha256(race_key_v2).slice(0,16)`, so it is stable across runs and restarts without a DB sequence — verified on prod 2026-10-01: `2026-09-30_addington_H_1` → `eda51f0bc5a4ffd2`. The delivered `race_key`/`race_key_v2` carry the meeting type (`{date}_{venueSlug}_{type}_{raceNo}`), and `first_seen_at` is when the race first appeared in the results table (distinct from `ingested_at`, the last write). `pools`, `dividends` and `exotic_pools` are empty arrays where national-tote data does not exist for the meeting (all NZ harness that day) — an empty array is a real "no tote data", never a partial omission. NZ results are thinner than AU: `margin`, `time` and settled SP and dividends are frequently absent, and `pools`/`dividends`/`exotic_pools` come back as empty arrays where no national-tote data exists for the meeting. `meeting_id` is the meeting's own identity, served beside `meeting_key` (unchanged: the Sydney-day key the row is filed under) — the two differ for a UK/IE card that runs after midnight in Sydney, and `race_key`/`race_key_v2`/`meeting_key`/`meeting_id` all follow from the row's stored id. `is_final` collapses `status` to a boolean settled flag (`true` for `resulted`/`finished`/`Final`). `meta.data_note` is always present — `null` when there is nothing to report, else a sentence naming the pending races, the `scheduled_time` fill count (`scheduled_time populated for X of Y rows; remaining rows have no jump time on record.`) or a short board read. All six (`meeting_id`, `meeting_key`, `local_date`, `jump_time_utc`, `meta.data_note`, `is_final`) verified served on prod 2026-10-23.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| date | string (YYYY-MM-DD) | No | – | Meeting date to fetch results for; 400 if not a valid YYYY-MM-DD string. |
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| venue | string | No | – | Case-insensitive substring match on track name/slug. Alias: `track`. |
| track | string | No | – | Alias for venue. |
curl \
-H "X-API-Key: YOUR_KEY" \
"https://krokodds.com.au/api/v1/racing/results/2026-09-01?venue=Randwick"{
"success": true,
"data": [
{
"id": "2026-09-30_addington_H_1",
"race_key": "2026-09-30_addington_H_1",
"meeting_key": "2026-09-30_addington",
"meeting_id": "2026-09-30_addington",
"date": "2026-09-30",
"track": "Addington",
"track_slug": "addington",
"state": null,
"race_no": 1,
"race_type": "H",
"distance_m": 2000,
"race_name": "WOODLANDS STUD BREED TO SUCCEED TROT SS",
"scheduled_time": "2026-09-30 03:55:00",
"jump_time_utc": "2026-09-30T03:55:00Z",
"local_date": "2026-09-30",
"actual_off_time": null,
"winning_time": null,
"going": null,
"race_class": null,
"status": "finished",
"is_final": true,
"winner": {
"tab_number": 4,
"name": "Tamsin Trouble",
"slug": "tamsin-trouble",
"jockey": "S O'Reilly",
"trainer": "S Sutherland",
"win_bsp": null
},
"pools": [],
"dividends": [],
"runners": [
{
"tab_number": 4,
"name": "Tamsin Trouble",
"slug": "tamsin-trouble",
"finish_position": 1,
"is_scratched": false,
"margin": null,
"time": null,
"win_result": "Winner",
"win_bsp": null,
"place_result": "Placed",
"place_bsp": null,
"jockey": "S O'Reilly",
"trainer": "S Sutherland",
"barrier": 4,
"weight": 0
},
{
"tab_number": 6,
"name": "Deltoro",
"slug": "deltoro",
"finish_position": 2,
"is_scratched": false,
"margin": null,
"time": null,
"win_result": null,
"win_bsp": null,
"place_result": "Placed",
"place_bsp": null,
"jockey": "R Close",
"trainer": "J Aarts",
"barrier": 6,
"weight": 0
}
],
"exotic_pools": [],
"ingested_at": "2026-10-01T00:00:36.359Z",
"first_seen_at": "2026-09-30T04:20:09.807Z",
"race_key_v2": "2026-09-30_addington_H_1",
"source_id": "eda51f0bc5a4ffd2",
"non_tab": null
}
],
"meta": {
"count": 1,
"date": "2026-09-03",
"venue": null,
"data_note": null,
"tier": "free",
"timestamp": "2026-09-03T05:30: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.