Settled race results
Cost: 2 credits. Settled AU/NZ race results — finishing order with the bookmaker's own settled fixed prices, plus scratchings and their deductions — and, from 2026-10-06, British and Irish thoroughbred results from Betway's settlement feed: every runner with its starting price (sp on placings and runners) and its finishing position where Betway publishes one (the whole order on the British races measured; on the Irish, the first four first and the rest within about 25 minutes of the off, while the result is still interim), non-runners as deductions with no Rule 4 figure, no dividends and no fixed settling prices (win_price/place_price null). A starter Betway has still not ranked once the result is final did not finish -- Betway ranks every finisher and leaves fallers and pulled-up horses unranked -- and from 2026-10-12 carries abnormal: did not finish with position null. UK racecards publish no race numbers; a GB/IE result takes the running-order number of the race it matched. From 2026-10-12, British and Irish greyhound results come from PointsBet's settled race card: the paid places (three on a six-dog field) with PointsBet's own settled fixed prices as win_price/place_price, the whole field as runners with a position on each placed dog, scratchings as deductions; no starting prices and no dividends on these races.
status is interim until the placings have been stable for 30 minutes, then final. A race that did not run is abandoned (Racing Australia's official notice, applied to every race of the meeting, with status_note carrying RA's word: abandoned, postponed, or transferred to another venue) — empty placings, null runners, filterable with status=abandoned. Settle only against final: an interim placing can still change on protest.
A runners entry is not necessarily a starter. status says whether the runner ran: ran, or scratched / late_scratching / reserve for one that did not. Since 2026-09-08 an AU thoroughbred scratched at the barrier arrives as status: scratched carrying abnormal: 'SB'; a result written before that date carries such a runner as status: ran with a null position. Such a row can still carry sp — the last price RA printed for it. That price is NOT what its deductions row was struck from (measured: 1/sp matches the published win deduction on none of the five stored priced rows), so take the deduction from deductions itself and never derive it. Settle on status, not on presence in runners. The thoroughbred and greyhound collectors do NOT spell a late scratching the same way; the runners field description says exactly how to tell them apart.
Settled prices can be null while status is interim — this is the SP timing, not a gap. The source book publishes the finishing order before its settled dividends, so a result fetched in the minutes after the jump can carry placings whose win_price / place_price are still null. They fill in during the interim window: measured over 7 days (1,541 final results, 2026-09-01), every final result carried settled prices and none was missing them. If you hit null prices, you are inside that window — poll again or wait for final, which is already the only status you should settle against.
sp on runners and on placings is the OFFICIAL starting price — not our consensus, and not the fixed price the bookmaker settled at. The two differ, and both are returned so you can compare them. Thoroughbred SP is Racing Australia's (its favouritism marker lands in sp_note), greyhound SP is our own collection's (Victorian tracks via FastTrack, every other state via the national results pages, from 2026-09-13), and harness SP is always null because no source we hold publishes it. A null sp means unknown — never zero.
race_id joins a result to /v1/racing/price-history, and to /v1/racing/next-to-go while the race was still open — use it rather than matching on venue + race number + start time.
Joining one RACE across endpoints: runner_ref. Joining one HORSE across meetings: horse_ref. Every thoroughbred entry in runners carries runner_ref (ra:<code>), the code Racing Australia published for the runner on race day — the same value the closing-line, price-path and markets archives carry and the live board carried that day, so it joins this result to every other row about the race. Racing Australia issues a new code for the same horse each day, so grouping a career on runner_ref returns one row per start. For a career, every thoroughbred entry in runners and placings carries horse_ref, pe:<name> — the registered name folded to letters and digits — the same value on the live board, the closing-line and price-path archives, /v1/racing/horses/form and /v1/racing/horses/runs. horse_ref is derived at serve time from the name already on the row, so it is on every historical result too. Since 2026-10-16 it is on EVERY racing code, not thoroughbreds alone: greyhound and harness entries carried a null before that. Where a greyhound also has a runner_ref (grv:/grsa:) that per-dog registry id remains the stronger identity and horse_ref sits beside it rather than replacing it — but those refs are attached when a race is archived and only on Australian tracks, so a GB or IE dog, an AU harness runner and every international thoroughbred have horse_ref and nothing else.
country splits the feed: country=AU and country=NZ are the two-URL form of an AU/NZ split. NZ rows come from the bookmaker results feed, which publishes placegetters, so they carry placings without the full runners finishing order the Racing Australia collector adds to AU thoroughbred results.
dividends carries the declared win/place dividends per placegetter per product and the exotic dividends (quinella, exacta, trifecta, first four), each as a return on a $1 stake. Exotics are declared a few minutes after the placings, so they land on a later poll than the result itself — see the field description for the full shape.
market_closed_at and inplay_at are the race lifecycle, captured live and kept here permanently: when the market was first seen shut, and when the race was first seen in-play — the actual off, where start_time is the advertised one and moves. Both are POLL-OBSERVED (polling passes are most frequent in the minutes before the jump), so each is the first poll at which the state was seen rather than the exact instant, and both are SET ONCE. They are copied from the live race row when the result is written. That row is deleted 10 minutes after the jump and results land a median 4.9 minutes after the start (p90 7.4), so a late result keeps null. Null never means the market stayed open. Capture began 2026-09-01, so every result before that date carries null.
Who reports market state, and what you see. Two feeds do. PointsBet closes its book at the real jump — measured 2026-09-03 over 9 live races followed across their jump, 0.2 to 1.4 minutes AFTER the advertised start on AU/NZ cards — and that is what populates market_closed_at for most races. The Betfair Exchange reports state while it quotes the market, which ends about two minutes BEFORE the jump (measured 2026-09-01 on Horsham R3, advertised 05:24 UTC: betfair last seen 119s before the off), which is why results between 2026-09-01 and 2026-09-03 carry null. Exchange-sourced market state is withheld from customer plans pending a data licence, so a race whose state only the exchange saw reads null for customers; bookmaker-sourced state is served to everybody. market_state_source names the feed behind the values you receive. inplay_at stays exchange-only — bookmakers do not run racing in-play.
Coverage: results collection began 2026-08-15, so hours_back cannot reach further than that no matter what you pass. Every row carries coverage_from, the earliest result currently retained, so an empty window is distinguishable from an unsupported one.
Field coverage, which is a different question, and runners: null is not its answer. Every row now carries field_status, field_source and field_note. field_status is complete | pending | overdue | unavailable | unsupported | not_applicable: a field that is here; one the pass that NORMALLY fills this race has not reached yet, with that instant in field_note; one where that pass has been and gone without writing a field but the collector still re-attempts the row; one no scheduled pass still selects, its collector's own candidate window having closed; a code no collector has ever existed for; and a race that did not run. The scheduled progression is pending -> overdue -> unavailable, one direction only, and every step is bounded by a collector's real candidate query rather than by its next run — so nothing here asks you to poll forever. Read overdue carefully: it is NOT terminal. Most rows that reach it stay null, so do not build on a field arriving, but do not write the race off either. And any of those three can become complete, unavailable INCLUDED — nothing un-writes a runners array, so a hand-run collector, a widened window or a late upstream publication can still fill a row we have stopped scheduling passes for. Treat unavailable as 'nothing further is scheduled', never as 'this can never arrive', and re-read rather than caching it as final. The full per-state contract is on the field_status field itself. AU thoroughbred fields come from Racing Australia and AU greyhound fields from our own collection; AU harness, NZ thoroughbred and NZ harness fields have come from TAB New Zealand since 2026-10-04 (field_source: tabnz, hourly, seven-day window). An entry carrying origin: board is a copy of the pre-race board (driver, trainer, barrier, form, positions for placegetters only, no times, SP or margins), not an official finishing field. Collection floors are the 2026-08-21 Sydney card for AU greyhound and the 2026-09-01 card for AU thoroughbred; no collector pass reaches back beyond its own floor, so a race older than one carries unsupported and will not fill. runners is JSON null in every one of these cases and has never been an empty array (0 in the whole store), so runners is None is the complete test. GET /v1/racing/results/coverage answers the same question per Sydney day, category and venue for 1 credit, so you can see what a day holds without paging its results.
going and going_rating (2026-09-10) are track_condition split into the vocabulary /v1/racing/horses/form already uses — 'Good (4)' becomes going: "Good", going_rating: 4 — parsed by the one shared helper so the two surfaces cannot disagree. track_condition is unchanged and is still the raw string the source published.
Request
- Base URL: https://api.puntersedge.online
- URL: https://api.puntersedge.online/v1/racing/results
- Auth: API key in header X-API-Key
Query parameters
How far back to look, in hours (max 7 days)
Single-day alias: date=YYYY-MM-DD returns the races that start on that calendar date in Sydney time (AET), instead of a rolling hours_back window (YYYYMMDD is read the same way). It is the same meeting_date_aet that /v1/racing/closing-lines stores, so the two join on date, venue and race_number. Each race belongs to exactly one date: a race that starts after midnight Sydney time (the last races of a Perth night meeting, British and Irish afternoon and evening racing) is under the next date. Mutually exclusive with hours_back. Also accepted by /v1/racing/closing-lines and /v1/racing/acceptances. NOT by /v1/racing/events, which is forward-looking and takes hours_ahead.
horse,greyhound,harness or omit for all
Alias of categories. Both spellings are accepted on every racing endpoint. An unknown value is a free 422 naming the valid ones.
Case-insensitive exact venue match, comma-separated for several, e.g. 'Rosehill' or 'Randwick,Eagle Farm,Flemington' — the same spelling /v1/racing/next-to-go takes
ISO country codes, comma-separated, case-insensitive (e.g. AU or AU,NZ). Matched against the result's country. Which countries have results at all is published by /v1/racing/results/coverage and the results_scope note on /v1/racing/closing-lines/coverage; GB and IE thoroughbred results come from Betway's settlement feed from 2026-10-06, GB and IE greyhound results from PointsBet's settled race card from 2026-10-12, and ZA thoroughbred results from Easybet's settled race card from 2026-10-15 (the placed runners ranked, sp null because the feed publishes no official starting price); a country with prices but no results source returns no rows here. A result whose country was never resolved (null) is excluded by any value here, so omit the filter if you need those rows.
Filter to 'final', 'interim' or 'abandoned'
Rows per page, newest first, at most 200. A larger value is served as 200 rather than refused, and every response carries X-Limit-Applied, the page size actually used: page with offset += that value, and read only a page shorter than it as the last.
Headers
Response
Successful Response
Example response
[
{
"category": "horse",
"completeness": {
"field_overdue": false,
"field_pending": false,
"result_final": true,
"result_source": "betright",
"retrying": false,
"state": "complete_full_field"
},
"country": "AU",
"coverage_from": "2026-08-15T05:53:00Z",
"deductions": [
{
"name": "Acapulco Girl",
"number": 5,
"place": 0,
"scratched_at": "2026-08-14T07:06:29Z",
"win": 0.01
}
],
"distance_m": 1200,
"dividends": {
"exotics": [
{
"amount": 14.4,
"code": "QN",
"product": "VIC",
"selection": "6,3",
"type": "Quinella"
},
{
"amount": 77.7,
"code": "TF",
"product": "VIC",
"selection": "6,3,9",
"type": "Trifecta"
}
],
"straight": [
{
"amount": 4.6,
"market": "WIN",
"name": "Grinzinger Champ",
"number": 6,
"position": 1,
"product": "FIXED"
},
{
"amount": 5,
"market": "WIN",
"name": "Grinzinger Champ",
"number": 6,
"position": 1,
"product": "MIDDIV"
},
{
"amount": 1.8,
"market": "PLC",
"name": "Grinzinger Champ",
"number": 6,
"position": 1,
"product": "FIXED"
}
],
"straight_types": [
"FIXED",
"MIDDIV"
]
},
"field_source": "racing_australia",
"field_status": "complete",
"going": "Good",
"going_rating": 4,
"market_closed_at": "2026-08-15T05:54:31Z",
"market_state_source": "pointsbetau",
"placings": [
{
"horse_ref": "pe:grinzingerchamp",
"name": "Grinzinger Champ",
"number": 6,
"place_price": 1.8,
"position": 1,
"sp": 4.4,
"sp_note": "F",
"win_price": 4.6
}
],
"race_id": "race_123",
"race_name": "TAB ROSEBUD",
"race_number": 8,
"resulted_at": "2026-08-15T06:01:12Z",
"runners": [
{
"box": 3,
"dead_heat": false,
"horse_ref": "pe:grinzingerchamp",
"jockey": "R Maloney",
"name": "Grinzinger Champ",
"number": 6,
"position": 1,
"runner_ref": "ra:AB12CD34",
"sp": 4.4,
"sp_note": "F",
"status": "ran",
"trainer": "T Gollan"
},
{
"dead_heat": false,
"horse_ref": "pe:acapulcogirl",
"name": "Acapulco Girl",
"number": 5,
"status": "scratched"
}
],
"start_time": "2026-08-15T05:53:00Z",
"status": "final",
"track_condition": "Good (4)",
"venue": "Doomben",
"weather": "Light Rain"
}
]Changes
No recorded changes to this operation across all 1 revision of this API.