Documentation / Trainers

Trainer statistics

GET/v1/trainers/{trainer_id}/stats

Available on Live Plus only

A Live key reaches the other 35 endpoints and receives 403 upgrade_required here. Compare plans

Strike rate for one trainer split by track, distance, trap and grade over a rolling window — answering how a yard performs AT A GIVEN TRACK, which a flat results list cannot.

Authenticate with your key in the X-API-Key header — see Authentication. Works with sandbox keys inside the sandbox data window.

Parameters

NameInTypeRequiredDescription
trainer_id path integer yes The trainer identifier. Trainer IDs come from Search trainers.
months query integer no Rolling window in months. Default 12, maximum 60.
track_id query integer no Restrict every split to one track.

Request

curl "https://api.greyhoundapi.com/v1/trainers/118/stats" \
  -H "X-API-Key: $GAPI_KEY"
<?php
$ch = curl_init('https://api.greyhoundapi.com/v1/trainers/118/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/trainers/118/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/trainers/118/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/trainers/118/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

200 OKapplication/json
{
    "meta": {
        "request_id": "req_8f2ac1",
        "data_as_of": "2026-07-08T13:05:12Z"
    },
    "data": {
        "trainer_id": 118,
        "name": "M E Wiley",
        "window_months": 12,
        "track_id": null,
        "overall": {
            "runs": 1887,
            "wins": 342,
            "places": 991,
            "win_pct": 18.12,
            "place_pct": 52.52,
            "first_run": "2025-08-19",
            "last_run": "2026-08-18"
        },
        "by_track": [
            {
                "track": "Romford",
                "runs": 1831,
                "wins": 335,
                "places": 959,
                "win_pct": 18.3,
                "place_pct": 52.38
            },
            {
                "track": "Central Park",
                "runs": 43,
                "wins": 6,
                "places": 26,
                "win_pct": 13.95,
                "place_pct": 60.47
            }
        ],
        "by_distance": [
            {
                "distance_m": 400,
                "runs": 1687,
                "wins": 304,
                "places": 886,
                "win_pct": 18.02,
                "place_pct": 52.52,
                "best_time_s": 23.64,
                "avg_time_s": 24.93
            }
        ],
        "by_going": [
            {
                "going": "standard",
                "going_values": [
                    0
                ],
                "runs": 210,
                "wins": 61,
                "places": 118,
                "win_pct": 29.05,
                "place_pct": 56.19
            }
        ],
        "by_trap": [
            {
                "trap": 1,
                "runs": 370,
                "wins": 89,
                "places": 219,
                "win_pct": 24.05,
                "place_pct": 59.19
            }
        ],
        "by_grade": [
            {
                "grade": "A12",
                "runs": 313,
                "wins": 49,
                "places": 157,
                "win_pct": 15.65,
                "place_pct": 50.16
            }
        ]
    }
}

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.

GET/v1/trainers/{trainer_id}/stats

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

Every trainer has tracks they do well at and tracks they turn up to. A yard running 18% overall might be 28% at its home course and 6% everywhere else, and that difference is the single most useful thing you can know about a runner away from home.

This endpoint answers that directly. It splits a trainer's record by track, distance, trap, grade and going over a rolling window, and accepts track_id to narrow every split to one course. Previously the same question meant paging through /v1/trainers/{trainer_id}/results and counting by hand.

The window is bounded deliberately. A busy yard has thousands of runners a year, and trainer form is not a permanent property — a strike rate from four years ago describes a different operation. Twelve months is the default; months widens it to sixty when you want a longer view.

Common uses

Away-day form

Call with track_id set to the course being run to see whether a yard actually travels. It is the fastest way to separate a genuine contender from a runner having a night out.

Tool calls for AI race analysis

An assistant asked "is this trainer in form at Monmore" can answer it in one call with grounded numbers instead of guessing. Small, aggregated and unambiguous is exactly the shape that keeps a model honest.

Model features

Trainer strike rate at track, at distance and at grade are standard features in a runner-level model, and computing them client-side means holding the whole results archive. Here they arrive ready.

Editorial and stable tours

The by_grade and by_distance splits describe what a yard specialises in, which is the substance behind most trainer profiles.

Notes

The window is bounded on purpose: a busy yard has thousands of runners and an unbounded scan would be slow for every caller. Widen it with months, up to 60. As with dog statistics, times appear only in by_distance.