# greyhound racing api complete reference

Greyhound racing results, racecards and tracks for the UK, Ireland and Australia.

- Base URL: `https://api.greyhoundracingapi.com/v1`
- Authentication: `Authorization: Bearer <key>` or `X-API-Key: <key>`; never in the URL
- Site: https://greyhoundracingapi.com
- Endpoints: 7
- Generated: 2026-10-06
- This file: https://greyhoundracingapi.com/documentation/manual.md

## Before anything else

- Factual data only: no predictions, ratings, tips or betting advice on any endpoint.
- Not included on any plan: odds or price feeds beyond the starting price, live streaming, sectional times, countries other than GB, IE and AU.
- Every answer is `{"data": ..., "meta": {...}}`. `meta` carries `count`, `page`, `total_pages`, `next_cursor` and `took_ms`.
- OpenAPI: https://greyhoundracingapi.com/openapi.json
- MCP server: https://greyhoundracingapi.com/mcp (tools listed under MCP tools below)

## Plans

| Plan | Price | Reads | Per minute | Per day |
|---|---|---|---|---|
| Free key | free | Yesterday's results | 30 | 75 |
| Race Pass | $29 a month | Today's racecards and results as each race settles | 120 | 20,000 |
| Archive Pass | $79 a month | Live plus every date from 2020 | 240 | 50,000 |

## Endpoints

