---
title: "Greyhound form history for one dog, from our own results"
method: GET
path: "/v1/racing/greyhounds/form"
tags: ["Racing"]
---

# Greyhound form history for one dog, from our own results

`GET /v1/racing/greyhounds/form`

## Request

- Base URL: `https://api.puntersedge.online`
- URL: `https://api.puntersedge.online/v1/racing/greyhounds/form`
- Auth: API key in header `X-API-Key`

Cost: 3 credits. Every run we hold for one greyhound, newest first, from our own collection.

SOURCE. Not a third-party form feed: every run comes off the official public results pages we
read ourselves — Victorian tracks from FastTrack (`source: fasttrack`, `runner_ref: grv:<id>`)
and every other state from the national results pages (`source: grsa`, `runner_ref:
grsa:<id>`). `origin` says which half of the store a run is in: `results` = a race we also
settled and serve on /v1/racing/results, `history` = a race our history collector read back
off the same page for a date our settled store does not cover, whose `result_id` is a
synthetic `hist:…` and joins to nothing. `source.coverage_from` is the oldest run actually
held and `source.results_from` the date the settled half begins, so `runs_total` is the dog's
record over a stated window and not its career. Since 2026-10-13 `runs_total` counts STARTS
(`status: ran`), the same figure as /v1/racing/greyhounds/stats `overall.starts`, and
`held_rows_total` counts every held row, scratchings and unused reserves included -- the rows
`runs` is drawn from. Before then `runs_total` counted every row.

IDENTITY. Pass a name and the runs are grouped on its letters and digits ("Ando's Mac" and
"ANDOS MAC" are one query; the whole name must match). Our two collectors number dogs in
different registries, so a dog that races in Victoria and interstate has two refs; the name
joins them and `runner_refs` lists every id seen. Pass a ref and you get that ref's runs —
plus, when the registry map has proved the two refs are one dog (one grv id, one grsa id,
trainers that agree or do not contradict), that dog's runs in BOTH registries. A name
matching nothing is a 404 and costs nothing.

READING A RUN. `position` is the finishing place and is null when the dog did not run (`status`
says `scratched` or `reserve`) or did not complete the course. `time_s` is the dog's own time
and `win_time_s` the winner's in the same race. `sp` is the official starting price as
published with the result; null means unknown, never zero. `margin` is the source's own text:
lengths behind the winner, and on Victorian tracks the winner's row carries its winning margin.
`field_size` is how many dogs ran.

THE MEASURED COLUMNS, AND WHY THEY ARE OFTEN NULL. `first_split_s`, `second_split_s`,
`weight_kg`, `pir` and `grade` are printed by the source pages and have been carried through
since 2026-09-21. Each is null wherever that page printed nothing, and the gaps are
structural, not random: FastTrack publishes one split and no second; PIR comes from
FastTrack's own column on Victorian tracks and, since 2026-09-29, from the national page's In
Race Positions card, which only some tracks print (see `pir`); Western Australian meetings
mostly print no weight; a rug 9/10 reserve that never started carries no weight, split or PIR
at all. Sampled on 2026-09-21 over
46 freshly read race pages, a grade appeared on 46/46 races and 362/362 runner rows, a first
split on 288/362 and a weight on 295/362. ⚠️ A STORED FIELD IS NEVER REWRITTEN, so a run
settled before 2026-09-21 carries none of the five however well its page printed them — read
them per run, never as a property of the dog.

## Query parameters

- `dog` string, required: Dog name (matched on letters and digits, case-insensitive, whole name), or a runner_ref like grv:1055038365 / grsa:441535 to restrict to one registry id.
- `limit` integer: Most recent runs to return.

## Headers

- `X-API-Key` string
- `X-RapidAPI-Proxy-Secret` string

## Response `200`

Successful Response

