Racing

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.

get/v1/racing/results

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

hours_backinteger

How far back to look, in hours (max 7 days)

datestring nullable

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.

categoriesstring

horse,greyhound,harness or omit for all

categorystring

Alias of categories. Both spellings are accepted on every racing endpoint. An unknown value is a free 422 naming the valid ones.

venuestring

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

countrystring

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.

statusstring

Filter to 'final', 'interim' or 'abandoned'

limitinteger

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.

offsetinteger

Headers

X-API-Keystring
X-RapidAPI-Proxy-Secretstring

Response

Successful Response

race_idstring nullable

Race id, joinable to /v1/racing/price-history and (while the race is still open) /v1/racing/next-to-go. Null if the race cannot be resolved in the price-history store.

coverage_fromstring nullable

Start time of the earliest result currently retained.

venuestring nullable required
venue_idstring nullable
venue_canonicalstring nullable
venue_sitestring nullable
race_numberinteger nullable required
categorystring nullable required
countrystring nullable required
start_timestring required
race_namestring nullable
distance_minteger nullable
track_conditionstring nullable
goingstring nullable

Track condition word, normalised: Good, Soft, Heavy, Firm, Fast, Synthetic. Parsed from track_condition with the same helper /v1/racing/horses/form uses, so the two surfaces agree. Null when track_condition is null or unparseable; track_condition remains the raw string exactly as the source published it.

going_ratinginteger nullable

Numeric going rating 1-12 (the 4 in 'Good (4)'), or null. NULL IS THE MAJORITY CASE, not an exception for two rare words: most stored conditions are a bare word carrying no number at all. Measured 2026-09-10 across all 5,579 stored results, a bare 'Good' is 3,954 rows (71%) and yields null, so a rating is present on roughly 29% of rows — greyhound and other non-thoroughbred meetings publish an unrated word as a rule. A rating is never guessed from the word ('Synthetic', 67 rows, and 'Firm', 0 rows, never carry one). Separately, 205 rows store the four-character STRING 'None' in track_condition: going and going_rating are both null on those, while track_condition still serves that literal string, because track_condition is the raw source value passed through untouched.

weatherstring nullable
statusstring required

interim | final | abandoned. interim until the placings have been stable for 30 minutes, then final. abandoned (2026-09-06) is a race that did NOT run: Racing Australia's official Abandoned & Transferred Meetings notice for that venue and date, applied to every race of the meeting — placings are empty and runners null. Settle only against final; treat abandoned as a void for settlement purposes.

status_notestring nullable

Only on abandoned rows: RA's own word for the non-run — "abandoned", "postponed", or "transferred to <venue>". A postponed or transferred meeting did not run at THIS venue on THIS date; if it ran elsewhere or later it appears as its own result.

placingsobject[]

The placegetters: {position, number, name, win_price, place_price, sp, sp_note, horse_ref}. win_price and place_price are the SETTLING BOOKMAKER'S FIXED prices. horse_ref (added 2026-09-21) is the same pe:<name> horse identity the runners entries carry, derived at serve time from the name on the placing and present on every placing — null off thoroughbred. It is the key that joins this placing to the same horse on another meeting; runner_ref on the matching runners entry joins the rows about this race and will not, because Racing Australia issues a new code for the same horse each day. sp is the OFFICIAL STARTING PRICE as a decimal return on a $1 stake (4.6 means $4.60), null where it is unknown — never 0. It is the settling market's own price, not our consensus and not a bookmaker's fixed price: thoroughbred SP comes from the Racing Australia results table, greyhound SP from our own collection of published results (Victorian tracks via FastTrack, every other state via the national results pages, both from 2026-09-13), and HARNESS SP IS ALWAYS NULL — no source we hold publishes it. sp_note carries Racing Australia's favouritism marker on thoroughbred runners ('F' favourite, 'EF' equal favourite) and is null everywhere else. Coverage RE-MEASURED 2026-09-08 over the whole retained store, counting only rows whose status is ran (a barrier scratching is not a starter and its price is not in this denominator): 88.6% of thoroughbred starters carry sp (2,105 of 2,375); on the greyhound races collected since 2026-09-13, 2,054 of 2,077 Victorian starters do (98.9%) and 4233 of 4596 of the other states' starters do (92.1%), both measured 2026-09-20. The Racing Australia block that held thoroughbred SP at 0% when this was last measured on 2026-09-03 has lifted and the collector has been landing meetings since. A null sp is unknown, never zero — RA prints no SP at all on some rows. On placings, sp is copied from the matching runners entry when the response is built, so the two can never disagree. On a race with no runners payload the sp and sp_note KEYS ARE ABSENT from each placing — not present and null. The copy step is what creates them and it is skipped when there is nothing to copy from, so a schema-validating consumer sees a different object shape, not a null: read them with .get(). The keys are deliberately NOT normalised in, because adding them here would change the shipped payload of every COMPLETE race too, and nothing may move under a customer mid-integration. field_status tells you which case you are in before you look.