[Documentation](https://greyhoundracingapi.com/documentation) / Results

### Yesterday's results

Free keyRace PassArchive PassMCP tool `yesterdays_results`

Yesterday's results, every meeting. Covers the UK, Ireland and Australia.

`GEThttps://api.greyhoundracingapi.com/v1/results/yesterday`

#### Parameters

| Name | Type |  | What it does |
|---|---|---|---|
| `country` | string |  | Leave out for all three countries.GBIEAU |
| `track` | string |  | A track id from [Tracks](https://greyhoundracingapi.com/documentation/tracks), such as `romford`. |
| `page` | integer |  | Page number, from 1. 50 races a page. |
| `cursor` | string |  | The `meta.next_cursor` from your last call, for the next page. |
| `format` | string |  | The answer format. Adding `.csv` to the path does the same as `csv`.jsoncsv |

#### Returns

A list of races in `data` and paging in `meta`: `count`, `page`, `per_page`, `total`, `total_pages` and `next_cursor`. A field we do not have for a race is `null`, never left out. See [Pagination](https://greyhoundracingapi.com/documentation/pagination).

| Field | Type | What it holds |
|---|---|---|
| `race_id` | string | Our id for the race. Stable, safe to store. |
| `track` | string | Track id, as in [Tracks](https://greyhoundracingapi.com/documentation/tracks). |
| `track_name` | string | Track name for display. |
| `country` | string | `GB`, `IE` or `AU`. |
| `no` | integer | Race number at the meeting. |
| `off` | time | Scheduled start, local to the track, `HH:MM`. |
| `off_utc` | datetime | Scheduled start in UTC. |
| `distance_m` | integer | Distance in metres. |
| `grade` | string | Race grade, where one is given. |
| `settled_at` | datetime | When the result arrived, UTC. Use it with `since`. |
| `result_status` | string | `provisional` until confirmed, then `final`. |
| `result[].pos` | integer | Finishing position. |
| `result[].trap` | integer | Trap, 1 to 6 (1 to 8 in Australia). |
| `result[].runner` | string | Greyhound name. |
| `result[].runner_id` | string | Our id for the greyhound. Stable, safe to store. |
| `result[].trainer` | string | Trainer name. |
| `result[].time` | number | Run time in seconds. |
| `result[].sp` | string | Starting price as given: fractional where there is one. |
| `result[].sp_decimal` | number | Starting price in decimal odds. |

#### Example answer

A real answer from 6 October 2026, 13:50 UTC, trimmed to one race and three runners.

```
{
    "data": [
        {
            "race_id": "rc_y7t67w4m",
            "track": "enniscorthy",
            "track_name": "Enniscorthy",
            "country": "IE",
            "no": 8,
            "off": "21:39",
            "off_utc": "2026-10-05T20:39:00Z",
            "distance_m": 480,
            "grade": "A2",
            "settled_at": "2026-10-05T21:05:00Z",
            "result_status": "final",
            "result": [
                {
                    "pos": 1,
                    "trap": 3,
                    "runner": "Ballinabola Wild",
                    "runner_id": "rn_y5ychzap",
                    "trainer": "Liam Butler (snr.)",
                    "time": 29.07,
                    "sp": "4",
                    "sp_decimal": 4
                },
                {
                    "pos": 2,
                    "trap": 2,
                    "runner": "Blackhill Jack",
                    "runner_id": "rn_wfh24r03",
                    "trainer": "Anton Butler",
                    "time": 29.24,
                    "sp": "3",
                    "sp_decimal": 3
                },
                {
                    "pos": 3,
                    "trap": 1,
                    "runner": "Karlow Blaze",
                    "runner_id": "rn_k0zm6ba6",
                    "trainer": "J-m-h-syndicate",
                    "time": 29.45,
                    "sp": "3.5",
                    "sp_decimal": 3.5
                }
            ]
        }
    ],
    "meta": {
        "count": 50,
        "page": 1,
        "per_page": 50,
        "total": 202,
        "total_pages": 5,
        "next_cursor": "cDI",
        "took_ms": 156
    }
}
```

#### Errors

| Status | Code | What to do |
|---|---|---|
| 400 | [bad_request](https://greyhoundracingapi.com/documentation/errors) | A value is not valid, a date is before 2020, or the key was put in the address. The message says which. |
| 401 | [unauthorized](https://greyhoundracingapi.com/documentation/errors) | No key, or the key is wrong, revoked or expired. Check the header. |
| 422 | [unknown_parameter](https://greyhoundracingapi.com/documentation/errors) | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | [rate_limited](https://greyhoundracingapi.com/documentation/errors) | Too many calls this minute. Wait for `Retry-After`. |
| 429 | [quota_exceeded](https://greyhoundracingapi.com/documentation/errors) | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | [server_error](https://greyhoundracingapi.com/documentation/errors) | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

Docs page: https://greyhoundracingapi.com/documentation/results-yesterday

[Documentation](https://greyhoundracingapi.com/documentation) / Results

### Today's results

Race PassArchive PassMCP tool `todays_results`

Today's results as each race settles. Covers the UK, Ireland and Australia.

`GEThttps://api.greyhoundracingapi.com/v1/results/today`

#### Parameters

| Name | Type |  | What it does |
|---|---|---|---|
| `country` | string |  | Leave out for all three countries.GBIEAU |
| `track` | string |  | A track id from [Tracks](https://greyhoundracingapi.com/documentation/tracks), such as `romford`. |
| `race` | integer |  | One race number at that track. |
| `since` | time |  | Only races settled after this time, UTC `HH:MM`. For polling. |
| `page` | integer |  | Page number, from 1. 50 races a page. |
| `cursor` | string |  | The `meta.next_cursor` from your last call, for the next page. |
| `format` | string |  | The answer format. Adding `.csv` to the path does the same as `csv`.jsoncsv |

#### Returns

A list of races in `data` and paging in `meta`: `count`, `page`, `per_page`, `total`, `total_pages` and `next_cursor`. A field we do not have for a race is `null`, never left out. See [Pagination](https://greyhoundracingapi.com/documentation/pagination).

| Field | Type | What it holds |
|---|---|---|
| `race_id` | string | Our id for the race. Stable, safe to store. |
| `track` | string | Track id, as in [Tracks](https://greyhoundracingapi.com/documentation/tracks). |
| `track_name` | string | Track name for display. |
| `country` | string | `GB`, `IE` or `AU`. |
| `no` | integer | Race number at the meeting. |
| `off` | time | Scheduled start, local to the track, `HH:MM`. |
| `off_utc` | datetime | Scheduled start in UTC. |
| `distance_m` | integer | Distance in metres. |
| `grade` | string | Race grade, where one is given. |
| `settled_at` | datetime | When the result arrived, UTC. Use it with `since`. |
| `result_status` | string | `provisional` until confirmed, then `final`. |
| `result[].pos` | integer | Finishing position. |
| `result[].trap` | integer | Trap, 1 to 6 (1 to 8 in Australia). |
| `result[].runner` | string | Greyhound name. |
| `result[].runner_id` | string | Our id for the greyhound. Stable, safe to store. |
| `result[].trainer` | string | Trainer name. |
| `result[].time` | number | Run time in seconds. |
| `result[].sp` | string | Starting price as given: fractional where there is one. |
| `result[].sp_decimal` | number | Starting price in decimal odds. |

#### Example answer

A real answer from 6 October 2026, 13:50 UTC, trimmed to one race and three runners.

```
{
    "data": [
        {
            "race_id": "rc_yjd8gbvy",
            "track": "valley",
            "track_name": "Valley",
            "country": "GB",
            "no": 3,
            "off": "14:26",
            "off_utc": "2026-10-06T13:26:00Z",
            "distance_m": 260,
            "grade": "D5",
            "settled_at": "2026-10-06T13:45:00Z",
            "result_status": "final",
            "result": [
                {
                    "pos": 1,
                    "trap": 3,
                    "runner": "Playdate Jasper",
                    "runner_id": "rn_3ebsczaq",
                    "trainer": "A N J Morgan",
                    "time": 16.8,
                    "sp": "7/1",
                    "sp_decimal": 8
                },
                {
                    "pos": 2,
                    "trap": 5,
                    "runner": "Dunbolg Ivy",
                    "runner_id": "rn_2t9bg253",
                    "trainer": "J A Danahar",
                    "time": 17.04,
                    "sp": "5/6",
                    "sp_decimal": 1.83
                },
                {
                    "pos": 3,
                    "trap": 2,
                    "runner": "Hawkfield Nina",
                    "runner_id": "rn_gq5srdbc",
                    "trainer": "D S Davy",
                    "time": 17.18,
                    "sp": "6/1",
                    "sp_decimal": 7
                }
            ]
        }
    ],
    "meta": {
        "count": 40,
        "page": 1,
        "per_page": 50,
        "total": 40,
        "total_pages": 1,
        "next_cursor": null,
        "took_ms": 49
    }
}
```

#### Errors

| Status | Code | What to do |
|---|---|---|
| 400 | [bad_request](https://greyhoundracingapi.com/documentation/errors) | A value is not valid, a date is before 2020, or the key was put in the address. The message says which. |
| 401 | [unauthorized](https://greyhoundracingapi.com/documentation/errors) | No key, or the key is wrong, revoked or expired. Check the header. |
| 403 | [upgrade_required](https://greyhoundracingapi.com/documentation/errors) | Your plan does not include this endpoint. `plan` names the one that does. |
| 422 | [unknown_parameter](https://greyhoundracingapi.com/documentation/errors) | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | [rate_limited](https://greyhoundracingapi.com/documentation/errors) | Too many calls this minute. Wait for `Retry-After`. |
| 429 | [quota_exceeded](https://greyhoundracingapi.com/documentation/errors) | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | [server_error](https://greyhoundracingapi.com/documentation/errors) | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

#### Polling for new results

Call every minute or two with `since` set to the newest `settled_at` you hold. You only get races settled after it, so each call is small.

Docs page: https://greyhoundracingapi.com/documentation/results-today

[Documentation](https://greyhoundracingapi.com/documentation) / Results

### Results by date

Archive PassMCP tool `search_results`

Results on any date from 2020 on. Covers the UK, Ireland and Australia.

`GEThttps://api.greyhoundracingapi.com/v1/results`

#### Parameters

| Name | Type |  | What it does |
|---|---|---|---|
| `date` | date | required | The day you want, `YYYY-MM-DD`, from `2020-01-01` on. |
| `country` | string |  | Leave out for all three countries.GBIEAU |
| `track` | string |  | A track id from [Tracks](https://greyhoundracingapi.com/documentation/tracks), such as `romford`. |
| `page` | integer |  | Page number, from 1. 50 races a page. |
| `cursor` | string |  | The `meta.next_cursor` from your last call, for the next page. |
| `format` | string |  | The answer format. Adding `.csv` to the path does the same as `csv`.jsoncsv |

#### Returns

A list of races in `data` and paging in `meta`: `count`, `page`, `per_page`, `total`, `total_pages` and `next_cursor`. A field we do not have for a race is `null`, never left out. See [Pagination](https://greyhoundracingapi.com/documentation/pagination).

| Field | Type | What it holds |
|---|---|---|
| `race_id` | string | Our id for the race. Stable, safe to store. |
| `track` | string | Track id, as in [Tracks](https://greyhoundracingapi.com/documentation/tracks). |
| `track_name` | string | Track name for display. |
| `country` | string | `GB`, `IE` or `AU`. |
| `no` | integer | Race number at the meeting. |
| `off` | time | Scheduled start, local to the track, `HH:MM`. |
| `off_utc` | datetime | Scheduled start in UTC. |
| `distance_m` | integer | Distance in metres. |
| `grade` | string | Race grade, where one is given. |
| `settled_at` | datetime | When the result arrived, UTC. Use it with `since`. |
| `result_status` | string | `provisional` until confirmed, then `final`. |
| `result[].pos` | integer | Finishing position. |
| `result[].trap` | integer | Trap, 1 to 6 (1 to 8 in Australia). |
| `result[].runner` | string | Greyhound name. |
| `result[].runner_id` | string | Our id for the greyhound. Stable, safe to store. |
| `result[].trainer` | string | Trainer name. |
| `result[].time` | number | Run time in seconds. |
| `result[].sp` | string | Starting price as given: fractional where there is one. |
| `result[].sp_decimal` | number | Starting price in decimal odds. |

#### Example answer

A real answer from 6 October 2026, 13:50 UTC, trimmed to one race and three runners.

```
{
    "data": [
        {
            "race_id": "rc_93w8ebbh",
            "track": "nottingham",
            "track_name": "Nottingham",
            "country": "GB",
            "no": 12,
            "off": "21:46",
            "off_utc": "2026-10-05T20:46:00Z",
            "distance_m": 500,
            "grade": "A3",
            "settled_at": "2026-10-05T20:50:01Z",
            "result_status": "final",
            "result": [
                {
                    "pos": 1,
                    "trap": 4,
                    "runner": "Bluejig Polly",
                    "runner_id": "rn_rz5pvd9h",
                    "trainer": "J Gray",
                    "time": 29.97,
                    "sp": "5/2",
                    "sp_decimal": 3.5
                },
                {
                    "pos": 2,
                    "trap": 1,
                    "runner": "Twilight Brook",
                    "runner_id": "rn_e4a6b61k",
                    "trainer": "P M Holland",
                    "time": 30.07,
                    "sp": "11/4",
                    "sp_decimal": 3.75
                },
                {
                    "pos": 3,
                    "trap": 3,
                    "runner": "Skeard Noah",
                    "runner_id": "rn_9syqf0e4",
                    "trainer": "B Denby",
                    "time": 30.31,
                    "sp": "5/2",
                    "sp_decimal": 3.5
                }
            ]
        }
    ],
    "meta": {
        "count": 50,
        "page": 1,
        "per_page": 50,
        "total": 354798,
        "total_pages": 7096,
        "next_cursor": "cDI",
        "took_ms": 90
    }
}
```

#### Errors

| Status | Code | What to do |
|---|---|---|
| 400 | [bad_request](https://greyhoundracingapi.com/documentation/errors) | A value is not valid, a date is before 2020, or the key was put in the address. The message says which. |
| 401 | [unauthorized](https://greyhoundracingapi.com/documentation/errors) | No key, or the key is wrong, revoked or expired. Check the header. |
| 403 | [upgrade_required](https://greyhoundracingapi.com/documentation/errors) | Your plan does not include this endpoint. `plan` names the one that does. |
| 422 | [unknown_parameter](https://greyhoundracingapi.com/documentation/errors) | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | [rate_limited](https://greyhoundracingapi.com/documentation/errors) | Too many calls this minute. Wait for `Retry-After`. |
| 429 | [quota_exceeded](https://greyhoundracingapi.com/documentation/errors) | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | [server_error](https://greyhoundracingapi.com/documentation/errors) | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

Docs page: https://greyhoundracingapi.com/documentation/results-search

[Documentation](https://greyhoundracingapi.com/documentation) / Racecards

### Today's racecards

Race PassArchive PassMCP tool `todays_racecards`

Today's racecards for every meeting. Covers the UK, Ireland and Australia.

`GEThttps://api.greyhoundracingapi.com/v1/racecards/today`

#### Parameters

| Name | Type |  | What it does |
|---|---|---|---|
| `country` | string |  | Leave out for all three countries.GBIEAU |
| `track` | string |  | A track id from [Tracks](https://greyhoundracingapi.com/documentation/tracks), such as `romford`. |
| `page` | integer |  | Page number, from 1. 50 races a page. |
| `cursor` | string |  | The `meta.next_cursor` from your last call, for the next page. |
| `format` | string |  | The answer format. Adding `.csv` to the path does the same as `csv`.jsoncsv |

#### Returns

A list of races in `data` and paging in `meta`: `count`, `page`, `per_page`, `total`, `total_pages` and `next_cursor`. A field we do not have for a race is `null`, never left out. See [Pagination](https://greyhoundracingapi.com/documentation/pagination).

| Field | Type | What it holds |
|---|---|---|
| `race_id` | string | Our id for the race. Stable, safe to store. |
| `track` | string | Track id, as in [Tracks](https://greyhoundracingapi.com/documentation/tracks). |
| `track_name` | string | Track name for display. |
| `country` | string | `GB`, `IE` or `AU`. |
| `no` | integer | Race number at the meeting. |
| `off` | time | Scheduled start, local to the track, `HH:MM`. |
| `off_utc` | datetime | Scheduled start in UTC. |
| `distance_m` | integer | Distance in metres. |
| `grade` | string | Race grade, where one is given. |
| `runners[].trap` | integer | Trap, 1 to 6 (1 to 8 in Australia). |
| `runners[].runner` | string | Greyhound name. |
| `runners[].runner_id` | string | Our id for the greyhound. Stable, safe to store. |
| `runners[].trainer` | string | Trainer name. |

#### Example answer

A real answer from 6 October 2026, 13:50 UTC, trimmed to one race and three runners.

```
{
    "data": [
        {
            "race_id": "rc_945kmh69",
            "track": "sheffield",
            "track_name": "Sheffield",
            "country": "GB",
            "no": 1,
            "off": "11:01",
            "off_utc": "2026-10-06T10:01:00Z",
            "distance_m": 500,
            "grade": "A4",
            "runners": [
                {
                    "pos": 2,
                    "trap": 1,
                    "runner": "Trickysteddybear",
                    "runner_id": "rn_jhsqwe1z",
                    "trainer": "R Holt",
                    "time": null,
                    "sp": "6/4",
                    "sp_decimal": 2.5
                },
                {
                    "pos": 3,
                    "trap": 2,
                    "runner": "Gurtnacrehy Rhys",
                    "runner_id": "rn_5g4y8zxv",
                    "trainer": "P Webster",
                    "time": null,
                    "sp": "11/4",
                    "sp_decimal": 3.75
                },
                {
                    "pos": 1,
                    "trap": 3,
                    "runner": "Listen Jessie",
                    "runner_id": "rn_xgfvd5nx",
                    "trainer": "K Hodson",
                    "time": null,
                    "sp": "7/1",
                    "sp_decimal": 8
                }
            ]
        }
    ],
    "meta": {
        "count": 50,
        "page": 1,
        "per_page": 50,
        "total": 177,
        "total_pages": 4,
        "next_cursor": "cDI",
        "took_ms": 100
    }
}
```

#### Errors

| Status | Code | What to do |
|---|---|---|
| 400 | [bad_request](https://greyhoundracingapi.com/documentation/errors) | A value is not valid, a date is before 2020, or the key was put in the address. The message says which. |
| 401 | [unauthorized](https://greyhoundracingapi.com/documentation/errors) | No key, or the key is wrong, revoked or expired. Check the header. |
| 403 | [upgrade_required](https://greyhoundracingapi.com/documentation/errors) | Your plan does not include this endpoint. `plan` names the one that does. |
| 422 | [unknown_parameter](https://greyhoundracingapi.com/documentation/errors) | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | [rate_limited](https://greyhoundracingapi.com/documentation/errors) | Too many calls this minute. Wait for `Retry-After`. |
| 429 | [quota_exceeded](https://greyhoundracingapi.com/documentation/errors) | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | [server_error](https://greyhoundracingapi.com/documentation/errors) | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

Docs page: https://greyhoundracingapi.com/documentation/racecards-today

[Documentation](https://greyhoundracingapi.com/documentation) / Racecards

### Upcoming races

Race PassArchive PassMCP tool `upcoming_races`

The next races coming up. Covers the UK, Ireland and Australia.

`GEThttps://api.greyhoundracingapi.com/v1/racecards/upcoming`

#### Parameters

| Name | Type |  | What it does |
|---|---|---|---|
| `country` | string |  | Leave out for all three countries.GBIEAU |
| `page` | integer |  | Page number, from 1. 50 races a page. |
| `cursor` | string |  | The `meta.next_cursor` from your last call, for the next page. |
| `format` | string |  | The answer format. Adding `.csv` to the path does the same as `csv`.jsoncsv |

#### Returns

A list of races in `data` and paging in `meta`: `count`, `page`, `per_page`, `total`, `total_pages` and `next_cursor`. A field we do not have for a race is `null`, never left out. See [Pagination](https://greyhoundracingapi.com/documentation/pagination).

| Field | Type | What it holds |
|---|---|---|
| `race_id` | string | Our id for the race. Stable, safe to store. |
| `track` | string | Track id, as in [Tracks](https://greyhoundracingapi.com/documentation/tracks). |
| `track_name` | string | Track name for display. |
| `country` | string | `GB`, `IE` or `AU`. |
| `no` | integer | Race number at the meeting. |
| `off` | time | Scheduled start, local to the track, `HH:MM`. |
| `off_utc` | datetime | Scheduled start in UTC. |
| `distance_m` | integer | Distance in metres. |
| `grade` | string | Race grade, where one is given. |
| `runners[].trap` | integer | Trap, 1 to 6 (1 to 8 in Australia). |
| `runners[].runner` | string | Greyhound name. |
| `runners[].runner_id` | string | Our id for the greyhound. Stable, safe to store. |
| `runners[].trainer` | string | Trainer name. |

#### Example answer

A real answer from 6 October 2026, 13:50 UTC, trimmed to one race and three runners.

```
{
    "data": [
        {
            "race_id": "rc_a65k137n",
            "track": "thurles-park",
            "track_name": "Thurles Park",
            "country": "IE",
            "no": 2,
            "off": "14:52",
            "off_utc": "2026-10-06T13:52:00Z",
            "distance_m": 480,
            "grade": "A5",
            "runners": [
                {
                    "pos": null,
                    "trap": 1,
                    "runner": "Monadreenspecial",
                    "runner_id": "rn_x5q83ps9",
                    "trainer": "Mr. Christy Fitzpatrick",
                    "time": null,
                    "sp": null,
                    "sp_decimal": null
                },
                {
                    "pos": null,
                    "trap": 2,
                    "runner": "Dafairatshinrone",
                    "runner_id": "rn_0athewvy",
                    "trainer": "Fairytale-of-newyork-syndicate",
                    "time": null,
                    "sp": null,
                    "sp_decimal": null
                },
                {
                    "pos": null,
                    "trap": 3,
                    "runner": "Cabra Iris",
                    "runner_id": "rn_7p0bmt1v",
                    "trainer": "Mr. Paddy Scally",
                    "time": null,
                    "sp": null,
                    "sp_decimal": null
                }
            ]
        }
    ],
    "meta": {
        "count": 50,
        "page": 1,
        "per_page": 50,
        "total": 86,
        "total_pages": 2,
        "next_cursor": "cDI",
        "took_ms": 77
    }
}
```

#### Errors

| Status | Code | What to do |
|---|---|---|
| 400 | [bad_request](https://greyhoundracingapi.com/documentation/errors) | A value is not valid, a date is before 2020, or the key was put in the address. The message says which. |
| 401 | [unauthorized](https://greyhoundracingapi.com/documentation/errors) | No key, or the key is wrong, revoked or expired. Check the header. |
| 403 | [upgrade_required](https://greyhoundracingapi.com/documentation/errors) | Your plan does not include this endpoint. `plan` names the one that does. |
| 422 | [unknown_parameter](https://greyhoundracingapi.com/documentation/errors) | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | [rate_limited](https://greyhoundracingapi.com/documentation/errors) | Too many calls this minute. Wait for `Retry-After`. |
| 429 | [quota_exceeded](https://greyhoundracingapi.com/documentation/errors) | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | [server_error](https://greyhoundracingapi.com/documentation/errors) | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

Docs page: https://greyhoundracingapi.com/documentation/racecards-upcoming

[Documentation](https://greyhoundracingapi.com/documentation) / Reference

### Tracks

Free keyRace PassArchive PassMCP tool `list_tracks`

Every track covered, with distances. Covers the UK, Ireland and Australia.

`GEThttps://api.greyhoundracingapi.com/v1/tracks`

#### Parameters

| Name | Type |  | What it does |
|---|---|---|---|
| `country` | string |  | Leave out for all three countries.GBIEAU |

#### Returns

| Field | Type | What it holds |
|---|---|---|
| `track` | string | Track id. Use it in the `track` parameter. |
| `name` | string | Track name for display. |
| `country` | string | `GB`, `IE` or `AU`. |
| `distances_m` | array | Race distances run there, in metres. |

#### Example answer

A real answer from 6 October 2026, 13:50 UTC, trimmed to one race and three runners.

```
{
    "data": [
        {
            "track": "central-park",
            "name": "Central Park",
            "country": "GB",
            "distances_m": [
                265,
                277,
                450,
                480,
                491,
                500,
                642,
                644,
                664,
                708,
                731,
                946
            ]
        },
        {
            "track": "doncaster",
            "name": "Doncaster",
            "country": "GB",
            "distances_m": [
                275,
                450,
                483,
                661,
                890
            ]
        },
        {
            "track": "dunstall-park",
            "name": "Dunstall Park",
            "country": "GB",
            "distances_m": [
                270,
                275,
                480,
                660,
                710,
                715,
                915,
                925
            ]
        }
    ],
    "meta": {
        "count": 16,
        "took_ms": 90
    }
}
```

#### Errors

| Status | Code | What to do |
|---|---|---|
| 400 | [bad_request](https://greyhoundracingapi.com/documentation/errors) | A value is not valid, a date is before 2020, or the key was put in the address. The message says which. |
| 401 | [unauthorized](https://greyhoundracingapi.com/documentation/errors) | No key, or the key is wrong, revoked or expired. Check the header. |
| 422 | [unknown_parameter](https://greyhoundracingapi.com/documentation/errors) | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | [rate_limited](https://greyhoundracingapi.com/documentation/errors) | Too many calls this minute. Wait for `Retry-After`. |
| 429 | [quota_exceeded](https://greyhoundracingapi.com/documentation/errors) | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | [server_error](https://greyhoundracingapi.com/documentation/errors) | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

Docs page: https://greyhoundracingapi.com/documentation/tracks

[Documentation](https://greyhoundracingapi.com/documentation) / Reference

### Your usage

Free keyRace PassArchive PassMCP tool `my_usage`

Your plan, calls today and limits. Free to call. Covers the UK, Ireland and Australia.

`GEThttps://api.greyhoundracingapi.com/v1/usage`

#### Parameters

None.

#### Returns

| Field | Type | What it holds |
|---|---|---|
| `plan` | string | Your plan. |
| `key` | string | The start of the key you called with. |
| `calls_today` | integer | Calls today across all your keys, UTC. |
| `calls_this_month` | integer | Calls this calendar month. |
| `per_day` | integer | Your daily allowance. |
| `per_minute` | integer | Calls allowed per minute. |
| `resets_at` | datetime | When the daily count resets, UTC. |
| `window` | string | `yesterday`, `live` or `archive`. |
| `countries` | array | Countries your plan covers. |

#### Example answer

A real answer from 6 October 2026, 13:50 UTC.

```
{
    "data": {
        "plan": "Archive Pass",
        "key": "gra_live_xxxx",
        "calls_today": 79,
        "calls_this_month": 79,
        "per_day": 50000,
        "per_minute": 240,
        "resets_at": "2026-10-07T00:00:00Z",
        "window": "archive",
        "countries": [
            "GB",
            "IE",
            "AU"
        ]
    },
    "meta": {
        "count": 1,
        "took_ms": 9
    }
}
```

#### Errors

| Status | Code | What to do |
|---|---|---|
| 401 | [unauthorized](https://greyhoundracingapi.com/documentation/errors) | No key, or the key is wrong, revoked or expired. Check the header. |
| 422 | [unknown_parameter](https://greyhoundracingapi.com/documentation/errors) | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | [rate_limited](https://greyhoundracingapi.com/documentation/errors) | Too many calls this minute. Wait for `Retry-After`. |
| 429 | [quota_exceeded](https://greyhoundracingapi.com/documentation/errors) | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | [server_error](https://greyhoundracingapi.com/documentation/errors) | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

Docs page: https://greyhoundracingapi.com/documentation/usage

## Guides

*Greyhound racing results, racecards and tracks for the UK, Ireland and Australia: every endpoint, a live call with your key, and everything for assistants and agents.* (https://greyhoundracingapi.com/documentation)

### The greyhound racing API

Results, racecards and tracks for every greyhound meeting in the UK, Ireland and Australia, as JSON or CSV over a simple REST API.

Every race carries its track, grade, distance and off time in local time and UTC. Results add the finishing order, trap, greyhound, trainer, run time and the starting price as a fraction and a decimal. Today's results arrive as each race settles, the racecards list every runner before the off, and the archive goes back to 1 January 2020.

People use it for results pages and apps, for form and trainer databases, for spreadsheets that fill themselves, and for assistants that answer racing questions from real data. It holds facts only: no tips, ratings or predictions.

#### Start here

1Get a key

Sign in with Google and your free key is made at once. It reads yesterday's results, 75 calls a day.

Get a free key

2Make the first call

Send the key in the `X-API-Key` header. Run it right here, or copy the curl line from Quick start.

Quick start

3Read the answer

Every answer is `data` plus `meta`, with paging, counts and the time taken. Add `format=csv` for a sheet.

Results guide

#### Every subject

Results

Finishing order, traps, greyhounds, trainers, run times and starting prices, for yesterday, today as races settle, or any date since 2020.

- [/v1/results/yesterday](https://greyhoundracingapi.com/documentation/results-yesterday)
- [/v1/results/today](https://greyhoundracingapi.com/documentation/results-today)
- [/v1/results](https://greyhoundracingapi.com/documentation/results-search)

Read the guide

Racecards

Every race on today's card with its runners, traps and trainers, and the next races about to go, to show before the off.

- [/v1/racecards/today](https://greyhoundracingapi.com/documentation/racecards-today)
- [/v1/racecards/upcoming](https://greyhoundracingapi.com/documentation/racecards-upcoming)

Read the guide

Tracks

Every track covered, its id, country and the distances raced there. The track id is what the other endpoints take.

- [/v1/tracks](https://greyhoundracingapi.com/documentation/tracks)

Read the guide

Paging and polling

Lists come 50 races a page. Follow `next_cursor`, or poll today's results with `since` to get only new races.

- `page`and`cursor`
- `since=HH:MM`

Read the guide

#### Every endpoint

Results

Finished races with full placings.

- [/v1/results/yesterday](https://greyhoundracingapi.com/documentation/results-yesterday)Yesterday's results, every meeting.
- [/v1/results/today](https://greyhoundracingapi.com/documentation/results-today)Today's results as each race settles.
- [/v1/results](https://greyhoundracingapi.com/documentation/results-search)Results on any date from 2020 on.

Racecards

Races still to run, with every runner.

- [/v1/racecards/today](https://greyhoundracingapi.com/documentation/racecards-today)Today's racecards for every meeting.
- [/v1/racecards/upcoming](https://greyhoundracingapi.com/documentation/racecards-upcoming)The next races coming up.

Reference

Lookups and your own account.

- [/v1/tracks](https://greyhoundracingapi.com/documentation/tracks)Every track covered, with distances.
- [/v1/usage](https://greyhoundracingapi.com/documentation/usage)Your plan, calls today and limits. Free to call.

Free keyRace PassArchive Pass

#### Popular calls

[Yesterday in BritainGET /v1/results/yesterday?country=GB](https://greyhoundracingapi.com/documentation/results-yesterday)[Tonight at RomfordGET /v1/racecards/today?track=romford](https://greyhoundracingapi.com/documentation/racecards-today)[New results since 19:30GET /v1/results/today?since=19:30](https://greyhoundracingapi.com/documentation/results-today)[Every Australian trackGET /v1/tracks?country=AU](https://greyhoundracingapi.com/documentation/tracks)[The next racesGET /v1/racecards/upcoming?country=GB](https://greyhoundracingapi.com/documentation/racecards-upcoming)

#### For assistants and agents

MCP server

Add it to Claude, ChatGPT or Cursor and ask racing questions in plain words. Sign in once; it uses your plan.

`https://greyhoundracingapi.com/mcp`[MCP guide and tools](https://greyhoundracingapi.com/documentation/mcp)

Agent skill

A short file that teaches an agent how to call the API well. Add it once to your agent's skills.

`https://greyhoundracingapi.com/skill.md`[About the skill](https://greyhoundracingapi.com/documentation/agent-skill)

The manual

The whole API in one markdown file: every endpoint, field and guide. Hand it to a model as context.

`https://greyhoundracingapi.com/documentation/manual.md`[Open the manual](https://greyhoundracingapi.com/documentation/manual.md)

llms.txt and OpenAPI

The short map for crawlers, and the OpenAPI file for code generators and API tools.

`https://greyhoundracingapi.com/llms.txt`[openapi.json](https://greyhoundracingapi.com/openapi.json)

#### Plans in short

Free key$0

Yesterday's results and tracks. 75 calls a day, 30 a minute.

[See pricing](https://greyhoundracingapi.com/pricing/)

Race Pass$29 a month

Today's racecards and results as each race settles. 20,000 calls a day, 120 a minute.

[See pricing](https://greyhoundracingapi.com/pricing/)

Archive Pass$79 a month

Everything live plus every date since 2020. 50,000 calls a day, 240 a minute.

[See pricing](https://greyhoundracingapi.com/pricing/)

#### What is new

- 6 Oct 2026The documentation moves to `/documentation`, with Try it on every endpoint, an MCP tools page and `/openapi.json`. [Changelog](https://greyhoundracingapi.com/documentation/changelog)
- 5 Oct 2026Results carry `settled_at` and `result_status`. Every list pages by `page` or `cursor`, 50 races a page. [Changelog](https://greyhoundracingapi.com/documentation/changelog)
- 1 Oct 2026Version 1: results (yesterday, today, by date from 2020), racecards (today, upcoming), tracks and usage, for the UK, Ireland and Australia, as JSON and CSV. MCP server for Race Pass and Archive Pass. [Changelog](https://greyhoundracingapi.com/documentation/changelog)

#### The rest

Authentication

Your key goes in `X-API-Key` or `Authorization: Bearer`, never in the address.

[Authentication](https://greyhoundracingapi.com/documentation/authentication)

Errors

Every code, what it means and what to do, from `401` to `quota_exceeded`.

[Errors](https://greyhoundracingapi.com/documentation/errors)

Rate limits

Per minute and per day by plan, with the headers that tell you where you stand.

[Rate limits](https://greyhoundracingapi.com/documentation/plans-and-limits)

Pagination

Page numbers or cursors, with totals in `meta`.

[Pagination](https://greyhoundracingapi.com/documentation/pagination)

Status

Live uptime for the site, the API and the assistant connector.

[Status](https://greyhoundracingapi.com/status/)

Support

Search the answers or open a ticket. Pass members are answered first.

[Support](https://greyhoundracingapi.com/support/)

#### Questions people ask

How fresh are today's results?

A race appears within a few minutes of being settled. Poll `/v1/results/today` with `since` set to your last `settled_at` to get only the new ones. [Results guide](https://greyhoundracingapi.com/documentation/results)

How far back does the archive go?

To 1 January 2020, for every country. Dates before that are refused with a 400. [Results by date](https://greyhoundracingapi.com/documentation/results-search)

Can I use it in Google Sheets?

Yes. A short Apps Script keeps your key out of the sheet and fills a tab on a timer. [Google Sheets guide](https://greyhoundracingapi.com/documentation/google-sheets)

Can an assistant use it?

Yes. Race Pass and Archive Pass members can connect Claude, ChatGPT or Cursor to the MCP server and ask in plain words. [MCP guide](https://greyhoundracingapi.com/documentation/mcp)

Do you give tips or predictions?

No. Every endpoint returns facts only: races, runners, placings and prices. [Results guide](https://greyhoundracingapi.com/documentation/results)

What happens if I go over my limit?

Calls answer `429` until the minute passes, or the day resets at 00:00 UTC. [Plans and limits](https://greyhoundracingapi.com/documentation/plans-and-limits)

*Get a free key, make your first greyhound racing API call and read the answer, in a minute.* (https://greyhoundracingapi.com/documentation/quick-start)

### Quick start

A key, the first call, the answer.

#### 1. Get a key

Sign in with Google on [the free key page](https://greyhoundracingapi.com/free-key/). Your key is shown once, so copy it somewhere safe. It starts with `gra_live_`, and it is filled into these pages for you.

#### 2. Make a call

Send the key in the `X-API-Key` header. This asks for yesterday's UK results, which every plan can read:

```
curl "https://api.greyhoundracingapi.com/v1/results/yesterday?country=GB" \
  -H "X-API-Key: $KEY"
```

#### 3. Read the answer

Every answer has the same shape: `data` holds what you asked for and `meta` says how much there is. When something goes wrong you get `error` instead, with a code you can act on (see [Errors](https://greyhoundracingapi.com/documentation/errors)).

```
{
  "data": [ races ],
  "meta": { "count": 48, "page": 1, "total_pages": 3, "next_cursor": "cDI", "took_ms": 61 }
}
```

#### Base address

`https://api.greyhoundracingapi.com/v1`

Every endpoint answers `GET`. Add `.csv` to any list path, or `format=csv`, for a spreadsheet-ready file.

#### Where next

[Authentication](https://greyhoundracingapi.com/documentation/authentication), [plans and limits](https://greyhoundracingapi.com/documentation/plans-and-limits), then the endpoint pages in the menu, each with Try it.

*How to send your greyhoundracingapi.com key in a header, keep it safe and roll it.* (https://greyhoundracingapi.com/documentation/authentication)

### Authentication

Every call needs a key. Send it in a header, from your server or script.

```
X-API-Key: $KEY
Authorization: Bearer $KEY
```

#### Never in the address

A key in the query string (`?key=`) is refused with `400 bad_request`. Addresses end up in server logs, browser history and shared links, so a key there is a key given away.

#### Several keys

You can hold up to five keys on [your account](https://greyhoundracingapi.com/account/), one per app, so you can see each one's use and revoke one without touching the rest. They share your plan's daily allowance.

#### Rolling a key

Roll a key on your account page to get a new one. The old one keeps working for 24 hours so you can swap it in without downtime. Revoke stops a key at once. A new key is filled into these docs pages for you.

#### Keep it out of web pages

Anyone holding a key can spend its calls. Call the API from your server or script, not from a public web page.

*What each plan can call, calls per minute and per day, and the rate headers on every answer.* (https://greyhoundracingapi.com/documentation/plans-and-limits)

### Plans and limits

Three plans, all covering the UK, Ireland and Australia. Paid plans are monthly and can be cancelled any time.

| Plan | Price | Data | Per minute / per day |
|---|---|---|---|
| Free key | Free | Yesterday's results | 30 / 75 |
| Race Pass | $29 a month | Today's racecards and results as each race settles | 120 / 20,000 |
| Archive Pass | $79 a month | Live, plus every date from 2020 | 240 / 50,000 |

#### What each plan can call

| Endpoint | Plans |
|---|---|
| [/v1/results/yesterday](https://greyhoundracingapi.com/documentation/results-yesterday) | Free keyRace PassArchive Pass |
| [/v1/results/today](https://greyhoundracingapi.com/documentation/results-today) | Race PassArchive Pass |
| [/v1/results](https://greyhoundracingapi.com/documentation/results-search) | Archive Pass |
| [/v1/racecards/today](https://greyhoundracingapi.com/documentation/racecards-today) | Race PassArchive Pass |
| [/v1/racecards/upcoming](https://greyhoundracingapi.com/documentation/racecards-upcoming) | Race PassArchive Pass |
| [/v1/tracks](https://greyhoundracingapi.com/documentation/tracks) | Free keyRace PassArchive Pass |
| [/v1/usage](https://greyhoundracingapi.com/documentation/usage) | Free keyRace PassArchive Pass |

#### Rate headers

Every answer tells you where you stand:

| Field | Type | Meaning |
|---|---|---|
| `X-RateLimit-Limit` | integer | Calls allowed per minute. |
| `X-RateLimit-Remaining` | integer | Calls left this minute. |
| `X-RateLimit-Reset` | unix time | When this minute's count resets. |
| `X-Quota-Remaining` | integer | Calls left today, UTC. |
| `Retry-After` | seconds | Sent with a 429: how long to wait. |

Days run on UTC. A call that fails on our side (any 5xx) is never counted. [/v1/usage](https://greyhoundracingapi.com/documentation/usage) is free to call. Full prices are on [pricing](https://greyhoundracingapi.com/pricing/).

*Paging through greyhound racing API lists by page number or cursor, and polling with since.* (https://greyhoundracingapi.com/documentation/pagination)

### Pagination

Every list comes 50 races a page, with the totals in `meta`.

| Field | Type | Meaning |
|---|---|---|
| `meta.count` | integer | Races on this page. |
| `meta.page` | integer | This page number. |
| `meta.per_page` | integer | Always 50. |
| `meta.total` | integer | Races in the whole list. |
| `meta.total_pages` | integer | Pages in the whole list. |
| `meta.next_cursor` | string | Pass it as `cursor` for the next page. `null` on the last page. |

#### By cursor

The simplest loop: call, keep the rows, and call again with `cursor` set to `meta.next_cursor` until it is `null`.

```
params = {"date": "2024-03-09"}
rows = []
while True:
    j = S.get("https://api.greyhoundracingapi.com/v1/results", params=params).json()
    rows += j["data"]
    if not j["meta"]["next_cursor"]: break
    params["cursor"] = j["meta"]["next_cursor"]
```

#### By page number

Pass `page=2`, `page=3` and so on, up to `meta.total_pages`. Useful when you want one page in the middle.

#### Polling instead of paging

For today's results, do not page through the day every time. Call with `since` set to the newest `settled_at` you hold and you get only the races settled after it. See [Today's results](https://greyhoundracingapi.com/documentation/results-today).

*Every error the greyhound racing API returns, what it means and what to do.* (https://greyhoundracingapi.com/documentation/errors)

### Errors

Every error has the same shape, with a stable `code` to act on and a `message` for people.

```
{
  "error": { "code": "upgrade_required", "message": "This needs the Race Pass.",
    "plan": "Race Pass", "docs": "https://greyhoundracingapi.com/documentation/errors" }
}
```

| HTTP | Code | What to do |
|---|---|---|
| 400 | `bad_request` | A value is not valid, a date is before 2020, or the key was put in the address. The message says which. |
| 401 | `unauthorized` | No key, or the key is wrong, revoked or expired. Check the header. |
| 403 | `upgrade_required` | Your plan does not include this endpoint. `plan` names the one that does. |
| 404 | `not_found` | No endpoint at that address. Check the path. |
| 422 | `unknown_parameter` | A parameter this endpoint does not take. The message lists the ones it does. |
| 429 | `rate_limited` | Too many calls this minute. Wait for `Retry-After`. |
| 429 | `quota_exceeded` | Today's allowance is used. It resets at 00:00 UTC. |
| 503 | `server_error` | Our side. Not counted against you. Try again shortly, and see [status](https://greyhoundracingapi.com/status/). |

*Greyhound results for yesterday, today as races settle, and any date since 2020: the fields and the common jobs.* (https://greyhoundracingapi.com/documentation/results)

### Greyhound results

Every race with its finishing order, traps, greyhounds, trainers, run times and starting prices.

#### Three ways in

| Endpoint | For | Plan |
|---|---|---|
| [/v1/results/yesterday](https://greyhoundracingapi.com/documentation/results-yesterday) | Yesterday, every meeting. The free key reads this. | Free key |
| [/v1/results/today](https://greyhoundracingapi.com/documentation/results-today) | Today, each race added as it settles. | Race Pass |
| [/v1/results?date=](https://greyhoundracingapi.com/documentation/results-search) | Any date from 1 January 2020. | Archive Pass |

#### How the records link

A race has a `race_id` and a `track`; each runner in `result` has a `runner_id`. Both ids are stable, so you can store them and join across days. The `track` id is the one [Tracks](https://greyhoundracingapi.com/documentation/tracks) lists, and the one the `track` parameter takes.

#### Provisional and final

`result_status` is `provisional` when a result first arrives and `final` once confirmed. `settled_at` is when it arrived, in UTC.

#### Common jobs

Show tonight's winners as they come in: poll `/v1/results/today?since=` every minute or two.

Build a trainer or greyhound history: walk the archive day by day with `/v1/results?date=`, paging each day, and key rows on `runner_id`.

Fill a sheet each morning: fetch `/v1/results/yesterday.csv` from [Google Sheets](https://greyhoundracingapi.com/documentation/google-sheets).

```
curl "https://api.greyhoundracingapi.com/v1/results/today?country=GB&since=19%3A30" \
  -H "X-API-Key: $KEY"
```

*Greyhound racecards for today and the next races: runners, traps and trainers before the off.* (https://greyhoundracingapi.com/documentation/racecards)

### Greyhound racecards

Races still to run, with every runner, trap and trainer.

| Endpoint | For | Plan |
|---|---|---|
| [/v1/racecards/today](https://greyhoundracingapi.com/documentation/racecards-today) | Every race on today's card, in off-time order. | Race Pass |
| [/v1/racecards/upcoming](https://greyhoundracingapi.com/documentation/racecards-upcoming) | The next races about to go. | Race Pass |

#### How the records link

A racecard race has the same `race_id` it will have in the results, and each runner the same `runner_id`. Show the card before the off, then match the result to it by `race_id` when it settles.

#### Non-runners

Withdrawn greyhounds are left out of `runners`, so the list is the field that will run.

#### Common jobs

A next-to-go board: call `/v1/racecards/upcoming` every minute.

One meeting tonight: `/v1/racecards/today?track=romford`.

```
curl "https://api.greyhoundracingapi.com/v1/racecards/today?track=romford" \
  -H "X-API-Key: $KEY"
```

*The greyhound tracks covered in the UK, Ireland and Australia, and how the track id links everything.* (https://greyhoundracingapi.com/documentation/tracks-guide)

### Greyhound tracks

Every track covered in the UK, Ireland and Australia, with its id, country and race distances.

The `track` id (for example `romford` or `shelbourne-park`) is what every race carries and what the `track` parameter takes. Read the list once a day; it rarely changes.

| Endpoint | For | Plan |
|---|---|---|
| [/v1/tracks](https://greyhoundracingapi.com/documentation/tracks) | Every track, with distances. | Free key |

Full coverage by country is on [coverage](https://greyhoundracingapi.com/coverage/).

```
curl "https://api.greyhoundracingapi.com/v1/tracks?country=IE" \
  -H "X-API-Key: $KEY"
```

*Pull greyhound results into Google Sheets with a short Apps Script, your key kept out of the sheet.* (https://greyhoundracingapi.com/documentation/google-sheets)

### Google Sheets

Sheets formulas cannot send a header, and keys never go in an address, so use a short Apps Script. It keeps your key in the script's settings, not in a cell anyone can see.

#### 1. Store your key

In your sheet open Extensions, Apps Script, then Project settings, Script properties, and add a property named `KEY` holding your key.

#### 2. Paste the script

```
function pull() {
  const key = PropertiesService.getScriptProperties().getProperty("KEY");
  const csv = UrlFetchApp.fetch("https://api.greyhoundracingapi.com/v1/results/yesterday.csv?country=GB",
    { headers: { "X-API-Key": key } }).getContentText();
  const rows = Utilities.parseCsv(csv), s = SpreadsheetApp.getActiveSheet();
  s.clear();
  if (rows.length) s.getRange(1, 1, rows.length, rows[0].length).setValues(rows);
}
```

#### 3. Run it

Run `pull` once and allow access. To refresh on a schedule, add a time-driven trigger from the clock icon in Apps Script. A daily trigger fits the free key.

*Call the greyhound racing API from Python with requests, with polling and paging.* (https://greyhoundracingapi.com/documentation/python)

### Python

All you need is `requests`. Keep the key in an environment variable.

```
import os, time, requests

S = requests.Session()
S.headers["X-API-Key"] = os.environ["KEY"]
URL = "https://api.greyhoundracingapi.com/v1/results/today"
since = time.strftime("%H:%M", time.gmtime())

while True:
    r = S.get(URL, params={"since": since})
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", 60))); continue
    since = time.strftime("%H:%M", time.gmtime())
    for race in r.json()["data"]:
        print(race["track_name"], race["no"], race["result"][0]["runner"])
    time.sleep(90)
```

#### Paging an archive day

See [Pagination](https://greyhoundracingapi.com/documentation/pagination) for the cursor loop.

*Call the greyhound racing API from Node with fetch, with polling and paging.* (https://greyhoundracingapi.com/documentation/node)

### Node

Node 18 and later have `fetch` built in. Keep the key in an environment variable.

```
const H = { "X-API-Key": process.env.KEY };
const hhmm = () => new Date().toISOString().slice(11, 16);
let since = hhmm();

setInterval(async () => {
  const r = await fetch(`https://api.greyhoundracingapi.com/v1/results/today?since=${since}`, { headers: H });
  if (r.status === 429) return;
  since = hhmm();
  for (const race of (await r.json()).data)
    console.log(race.track_name, race.no, race.result[0]?.runner);
}, 90_000);
```

#### CSV instead

Add `.csv` to the path and read the body as text: one row per runner, race fields repeated on each row.

*Changes to the greyhound racing API, newest first.* (https://greyhoundracingapi.com/documentation/changelog)

### Changelog

Changes to the API, newest first. Nothing is removed or renamed without notice here first.

| Date | Change |
|---|---|
| 2026-10-06 | The documentation moves to `/documentation`, with Try it on every endpoint, an MCP tools page and `/openapi.json`. |
| 2026-10-05 | Results carry `settled_at` and `result_status`. Every list pages by `page` or `cursor`, 50 races a page. |
| 2026-10-01 | Version 1: results (yesterday, today, by date from 2020), racecards (today, upcoming), tracks and usage, for the UK, Ireland and Australia, as JSON and CSV. MCP server for Race Pass and Archive Pass. |

*Connect Claude, ChatGPT, Cursor or Claude Code to the greyhound racing API with the MCP server.* (https://greyhoundracingapi.com/documentation/mcp)

### MCP server

Connect an assistant to the API and ask racing questions in plain words. It answers from live data with your plan.

`https://greyhoundracingapi.com/mcp`

The MCP server is for Race Pass and Archive Pass members. A free key can read `my_usage` only.

#### Claude

In Claude, open Settings, Connectors, Add custom connector, and paste the address. Sign in with Google when asked and allow access. The connector gets its own key on your account, which you can revoke there.

#### ChatGPT

In ChatGPT, open Settings, Connectors, Create, and paste the address. Sign in when asked.

#### Cursor

Add it to `~/.cursor/mcp.json` with your key in a header:

```
{
  "mcpServers": {
    "greyhoundracingapi": {
      "url": "https://greyhoundracingapi.com/mcp",
      "headers": { "X-API-Key": "$KEY" }
    }
  }
}
```

#### Claude Code

```
claude mcp add --transport http greyhoundracingapi https://greyhoundracingapi.com/mcp --header "X-API-Key: $KEY"
```

#### An example

Ask: "Who won the 19:47 at Romford tonight, and at what price?" The assistant calls `todays_results` with `track=romford`, finds race 7 and answers with the winner, the trap and the starting price from the result.

Every tool, with its parameters and the plan it needs, is on [MCP tools](https://greyhoundracingapi.com/documentation/mcp-tools).

*Every greyhound racing API MCP tool: what it does, its parameters, the endpoint it calls and the plan it needs.* (https://greyhoundracingapi.com/documentation/mcp-tools)

### MCP tools

Every tool the MCP server offers, generated from the same registry as the API.

`yesterdays_results`

Yesterday's greyhound results for the UK, Ireland and Australia, every race with finishing order, times and starting prices.

- Parameters`country` `track`
- Calls[GET /v1/results/yesterday](https://greyhoundracingapi.com/documentation/results-yesterday)
- PlanRace PassArchive Pass

`todays_results`

Today's greyhound results as each race settles. Use since (HH:MM UTC) to get only races settled after a time.

- Parameters`country` `track` `race` `since`
- Calls[GET /v1/results/today](https://greyhoundracingapi.com/documentation/results-today)
- PlanRace PassArchive Pass

`search_results`

Greyhound results on any date from 2020-01-01 (YYYY-MM-DD). Archive Pass.

- Parameters`date` `country` `track`
- Calls[GET /v1/results](https://greyhoundracingapi.com/documentation/results-search)
- PlanArchive Pass

`todays_racecards`

Today's greyhound racecards: every race with its runners, traps and trainers.

- Parameters`country` `track`
- Calls[GET /v1/racecards/today](https://greyhoundracingapi.com/documentation/racecards-today)
- PlanRace PassArchive Pass

`upcoming_races`

The next greyhound races coming up, with runners.

- Parameters`country`
- Calls[GET /v1/racecards/upcoming](https://greyhoundracingapi.com/documentation/racecards-upcoming)
- PlanRace PassArchive Pass

`list_tracks`

Every greyhound track covered, with its id, country and race distances.

- Parameters`country`
- Calls[GET /v1/tracks](https://greyhoundracingapi.com/documentation/tracks)
- PlanRace PassArchive Pass

`my_usage`

Your plan, calls used today and your limits.

- Parametersnone
- Calls[GET /v1/usage](https://greyhoundracingapi.com/documentation/usage)
- PlanFree keyRace PassArchive Pass

*The greyhoundracingapi.com agent skill: what /skill.md is and how to add it to an agent.* (https://greyhoundracingapi.com/documentation/agent-skill)

### Agent skill

A short markdown file that teaches an agent how to use this API: the calls, the plans, the limits and the errors.

`https://greyhoundracingapi.com/skill.md`

#### Add it to an agent

Claude Code: save it as `~/.claude/skills/greyhoundracingapi/SKILL.md`.

```
mkdir -p ~/.claude/skills/greyhoundracingapi && curl -s https://greyhoundracingapi.com/skill.md -o ~/.claude/skills/greyhoundracingapi/SKILL.md
```

Claude: upload it as a skill in Settings, Capabilities.

Other agents: agents that read the skills index find it at [/.well-known/agent-skills/index.json](https://greyhoundracingapi.com/.well-known/agent-skills/index.json).

#### The manual

For the whole API in one file, hand a model [manual.md](https://greyhoundracingapi.com/documentation/manual.md). Both the skill and the manual are rebuilt from the registry, so they always match these pages.

## About this document

Generated from the endpoint registry, the docs pages and the plan settings. The date at the top is the newest change to those; a copy with an older date is stale. The agent skill is at https://greyhoundracingapi.com/skill.md.
