Live Plus · Statistics endpoints
Three endpoints that return greyhound form already aggregated — strike rate by distance, trap, track, grade and going for any dog, trainer or owner. One call replaces an archive download and an aggregation layer you would otherwise write and maintain.
Built for models, useful to everyone
Hand an assistant three hundred race lines and ask which trap suits a dog and it will do arithmetic it is not good at, confidently. Hand it one object where the arithmetic is already done and it reasons over facts instead. That is the whole design brief for these endpoints, and it happens to be what a human analyst wants too.
A complete dog profile is around 4KB. Three hundred form lines are not, and truncating them silently changes the answer.
Every percentage arrives with its runs. A model cannot mistake three runs at 33% for
thirty at 33%, because both numbers are present.
Function calling works best when a question maps to a single call. These map one-to-one onto the questions people actually ask.
What each one does
Every example below is a real response from the live API.
Distance, trap, track, grade and going — each with runs, wins, places, strike rate and place rate.
by_distance also carries best and average winning time.
Times appear only there, deliberately. A time averaged across a 268m sprint and a 500m race describes neither, and returning it would invite exactly the wrong comparison.
Going is banded — fast, standard, slow — because the raw allowance shatters a career into slices
too small to read. The underlying values still come back in going_values.
# A Bad Winter — 59 runs, real response "overall": { "runs": 59, "wins": 11, "win_pct": 18.64 } "by_distance": [ { "distance_m": 462, "runs": 28, "win_pct": 21.43, "best_time_s": 28.02 }, { "distance_m": 268, "runs": 11, "win_pct": 9.09 } ] # same dog. right trip, wrong trip. "by_trap": [ { "trap": 1, "runs": 40, "win_pct": 22.5 } ]
The same splits over a rolling window, plus track_id to narrow every one of them to a
single course. This is the question a flat results list cannot answer without you counting.
The window is bounded on purpose. A busy yard has thousands of runners a year, and trainer form is not permanent — a strike rate from four years ago describes a different operation.
# M E Wiley — 12 months, real response "overall": { "runs": 1887, "wins": 342, "win_pct": 18.12 } "by_track": [ { "track": "Romford", "runs": 1831, "win_pct": 18.3 }, { "track": "Central Park", "runs": 43, "win_pct": 13.95 }, { "track": "Hove", "runs": 6, "win_pct": 0 } ] # a home-track yard. now you know.
by_trainer is unique to this endpoint and answers something nothing else in the API
can: not how the dogs are running, but which trainers an ownership is getting results from.
For a syndicate paying several sets of training fees, that is the entire question, and it arrives in one request.
# Justin Bowman — real response "overall": { "runs": 97, "wins": 9, "win_pct": 9.28 } "by_trainer": [ { "trainer": "Justin Bowman", "runs": 66, "win_pct": 12.12 }, { "trainer": "Carolyn Jones", "runs": 12, "win_pct": 8.33 }, { "trainer": "Chloe Bowman", "runs": 19, "win_pct": 0 } ] # three yards. one is working.
Twelve things people build with these
Not a feature list — the questions these were built to answer.
/v1/dogs/{dog_id}/stats
A dog with 21% over 462m and 9% over 268m is not an inconsistent dog — it is a dog in the wrong race. by_distance answers that before you look at anything else.
A 22.5% trap-1 record means one thing at Romford and another at Hove. Read by_trap against the track's own draw bias and you can tell the dog from the draw.
One compact object per runner fits in a prompt. Hundreds of raw form lines do not, and a model asked to aggregate them will quietly get it wrong.
runs travels with every percentage, so a 100% strike from one run cannot be presented as a record.
/v1/trainers/{trainer_id}/stats
M E Wiley runs 18.3% at Romford across 1,831 runners and 0% at Hove across 6. track_id answers "are they any good here" in one call.
A rolling window means you are reading this season, not a career average diluted by four years ago. months widens it when you want the long view.
Trainer strike rate at track, at distance and at grade are standard runner-level features. Computing them yourself means holding the whole archive.
An assistant asked "is this trainer in form at Monmore" returns a number instead of an impression.
/v1/owners/{owner_id}/stats
by_trainer is unique to this endpoint. One ownership, three trainers, three strike rates — 12.12%, 8.33% and 0.00%. Nothing else in the API answers that.
Owner-trainer pairings carry signal neither carries alone. Cross-reference with trainer statistics and the partnerships stand out.
With /v1/owners/search, enough for a browsable owner section with real substance rather than a list of runners.
For a syndicate paying several sets of training fees, this is the whole picture in a single request.
Together
Each endpoint answers one question. Combined, they answer the one that matters: is this animal, in this race, in the right place tonight — and are the people behind it any good at this track.
Right trip? Right box? by_distance and by_trap for tonight's
400m from trap 1.
With track_id set to tonight's course. A yard at 28% here is a different runner
from the same yard at 6%.
by_trainer shows whether this owner-trainer pairing is one that works, or one of
three they are trying.
# one runner, three calls, in parallel dog = GET /v1/dogs/654594/stats trainer = GET /v1/trainers/118/stats?track_id=14 owner = GET /v1/owners/2231/stats # what you can now say, with the sample size attached to every claim Trap 1 over 400m: 22.5% from 40 runs — the dog's best box. Trainer at this track: 18.3% from 1,831 runners — home yard. Owner with this trainer: 12.12% from 66 — their strongest pairing. # six runners = 18 calls, well inside 180/min. Do it at declaration time.
Live Plus
Everything on Live, plus the statistics endpoints, more than double the request allowance and a higher rate limit for profiling a full card before the off.
Live is $99/mo and reaches 35 of the 38 endpoints.
Cancel any time from your dashboard. Your existing keys keep working — the three endpoints simply start answering.