Documentation / Races

Race card with form

GET/v1/races/{race_id}/form

Available on Live Plus only

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

The full race card with every runner's recent form attached — the race and its dogs' form lines in a single call instead of one request per runner.

Authenticate with your key in the X-API-Key header, or ?key= if your tool cannot set one — see Authentication. Works with sandbox keys inside the sandbox data window.

Parameters

NameInTypeRequiredDescription
race_id path integer yes The race identifier.
runs query integer no Form lines per runner, most recent first. Default 6, maximum 12.

Request

curl "https://api.greyhoundapi.com/v1/races/3959843903/form" \
  -H "X-API-Key: $GAPI_KEY"
<?php
$ch = curl_init('https://api.greyhoundapi.com/v1/races/3959843903/form');
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/races/3959843903/form', {
  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/races/3959843903/form', {
      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/races/3959843903/form",
    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": {
        "race_id": 1229082445,
        "track": "Romford",
        "grade": "A3",
        "distance_m": 400,
        "scheduled_start": {
            "utc": "2026-07-08T18:46:00Z",
            "local": "2026-07-08T19:46:00+01:00"
        },
        "status": "complete",
        "runners": [
            {
                "trap": 3,
                "dog_id": 1654595188,
                "dog_name": "Miami Yeats",
                "sp": {
                    "fraction": "5/2",
                    "decimal": 3.5
                },
                "position": 1,
                "form": [
                    {
                        "race_id": 1229081992,
                        "date_local": "2026-07-01",
                        "track": "Romford",
                        "grade": "A3",
                        "distance_m": 400,
                        "trap": 2,
                        "position": 2,
                        "sp": {
                            "fraction": "3/1",
                            "decimal": 4
                        },
                        "sectional_s": 3.91,
                        "run_time_s": 24.62,
                        "weight_kg": 31.4
                    },
                    {
                        "race_id": 1229081455,
                        "date_local": "2026-06-24",
                        "track": "Romford",
                        "grade": "A4",
                        "distance_m": 400,
                        "trap": 5,
                        "position": 1,
                        "sp": {
                            "fraction": "2/1",
                            "decimal": 3
                        },
                        "sectional_s": 3.88,
                        "run_time_s": 24.48,
                        "weight_kg": 31.2
                    }
                ]
            }
        ]
    }
}

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/races/{race_id}/form

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.

Notes

Every form line returned happened before this race went off, and the race itself is excluded. That matters for historical races: "recent runs by this dog" would otherwise include what it did afterwards, and anyone testing a method against it would be measuring their own lookahead. The cutoff used is echoed in meta.form_cutoff. A runner with no prior completed runs returns an empty form array — that is a first-timer, not an error. Sectional times are timed to a fixed point on the track, not to a fixed distance from the traps, so they compare only within the same track AND distance: at Towcester a 500m split runs about 4.0s and a 460m split about 1.4s, because the shorter start sits forty metres closer to the marker. Comparing across distances ranks a dog against the layout of the course rather than against itself. Form is drawn from completed races with a recorded finishing position; see Dog form for the same lines per dog, paged.