runnersobject[] nullable

One entry per runner: {number, box, name, position, status, abnormal, margin, time_s, dead_heat}. Presence in this list is NOT proof the runner started. status is what says so, and status is what you settle on. ⚠️ COVERAGE. Read field_status on the row FIRST — it is the per-race answer, and it is what separates a field that has not been filled yet from one that never will be. Two different facts live here. (1) WHETHER THERE IS A FIELD AT ALL. Measured 2026-09-10 across the whole retained store — 5,577 results, 2,902 of them serving runners: null: AU greyhound carried a field on 2,360 of 3,219 races, AU thoroughbred on 315 of 1,104, and AU harness, NZ thoroughbred and NZ harness on none, as no collector covered those three codes then. Since 2026-10-04 TAB New Zealand fills them (field_source: tabnz, hourly, seven-day window) and has replaced the board copies described next wherever it could match the race; /v1/racing/results/coverage gives the current share per day, code and venue. FROM 2026-09-29 harness and NZ fields come from the pre-race board (origin: board): driver, trainer, barrier, form; positions only for placegetters; no times, SP or margins. Such a field is copied from the live board when the result is first written, before the board is purged 10 minutes after the jump, so a race whose result landed after the purge still has none. On these entries "origin": "board" is set on every entry, box holds the barrier (as on thoroughbred entries), jockey is the harness DRIVER, weight_kg and form are what the board showed, status is scratched for a runner the race's scratchings or deductions name and ran otherwise, and position is set for placegetters ONLY — a null position on an origin: board entry means 'not a placegetter, or not known', never 'did not finish'. Inside the two supported codes it is not a clean ramp either: each is filled by a scheduled pass, and where that pass cannot match a race with certainty it writes nothing rather than another race's field, so past the fill window 104 of 2,201 AU greyhound races (4.7%) and 44 of 288 AU thoroughbred races (15.3%) keep runners: null for good — field_status: unavailable, and polling them will not help. runners is JSON null in every one of these cases and has never once been an empty array (0 empty arrays in the whole store, measured the same day), so runners is None is a safe test and an empty field is not a shape you have to handle. (2) THE SHAPE OF A FIELD THAT IS PRESENT, which is where the 2026-09-08 date belongs. An AU thoroughbred field WRITTEN from 2026-09-08 carries every starter plus every runner Racing Australia printed as scratched; one written before that date carries STARTERS ONLY, because the collector dropped RA's scratched rows and a stored field is never rewritten. Measured 2026-09-08, all 244 thoroughbred fields stored at that point were the old shape and 198 of them publish a deductions row for a horse absent from runners. So on an older race deductions is the list of scratchings and runners is the starters; do not read a short runners array as a small field. Greyhound fields have carried the whole field since greyhound collection began on the 2026-08-21 Sydney card — but 859 AU greyhound races carry no field at all, which is question (1) and not this one. position is the finishing position for every runner that completed the race — not just the placegetters — and is null whenever there is none: the runner did not start, or it started and did not finish (except on an origin: board entry, which carries placegetters' positions only — see above). status is ran | scratched | late_scratching | reserve (an emergency that never got a start). abnormal is the official reason cell, passed through VERBATIM from the source — on AU thoroughbred it is Racing Australia's own Finish cell whenever that cell is not a number. THERE IS NO CLOSED LIST OF CODES and you should not write a match statement that assumes one: the source invents them, and a code nobody here has seen before will reach you unchanged rather than be dropped or renamed. Everything stored to date, with counts as at 2026-09-14: Fell (101), TailedOff (32), SB (25), PulledUp (8), FF (1, Rosehill R4 on 2026-09-12), LP (1). Treat abnormal as the authoritative explanation for a missing position, and treat an unfamiliar value as a did-not-finish unless status says otherwise — which is exactly what this API does: only codes PROVEN to mean the runner never left the barrier flip status to scratched, and that list currently holds one entry, 'SB'. Anything else stays ran, deliberately, because misreading a starter as a non-starter turns a losing bet into a refund. It carries TWO families that settle in OPPOSITE directions, so read it with status and never alone. (1) A DID-NOT-FINISH reason on a row whose status is ran — Fell, PulledUp, Disqualified, TailedOff, StayedInBox, FF and LP are the ones seen so far: the runner started and simply has no finishing position, and a bet on it lost. (2) A DID-NOT-START reason on a row whose status is scratched — 'SB', Racing Australia's code for scratched at the barrier: the runner was taken out of the market before the jump, so position is null, it is in no placings entry, and bets on it were refunded while the rest of the race was deducted. An 'SB' row may still carry sp — the last price Racing Australia printed for it, kept rather than blanked because it is a real market fact about the withdrawn runner. It is NOT the basis of the deduction, and you must never derive one from the other: sp comes from RA's results table while a deduction is struck by the settling bookmaker, and they do not agree. Measured 2026-09-08 across all five stored 'SB' rows that carry a price, 1/sp equals the published win deduction on NONE of them — Varejao, Sunshine Coast R4 2026-09-06, saddlecloth 5, withdrawn about 2 minutes 20 before the jump: sp 3.70, so 1/3.70 is 0.27 in the dollar, against a published deductions row of 0.18 win and 0.15 place; Dubai Dancer, Warrnambool R5: 1/5.50 is 0.18 against a published 0.10. Settle from deductions, which is authoritative. None of the five carries a position or a margin. Telling a barrier scratching from one made days earlier is CODE-SPECIFIC, and the two collectors do not spell it the same way — do not write one rule across categories. On AU thoroughbred (Racing Australia) both are status: scratched, and abnormal is the discriminator ONLY in one direction: a barrier scratching carries 'SB'; every other scratching carries abnormal null. Both carry their saddlecloth number, both carry box null (the runner has no barrier it jumped from — RA prints 0 there and we do not pass that sentinel on), and an ordinary scratching carries sp null while an 'SB' may carry one. So abnormal == 'SB' identifies a barrier scratching; abnormal null tells you only that it was not one, not how early it happened — use deductions[].scratched_at for that. On greyhound (our own collection since 2026-09-13: FastTrack for Victorian tracks, the national results pages for every other state) abnormal is null on every scratching and status carries three values: ran, scratched (merged in from our own deductions, so it never says how late), and reserve for a rug 9/10 reserve that never got a box. late_scratching was the retired interim feed's greyhound-only value — a thoroughbred barrier scratching does NOT use it — and it is no longer emitted; scratched does not carry identical meaning in the two codes. deductions carries scratched_at for either, and is the one cross-code way to see how close to the jump a runner came out. dead_heat is true on each runner sharing a position. IDENTITY. runner_ref (ra:<code>) is the code Racing Australia published for this runner on race day. It is the same value on the closing-line, price-path and markets archives, on the live board on race day, and on /v1/racing/acceptances once that day's field has been read, so it joins this runner across every endpoint for this race. Racing Australia issues a new code for the same horse each day, so it is not a horse identity: the same horse carries a different ra: code at each meeting. horse_ref (pe:<name>) is: the registered name folded to letters and digits (trailing country parenthetical off), the same value on results, the live board, the closing-line and price-path archives, /v1/racing/horses/form, /v1/racing/horses/runs and the backfill, and it is the key to join a horse across meetings. It is derived at serve time from the name on the row, never stored, so every historical row carries it. On every racing code since 2026-10-16 — greyhound and harness runners carried a null before that and now carry the same pe:<name> fold, which for them is the only identity that joins a runner to itself across meetings. On GREYHOUNDS runner_ref IS the dog: grv:<id> for Victorian tracks as FastTrack numbers the dog and grsa:<id> elsewhere as the national results pages number it — per-dog registry ids that DO persist across meetings, in two namespaces, so a dog racing in both is two refs until mapped. runner_ref is null while a code's registry source is not yet wired. trainer and jockey come from the same official results source and may be null where that source is not yet live for the code. GREYHOUND-ONLY, ADDITIVE FROM 2026-09-21, five measured columns the results pages print. first_split_s is the first sectional in seconds exactly as the source page printed it, null where the page printed none. second_split_s is the second sectional, and is null on EVERY Victorian run because FastTrack publishes one split and not two. weight_kg is the greyhound's race-day weight in kilograms, null where the page carries no weight column at all — Western Australian meetings carry none (0 of 36 runner rows sampled 2026-09-21). pir is position-in-running text passed through as a STRING and never a number ("21" means 2nd at the first mark then 1st at the second): FastTrack's own column on Victorian runs and, since 2026-09-29, the national page's In Race Positions card elsewhere, which only some tracks print (see /v1/racing/greyhounds/form pir for the per-state rates) — the marks are each site's own, so compare PIR within one source; null where the page printed none. weather (added 2026-09-29) is the meeting's weather in the national page's OWN words ("Fine", "Light showers", "Overcast"), stamped on every entry of the field exactly as grade is; null on Victorian (FastTrack) fields, which print none, and ABSENT on fields written before it existed — measured 2026-09-29, 170 of the 2,012 stored greyhound fields carry it, from the 2026-09-27 card on. It is not on /v1/racing/greyhounds/form. grade is the race's grade in the SOURCE'S OWN WORDS — "M", "4/5" or "FFA" on the national pages, a race type such as "Tier 3 - Maiden" on FastTrack — and the two vocabularies are NOT mapped onto each other, so do not compare a Victorian grade with an interstate one. ⚠️ A STORED FIELD IS NEVER REWRITTEN, so a greyhound field written before 2026-09-21 carries none of these five keys AT ALL — absent, not null — and no thoroughbred field carries them in any era: read them with .get(). Measured on 46 freshly read race pages on 2026-09-21, a grade appeared on 46/46 races and 362/362 runner rows, a first split on 288/362 and a weight on 295/362; the rows without them are overwhelmingly rug 9/10 reserves, which never started and for which the page prints nothing. sp is the OFFICIAL STARTING PRICE as a decimal return on a $1 stake (4.6 means $4.60), null where it is unknown — never 0. It is the settling market's own price, not our consensus and not a bookmaker's fixed price: thoroughbred SP comes from the Racing Australia results table, greyhound SP from our own collection of published results (Victorian tracks via FastTrack, every other state via the national results pages, both from 2026-09-13), and HARNESS SP IS ALWAYS NULL — no source we hold publishes it. sp_note carries Racing Australia's favouritism marker on thoroughbred runners ('F' favourite, 'EF' equal favourite) and is null everywhere else. Coverage RE-MEASURED 2026-09-08 over the whole retained store, counting only rows whose status is ran (a barrier scratching is not a starter and its price is not in this denominator): 88.6% of thoroughbred starters carry sp (2,105 of 2,375); on the greyhound races collected since 2026-09-13, 2,054 of 2,077 Victorian starters do (98.9%) and 4233 of 4596 of the other states' starters do (92.1%), both measured 2026-09-20. The Racing Australia block that held thoroughbred SP at 0% when this was last measured on 2026-09-03 has lifted and the collector has been landing meetings since. A null sp is unknown, never zero — RA prints no SP at all on some rows. Null runners means the full field is not available for this race — never an empty field; every AU and NZ code carries one (AU thoroughbred, AU greyhound, AU harness, NZ harness, NZ thoroughbred). placings remains the source for the settling bookmaker's own fixed prices, and now also carries sp copied from here.

