Dog statistics
/v1/dogs/{dog_id}/statsAvailable on Live Plus only
A Live key reaches the other 35 endpoints and
receives 403 upgrade_required here. Compare plans
Career splits for one greyhound: strike rate by distance, trap, track, grade and going, with best and average winning times in each — what tends to happen, rather than what happened.
Authenticate with your key in the X-API-Key header —
see Authentication. Works with sandbox keys
inside the sandbox data window.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
dog_id |
path | integer | yes | The dog identifier. |
Request
curl "https://api.greyhoundapi.com/v1/dogs/655044/stats" \
-H "X-API-Key: $GAPI_KEY"<?php
$ch = curl_init('https://api.greyhoundapi.com/v1/dogs/655044/stats');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('GAPI_KEY')],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($response['data']);const res = await fetch('https://api.greyhoundapi.com/v1/dogs/655044/stats', {
headers: { 'X-API-Key': process.env.GAPI_KEY }
});
if (!res.ok) throw new Error(`GreyhoundAPI ${res.status}`);
const { meta, data } = await res.json();
console.log(meta.data_as_of, data);import { useEffect, useState } from 'react';
export default function Example() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.greyhoundapi.com/v1/dogs/655044/stats', {
headers: { 'X-API-Key': import.meta.env.VITE_GAPI_KEY }
})
.then((r) => r.json())
.then((body) => setData(body.data));
}, []);
if (!data) return <p>Loading…</p>;
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}Browser code exposes whatever key it ships with — use a sandbox key for prototypes and proxy live keys through your own server in production.
import os
import requests
r = requests.get(
"https://api.greyhoundapi.com/v1/dogs/655044/stats",
headers={"X-API-Key": os.environ["GAPI_KEY"]},
timeout=10,
)
r.raise_for_status()
body = r.json()
print(body["meta"]["data_as_of"], body["data"])Response
{
"meta": {
"request_id": "req_8f2ac1",
"data_as_of": "2026-07-08T13:05:12Z"
},
"data": {
"dog_id": 655044,
"name": "A Bad Winter",
"overall": {
"runs": 59,
"wins": 11,
"places": 33,
"win_pct": 18.64,
"place_pct": 55.93,
"first_run": "2022-03-25",
"last_run": "2024-09-20"
},
"by_distance": [
{
"distance_m": 462,
"runs": 28,
"wins": 6,
"places": 18,
"win_pct": 21.43,
"place_pct": 64.29,
"best_time_s": 28.02,
"avg_time_s": 28.5
},
{
"distance_m": 500,
"runs": 15,
"wins": 4,
"places": 11,
"win_pct": 26.67,
"place_pct": 73.33,
"best_time_s": 29.05,
"avg_time_s": 29.46
}
],
"by_trap": [
{
"trap": 1,
"runs": 40,
"wins": 9,
"places": 23,
"win_pct": 22.5,
"place_pct": 57.5
}
],
"by_track": [
{
"track": "Kinsley",
"runs": 39,
"wins": 7,
"places": 21,
"win_pct": 17.95,
"place_pct": 53.85
}
],
"by_grade": [
{
"grade": "A4",
"runs": 14,
"wins": 3,
"places": 9,
"win_pct": 21.43,
"place_pct": 64.29
}
],
"by_going": [
{
"going": "fast",
"going_values": [
-40,
-20
],
"runs": 4,
"wins": 0,
"places": 3,
"win_pct": 0,
"place_pct": 75
},
{
"going": "standard",
"going_values": [
0
],
"runs": 9,
"wins": 1,
"places": 6,
"win_pct": 11.11,
"place_pct": 66.67
}
]
}
}Run it live
A real request from your browser straight to api.greyhoundapi.com
with your own key — nothing is proxied or logged by this page.
Held in this tab only, sent only to the API host. No key yet? Create a free sandbox key — it runs every endpoint against the sandbox data window.
What this is for
A greyhound's raw form line tells you what happened. It does not tell you what tends to happen — and those are different questions. A dog with four wins from twenty runs looks ordinary until you notice all four came over 400 metres from trap 1, and that it has never won over 500. That pattern is invisible in a results list and obvious in a split.
This endpoint returns the whole career cut five ways: by distance, by trap, by track, by grade and by going. Every split carries runs, wins, places, strike rate and place rate, so a small sample announces itself rather than hiding behind a percentage. Three runs at 33% and thirty runs at 33% are not the same claim, and the runs field is there so your code can tell them apart.
It is built for the moment before a race, when you have six dogs and a card and need to know which of them has actually done this before — this trip, this box, this track.
Common uses
Feeding a model or an AI assistant
Language models reason well over small, clean, pre-aggregated inputs and badly over hundreds of raw form lines. One call returns a compact profile that fits comfortably in a prompt, which is why this is usually a better tool call than /form when the question is comparative rather than historical.
Race previews and tipping content
Pull the six runners in a race, take each dog's by_distance and by_trap rows for the trip being run, and you have the factual spine of a preview without writing an aggregation layer.
Trap and draw research
Combine by_trap here with /v1/tracks/{track_id}/stats to separate a dog's own box preference from the track's draw bias — a fast dog from trap 1 at Romford is partly a fast dog and partly trap 1 at Romford.
Sales, syndication and stud research
Strike rate broken down by grade and distance is the honest version of a sales pitch, and first_run / last_run show whether a record is current or historical.
Notes
best_time_s and avg_time_s appear only in by_distance. A time averaged across mixed trips is meaningless — a 268m sprint and a 500m race do not share a scale — so the fields are omitted elsewhere rather than shipped with a caveat. going is banded (fast, slightly fast, standard, slightly slow, slow) because the raw allowance splits a career into slices too small to read; the underlying values are returned in going_values. Completed runs only — reserves and withdrawals excluded, and a split with no runs is omitted rather than returned as zero.