- GreyhoundFormOut
  - `dog` string, required: The dog's name as our results spell it.
  - `name_key` string, required: The identity the runs were grouped on (letters and digits).
  - `runner_refs` string[], required: Every registry id seen for this name, across both collectors.
  - `runs_total` integer, required: STARTS we hold for this dog since `source.coverage_from`: runs with `status` `ran`, the same count as /v1/racing/greyhounds/stats `overall.starts`. A scratching or an unused reserve is not a start. Before 2026-10-13 this counted every held row; that count is `held_rows_total`.
  - `held_rows_total` integer, required: Every row we hold for this dog since `source.coverage_from`: its starts plus its scratchings and unused reserves (rows whose `status` is not `ran`). `runs` is the newest `limit` of these rows. Measured 2026-10-13: 6,247 of the store's 103,553 rows were not starts, and 102 of its 12,191 dogs held rows but no start.
  - `runs` GreyhoundRun[], required
    - `date` string, nullable: Sydney calendar date of the race; the London date on a British or Irish run.
    - `start_time` string, nullable: Scheduled start, UTC.
    - `venue` string, nullable
    - `race_number` integer, nullable
    - `distance_m` integer, nullable
    - `race_name` string, nullable
    - `track_condition` string, nullable
    - `box` integer, nullable
    - `number` integer, nullable: Rug number; equals box for a starter.
    - `position` integer, nullable: Finishing place. Null when the dog did not run (see `status`) or did not complete the course. On a British or Irish run the positions are placings, so null with `status: ran` means not placed (see `source.note` on /v1/racing/greyhounds/field).
    - `status` string, nullable: `ran`, `scratched`, or `reserve` (a rug 9/10 reserve that never got a box).
    - `margin` string, nullable: Lengths behind the winner as the source printed it; the winner's own row carries the winning margin on Victorian tracks and null elsewhere.
    - `time_s` number, nullable: The dog's own finish time in seconds.
    - `first_split_s` number, nullable: First sectional in seconds, as the source page printed it. Null where it printed none — a reserve that never started has none, and some tracks publish no sectionals at all.
    - `second_split_s` number, nullable: Second sectional in seconds. Null on every Victorian run: FastTrack publishes one split, not two.
    - `weight_kg` number, nullable: Race-day weight in kilograms. Null where the page prints no weight — Western Australian meetings mostly print none (measured 2026-09-28 over 2026-09-13..28: Cannington 2.5%, Mandurah 15.4%, Northam 68.7% of runs).
    - `pir` string, nullable: Position in running as TEXT, one digit per in-running mark ("21" = 2nd then 1st at the marks; the finish is not a mark). Victorian runs: FastTrack's own PIR column. Other states, since 2026-09-29: the national page's In Race Positions card, which only some tracks print — measured 2026-09-28 over the 158 national races of 2026-09-27..28: NSW 79.6%, QLD 79.0%, WA 100% of runs, SA and TAS about 0% (no card at Angle Park, Gawler, Launceston, Rockhampton or Temora). The two sources' marks are not the same points on a track: compare PIR within one source. Null where the page printed none.
    - `grade` string, nullable: The race's grade in the SOURCE'S OWN WORDS — "M", "4/5", "FFA" on the national pages, a race type like "Tier 3 - Maiden" on FastTrack. The two vocabularies are NOT mapped onto each other and must not be compared across states. Null on runs whose field was stored before 2026-09-21.
    - `win_time_s` number, nullable: The winner's time in the same race, so `time_s - win_time_s` is the deficit.
    - `sp` number, nullable: Official starting price, decimal return on $1. Null = unknown, never zero.
    - `dead_heat` boolean
    - `trainer` string, nullable
    - `field_size` integer, nullable: Dogs that ran in that race.
    - `runner_ref` string, nullable: Registry id of the dog as the collector for that track numbers it: grv:<id> or grsa:<id>.
    - `source` string, nullable: `fasttrack` or `grsa` — which collector wrote the race; `pointsbetau` on a British or Irish run.
    - `origin` string, nullable: `results` — the race is one we settled and serve on /v1/racing/results; `history` — the race was read back off the same official results page by our history collector and has no results row.
    - `result_id` string, nullable: Id of the /v1/racing/results row this run came from. On an `origin: history` run it is a synthetic `hist:…` id that joins to nothing.
  - `source` SourceBlock, required
    - `feed` string: Where the data comes from: our own collection of published AU greyhound results, Victorian tracks via FastTrack (runner_ref grv:) and every other state via the national results pages (runner_ref grsa:). Runs on or after `results_from` are races we settled ourselves; earlier runs are the same pages read back by our history collector. Refreshed hourly. On a British or Irish race (/v1/racing/greyhounds/field, from 2026-10-12) `region` reads GB-IE and the runs are our own GB/IE results from PointsBet's settled race card, read live.
    - `region` string
    - `sport` string
    - `coverage_from` string: Sydney date of the OLDEST run in the store. A dog's record here starts here.
    - `results_from` string: Sydney date our own settled results begin. A run on or after it has `origin: results` and a `result_id` that joins to /v1/racing/results; an earlier one has `origin: history` and does not.
    - `coverage_to` string, nullable: Sydney date of the latest race in the store.
    - `collectors` string[]: Which of our collectors can contribute a run: `fasttrack` = Victorian tracks, `grsa` = every other state.
    - `refreshed_hourly` boolean: The store is rebuilt from our results at :58 each hour, after both collectors have written.

## Other responses

- `401`: Missing or invalid API key. Send `X-API-Key`. See https://puntersedge.online/developers/errors
- `402`: Monthly credit allowance exhausted for this plan. Upgrade at https://puntersedge.online/api/pricing
- `422`: Validation Error
- `429`: Rate limit exceeded for this plan. Honour the `Retry-After` header (seconds) before retrying. See https://puntersedge.online/developers/rate-limits
- `500`: Unexpected server error. Safe to retry with backoff.

---

[API](https://skmtc.dev/puntersedge/apis/puntersedge-odds-api.md) · [All operations](https://skmtc.dev/puntersedge/apis/puntersedge-odds-api/llms.txt) · [OpenAPI document](https://skmtc.dev/puntersedge/apis/puntersedge-odds-api/revisions/f35b6aab1946?raw)