field_statusstring

Why runners is or is not there, per race — the field a caller was missing when runners: null was the only signal and it collapsed several different futures into one. SIX values. complete: runners is present. It is set whenever a field is stored, including on an abandoned race that unexpectedly carries one, so field_status == 'complete' is a safe gate before parsing. An AU harness result settled between 2026-09-29 and 2026-10-04 that the TAB New Zealand pass could not match may still hold the PRE-RACE BOARD copy — every entry origin: board, field_source null, positions for placegetters only and no times, SP or margins — so check origin before treating it like a collected field. On GB and IE thoroughbred (from 2026-10-06) complete means Betway's field (field_source: betway_uk, every entry origin: betway_uk): every runner with its starting price in sp and sp_fraction and a position wherever Betway publishes one — every finisher on the British races measured; on the Irish ones Betway ranks the first four first and the rest of the order within about 25 minutes of the off, which the interim result picks up, so until then an unplaced Irish starter is ran with position null — and non-runners as scratched; no margins, times, barriers, jockeys or dividends, and no Rule 4 figure on the deductions. On AU harness, NZ harness and NZ thoroughbred (from 2026-10-04) complete means the TAB New Zealand field (field_source: tabnz, every entry origin: tabnz): the full finishing order with margins in lengths, each runner's time (NZ racing only — TAB New Zealand publishes no times on Australian races), barrier and gate, driver in jockey (gallops add weight_kg, the total carried), trainer, scratchings with scratched_at, and TAB New Zealand's own pool win and place dividends on the placegetters; sp is null because TAB NZ publishes no official starting price. A board copy written before 2026-10-04 is replaced by the first pass. On ZA thoroughbred (from 2026-10-15) complete means the Ambernet settled race card (field_source: easybet_za; each entry's origin is the book it was read from, easybet_za or topbet_za): every runner, with a position on the runners the book ranks (the placed runners; unplaced starters stay ran with position null), jockey and trainer, non-runners as scratched; no margins, times, SP or dividends, and no deduction figure on the deductions. pending: a collector exists for this code and the pass that NORMALLY fills this race has not been yet; field_note names the UTC instant by which it will have run. overdue: that pass has been and gone without writing a field, but the collector still selects this row as a candidate and keeps re-attempting it — this state is NOT terminal. For AU greyhound the hourly pass for its state (FastTrack for Victoria, the national results pages elsewhere) re-reads every field-less race inside its seven-day window, and so does the hourly TAB New Zealand pass for AU harness, NZ harness and NZ thoroughbred; for AU thoroughbred a bounded re-fetch reaches six days but is run by hand rather than on a schedule. Most rows that reach overdue stay null, so do not build on a field arriving — but do not write the race off either, and field_note gives the horizon. unavailable: no scheduled pass still selects this row. Its collector's own candidate window closed at the instant in field_note and no field was written — the pass either never matched the race or refused an ambiguous match, which it does rather than write another race's field. unsupported: no collector exists for this category/country. Since 2026-10-04 that is only a foreign race that appears because an AU book listed the meeting: AU harness, NZ harness and NZ thoroughbred (1,254 of the 5,577 stored results on 2026-09-10) all gained their TAB New Zealand collector that day — and no amount of waiting will produce one. not_applicable: the race did not run (abandoned, postponed or transferred) and carries no field, so there is nothing to collect. TRANSITIONS, stated explicitly because acting on the wrong one costs you data. The scheduled progression is pending -> overdue -> unavailable, one direction only. It is bounded at every step by a collector's own window rather than by hope: a race can sit matched-and-never-resulted forever (The Gardens, 2026-09-05, 12 races), and an open-ended pending would have you polling it forever. Any of those three becomes complete the moment a field is written, AND THAT INCLUDES unavailable — nothing un-writes a runners array, so a collector re-run by hand, a widened window or a late upstream publication can still fill a row we have stopped scheduling passes for. So unavailable means 'nothing further is scheduled', never 'this can never arrive'; if you reconcile, re-read rather than caching it as final. unsupported and not_applicable are properties of the racing code and of the race itself, not of a schedule, and do not change on their own.

field_sourcestring nullable

Which collector owns runners for this race: racing_australia (AU thoroughbred), fasttrack (AU greyhound at Victorian tracks) and grsa (AU greyhound everywhere else), the last two our own collection, or null where no collector exists — including a complete AU harness row settled between 2026-09-29 and 2026-10-04 whose runners is still the pre-race board copy (origin: board), which no collector owns; tabnz (TAB New Zealand) owns AU harness, NZ harness and NZ thoroughbred; betway_uk (Betway's settlement feed) owns GB and IE thoroughbred from 2026-10-06; pointsbetau (PointsBet's settled race card) owns GB and IE greyhound from 2026-10-12. Set on pending, overdue, unavailable and complete rows alike — it names who WOULD fill the field, not who did.

field_notestring nullable

Prose for the non-complete states: which pass fills this code, when its normal pass for this race has been and gone, how long the collector keeps re-attempting the row, or that the code has no source at all. Null on complete. Written for a human reading a response — branch on field_status, never on this text.

completenessobject nullable

Added 2026-10-20, additive. Result and field completeness in one object, so a caller does not have to combine status and field_status itself. state is one of four values: provisional (the result is not final yet), final_placings (final placings, and dividends where the settling book declares them, but no full field — field_status says whether one is still coming), complete_full_field (final, and runners holds the whole field) and not_run (abandoned, postponed or transferred). result_final is status == 'final'; result_source names the feed that settled the race (betright, pointsbetau, betway_uk, ambernet_za, racing_australia for an abandonment, or null when unknown). For a race whose field is not in yet: field_pending / field_overdue mirror field_status, field_due_by is when the pass that normally fills it will have run, overdue_since is that same instant once it has passed, retrying is true while a scheduled pass still re-attempts the row and retry_until is the collector's retry horizon. source_refused_since (UTC) is set while the field's source is refusing our collector for this race (FastTrack for Victorian greyhounds since 2026-10-13). last_successful_collection_at is the field collector's latest served run where the collector records one (FastTrack only; null for every other source). The four state values are counted per lane by /v1/racing/results/coverage (result_completeness). Read it with .get().

deductionsobject[]

Scratched runners and the deduction applied to bets already struck. win and place are fractions of the dollar in the range 0-1 (0.34 = 34 cents in the dollar), as published by the settling bookmaker.

dividendsobject nullable

Dividends declared for the race. straight holds one row per placegetter per product: {position, number, name, market ('WIN' or 'PLC'), product, amount}. exotics holds one row per exotic product: {type, code ('QN', 'EX', 'TF', 'FF'), selection, product, amount}, where selection is the winning saddlecloth numbers in finishing order, e.g. '5,1'. Every amount is the return on a $1 stake, the same convention as the odds fields — a 'FIXED' straight dividend equals that runner's own settled fixed price. product names the settling pool: 'FIXED' is the bookmaker's own price, the rest are tote products (SP, MIDDIV, VIC, RD+, BT+SP). A product that declared no dividend is omitted rather than returned as 0. Exotic dividends are only declared once the race fully settles, a few minutes after the placings, so a just-resulted race can carry straight while exotics is still empty — it fills in on a later poll. multi_race (from 2026-09-29) holds the meeting-level products — Quaddie, Giant 6, Daily Double and the like — on the race that is the product's FINAL leg and on no other race: one row per declared pool, {code (the book's own, e.g. 'RC-QUADDIE'), type ('Quaddie'), product ('VIC', 'BT', ...), selection (the winning saddlecloth in each leg, in leg order, e.g. '1,4,2,11'), amount (the return on $1), legs (the race numbers the product spans, e.g. [7, 8, 9, 10])}. Each row is published as the settling book declares it: Rosehill R10 on 2026-09-26 closed the Quaddie (R7-R10, $128.40 VIC and BT), a Giant 6 (R5-R10, $544.40 VIC) and a second Giant 6 row whose selection names five legs, at $1.00. A result stored before 2026-09-29 carries NO multi_race key at all — read it with .get() — and on a newer row it is a list, empty when the race closes no product. straight_types is the book's raw list of product codes, retained for backwards compatibility. note (rare, from 2026-10-03) is a plain-text caveat on the dividends, absent on almost every race: e.g. Randwick R1 on 2026-10-03, where the settling book paid on the first horse past the post and a protest then changed the official placings, so these dividends name a different winner from placings. Read it with .get().

sectionalsobject nullable

NSW harness sectional times, or null. Present on AU harness races at NSW tracks once Harness Racing NSW has published the meeting's Sectional Times sheet, usually a few days after the meeting, and it has been matched to this race by venue, Sydney date, race number and the winner's saddlecloth. Race level: gross_time_s (the winning time), mile_rate_s, lead_time_s (null where none was taken), quarters_s (the leader's four quarters, in order), distance_m. runners lists every starter by saddlecloth number with name, position (the official placing; dead heats share it and set dead_heat), margin_m (metres behind the winner), time_s (the runner's own time), behind_800m_m and wide_800m, behind_400m_m and wide_400m (metres behind the leader and how many horses wide, at the 800 m and the 400 m), and q3_s and q4_s (the runner's own third and fourth quarters). source is hrnsw and source_url is the sheet it was read from. Times are in seconds and distances in metres. Read it with .get().

resulted_atstring nullable
market_closed_atstring nullable

UTC time at which the market was FIRST seen shut — the book stopped taking bets on this race. Poll-observed: this is the first poll that saw the state, not the exact instant, so it lands up to one polling pass after it, and passes are most frequent in the minutes before the jump. Set once: a market that flickers SUSPENDED -> OPEN -> SUSPENDED keeps the FIRST suspension. TWO SOURCES report market state. 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 the Betfair Exchange reports it while it quotes the market, which is until about two minutes before the jump. market_state_source names the one that produced this value. Exchange-sourced stamps are withheld from customer plans, so a race seen shut only by the exchange reads null. Bookmaker-sourced stamps are served to everybody. Null also means no feed observed a transition — it never means the market stayed open. 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, so a late result keeps null.

inplay_atstring nullable

UTC time at which the race was FIRST seen in-play — the actual off, as opposed to start_time, which is the ADVERTISED off and moves. Same poll-observed, set-once semantics as market_closed_at, and withheld on the same source rule. Reported by the Betfair Exchange only: bookmakers do not run racing in-play, so a bookmaker feed says when it CLOSED its book, not when the race went. For a race the exchange has stopped quoting, market_closed_at from a bookmaker is the closest measured instant to the off. 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, so a late result keeps null.

market_state_sourcestring nullable

Which feed's market state produced market_closed_at / inplay_at on this race — 'pointsbetau' for the bookmaker, 'betfair_ex_au' for the exchange. Set once, alongside the first stamp. Null when no transition has been observed, and null for customer plans whenever the stamps themselves are withheld, so a non-null value here is always the provenance of values you can see.

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.