# Horse Racing API UK complete reference

The whole UK Horse Racing API in one file: every endpoint, parameter, sample answer and guide, for British and Northern Irish racing since 2017.

- Base URL: https://api.horseracingapi.co.uk/v1
- Authentication: your key in the `X-API-Key` header, or `Authorization: Bearer <key>`. Never in the address.
- Site: https://horseracingapi.co.uk (documentation at https://horseracingapi.co.uk/documentation)
- Endpoints: 46
- Generated: 2026-10-30T12:46:45Z
- This file: https://horseracingapi.co.uk/documentation/manual.md
- Operator: DeveloperData.net

## Before anything else

- Factual racing data only. There are no predictions, ratings, tips or betting advice on any endpoint.
- Great Britain and Northern Ireland only. No racing from the Republic of Ireland or anywhere else, on any plan.
- Not in the data, on any plan, at any price: sectional times, in-running comments, a live bookmaker feed, or anything before 1 January 2017. Race reports start in 2020.
- Every answer is an envelope: `data` (an object for one record, a list for many) and `meta` (`request_id`, `plan`, `window`, `data_as_of`, and for lists `count`, `next_cursor`, `has_more`).
- Dates are the course's own racing day, `YYYY-MM-DD`. Race times are the racecourse clock. Every other time is UTC.
- Every id is ours and stable (`cr_` course, `mt_` meeting, `rc_` race, `hs_` horse, `tr_` trainer, `jk_` jockey, `ow_` owner). Take ids from answers; never build one.

## Plans

| Plan | Price | Reads | Per minute | Per month |
| --- | --- | --- | --- | --- |
| Free key | Free | yesterday only | 60 | 50 |
| Live | GBP 35 a month, GBP 350 a year | today and the next 3 days | 180 | 250,000 |
| Archive | GBP 60 a month, GBP 600 a year | January 2017 to yesterday | 90 | 150,000 |
| Complete | GBP 89 a month, GBP 890 a year | January 2017 to the next 3 days, race reports and statistics | 180 | 400,000 |

The free key returns prices (starting prices, the market and dividends) as `null`, with a note in `meta`. Plans and prices: https://horseracingapi.co.uk/pricing

## Coverage

69 British and Northern Irish courses, counted from `GET /v1/courses`, which returns the same list.
Races from 1 January 2017 to the cards declared ahead, by plan window. Race reports from 2020.

## Endpoints

### Courses

Every UK course: where it is, which way round, what it races and its fixtures ahead.

#### `GET /v1/courses`

Every UK course. Every UK course, busiest first.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/courses-list. MCP tool: `list_courses`.

Errors: `unauthorized` (401), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "course_id": "cr_1wkcasv1",
            "name": "Wolverhampton",
            "nation": "England",
            "town": "Wolverhampton",
            "county": "West Midlands",
            "lat": 52.604,
            "lng": -2.1436,
            "direction": "left",
            "kinds": [
                "flat",
                "all_weather"
            ],
            "races": 6246,
            "first_meeting": "2017-01-04",
            "last_meeting": "2026-10-27"
        },
        {
            "course_id": "cr_xtryzmdd",
            "name": "Newcastle",
            "nation": "England",
            "town": "Newcastle upon Tyne",
            "county": "Tyne and Wear",
            "lat": 55.0308,
            "lng": -1.6008,
            "direction": "left",
            "kinds": [
                "flat",
                "jumps",
                "all_weather"
            ],
            "races": 5653,
            "first_meeting": "2017-01-03",
            "last_meeting": "2026-10-31"
        }
    ],
    "meta": {
        "request_id": "03f58a1214ba7e5f",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "count": 68
    }
}
```

#### `GET /v1/courses/{course_id}`

One course. One course: what is raced there and the distances.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/course. MCP tool: `course_details`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `course_id` | path | id | yes | Our id for the course, as other answers give it (cr_ and eight characters). | `cr_239y20yw` |

Errors: `unauthorized` (401), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": {
        "course_id": "cr_239y20yw",
        "name": "Abu Dhabi",
        "shortcode": null,
        "country": "UAE",
        "region": "UAE",
        "races": 22,
        "meetings": 3,
        "first_meeting": "2025-04-12",
        "last_meeting": "2026-10-29",
        "town": null,
        "county": null,
        "nation": null,
        "lat": null,
        "lng": null,
        "direction": null,
        "kinds": [],
        "run_types": [
            {
                "run_type": "Flat",
                "surface": "TURF",
                "races": 21,
                "first": "2025-04-12",
                "last": "2026-10-29"
            },
            {
                "run_type": null,
                "surface": "TURF",
                "races": 1,
                "first": "2025-04-12",
                "last": "2025-04-12"
            }
        ],
        "distances": [
            {
                "distance": "1m 3f",
                "races": 7
            },
            {
                "distance": "1m",
                "races": 6
            },
            {
                "distance": "7f",
                "races": 5
            }
        ]
    },
    "meta": {
        "request_id": "e7934fe3e2b0a40f",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T10:08:33+00:00"
    }
}
```

#### `GET /v1/courses/{course_id}/fixtures` (Live, Archive and Complete)

A course's fixtures ahead. The meetings ahead at one course.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/course-fixtures.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `course_id` | path | id | yes | Our id for the course, as other answers give it (cr_ and eight characters). | `cr_239y20yw` |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29):

```json
{
    "data": [],
    "meta": {
        "request_id": "7a22c561a37a16ea",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T09:29:32+00:00",
        "count": 0
    }
}
```

### Cards and results

Meetings, racecards and settled results, by day.

#### `GET /v1/meetings/calendar` (Live, Archive and Complete)

The meetings calendar. Thirty days back and the week ahead, one row per UK course per day.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/meetings-calendar.

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "date": "2026-09-30",
            "course_id": "cr_ttc2m93z",
            "course": "Catterick",
            "country": "GB",
            "code": "flat",
            "fixtures": 1,
            "races": 8,
            "status": "run"
        },
        {
            "date": "2026-09-30",
            "course_id": "cr_qxzyn94c",
            "course": "Kempton",
            "country": "GB",
            "code": "aw",
            "fixtures": 1,
            "races": 9,
            "status": "run"
        }
    ],
    "meta": {
        "request_id": "2d6f24742b86e537",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T12:18:33+00:00",
        "count": 125
    }
}
```

#### `GET /v1/meetings/{date}`

Meetings on a date. Every UK meeting on a date, with going and weather.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/meetings-by-date.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `date` | path | date | yes | A UK racing day, YYYY-MM-DD, by the course's own clock. | `2026-10-29` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "meeting_id": "mt_b5898ppq",
            "course_id": "cr_jqze1jjy",
            "course": "Bath",
            "shortcode": "BTH",
            "country": "ENG",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Soft (Heavy in places)",
            "surface": "TURF",
            "weather": "Sunny",
            "status": "DORMANT",
            "races": 8
        },
        {
            "meeting_id": "mt_rc6bwdyr",
            "course_id": "cr_7vbqtcfg",
            "course": "Ffos Las",
            "shortcode": "FFL",
            "country": "Wale",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Good",
            "surface": "TURF",
            "weather": "Mostly Cloudy",
            "status": "DORMANT",
            "races": 7
        }
    ],
    "meta": {
        "request_id": "73755e24dae59fcb",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T08:03:04+00:00",
        "count": 4
    }
}
```

#### `GET /v1/meetings/{meeting_id}`

One meeting. One meeting and every race on it.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/meeting.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `meeting_id` | path | id | yes | Our id for the meeting, as other answers give it (mt_ and eight characters). | `mt_yzs5rm2b` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": {
        "meeting_id": "mt_yzs5rm2b",
        "course_id": "cr_239y20yw",
        "course": "Abu Dhabi",
        "country": "UAE",
        "region": "UAE",
        "date": "2026-10-29",
        "going": "Good",
        "surface": "TURF",
        "weather": "Fine",
        "status": "DORMANT",
        "races": [
            {
                "race_id": "rc_0aa1c4st",
                "meeting_id": "mt_yzs5rm2b",
                "course": "Abu Dhabi",
                "time": "13:00",
                "off_time": "13:01:21",
                "name": "Race 1 - Al Ghadeer Handicap",
                "run_type": "Flat",
                "class": null,
                "distance": "6f",
                "going": "Good",
                "surface": "TURF",
                "handicap": true,
                "runners": 12,
                "result_available": true
            },
            {
                "race_id": "rc_z054gb4m",
                "meeting_id": "mt_yzs5rm2b",
                "course": "Abu Dhabi",
                "time": "13:30",
                "off_time": "13:32:18",
                "name": "Race 2 - Al Bidaya Maiden Stakes",
                "run_type": "Flat",
                "class": null,
                "distance": "7f",
                "going": "Good",
                "surface": "TURF",
                "handicap": false,
                "runners": 13,
                "result_available": true
            },
            {
                "race_id": "rc_ny78pgj5",
                "meeting_id": "mt_yzs5rm2b",
                "course": "Abu Dhabi",
                "time": "14:00",
                "off_time": "14:02:58",
                "name": "Race 3 - Al Maqam Classic Maiden Stakes",
                "run_type": "Flat",
                "class": null,
                "distance": "1m 3f",
                "going": "Good",
                "surface": "TURF",
                "handicap": false,
                "runners": 15,
                "result_available": true
            }
        ]
    },
    "meta": {
        "request_id": "f9641ec4a5704e10",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:05:06+00:00"
    }
}
```

#### `GET /v1/racecards/today` (Live, Archive and Complete)

Today's UK racecards. Today's UK cards, grouped by meeting.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/racecards-today. MCP tool: `todays_racecards`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `course` | query | course id | no | Only this course's meeting. Course ids come from GET /v1/courses. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "meeting_id": "mt_e6gdvcan",
            "course_id": "cr_m5cvpetc",
            "course": "Down Royal",
            "country": "Nort",
            "region": "NIR",
            "date": "2026-10-30",
            "going": "Yielding",
            "surface": "TURF",
            "races": [
                {
                    "race_id": "rc_2drzxxqn",
                    "meeting_id": "mt_e6gdvcan",
                    "course": "Down Royal",
                    "time": "13:00",
                    "off_time": null,
                    "name": "Irish Stallion Farms EBF Maiden Hurdle",
                    "run_type": null,
                    "class": null,
                    "distance": "2m 6f 110y",
                    "going": "Yielding",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 11,
                    "result_available": false
                },
                {
                    "race_id": "rc_tq45xw2w",
                    "meeting_id": "mt_e6gdvcan",
                    "course": "Down Royal",
                    "time": "13:30",
                    "off_time": null,
                    "name": "Eventsec Handicap Hurdle (0-100)",
                    "run_type": null,
                    "class": null,
                    "distance": "3m 45y",
                    "going": "Yielding",
                    "surface": "TURF",
                    "handicap": true,
                    "runners": 23,
                    "result_available": false
                },
                {
                    "race_id": "rc_97we86jg",
                    "meeting_id": "mt_e6gdvcan",
                    "course": "Down Royal",
                    "time": "14:00",
                    "off_time": null,
                    "name": "Irish Stallion Farms EBF Feathard Lady Mares Novice Hurdle (Grade 3)",
                    "run_type": null,
                    "class": "1",
                    "distance": "2m 190y",
                    "going": "Yielding",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 9,
                    "result_available": false
                }
            ]
        },
        {
            "meeting_id": "mt_27reay5r",
            "course_id": "cr_xtryzmdd",
            "course": "Newcastle",
            "country": "ENG",
            "region": "GB",
            "date": "2026-10-30",
            "going": "Standard",
            "surface": "ALLWEATHER",
            "races": [
                {
                    "race_id": "rc_jnae42nn",
                    "meeting_id": "mt_27reay5r",
                    "course": "Newcastle",
                    "time": "16:15",
                    "off_time": null,
                    "name": "Midnite: Built For 2026 Not 2006 Handicap",
                    "run_type": null,
                    "class": "6",
                    "distance": "1m 2f 42y",
                    "going": "Standard",
                    "surface": "ALLWEATHER",
                    "handicap": true,
                    "runners": 14,
                    "result_available": false
                },
                {
                    "race_id": "rc_385jyvxh",
                    "meeting_id": "mt_27reay5r",
                    "course": "Newcastle",
                    "time": "16:45",
                    "off_time": null,
                    "name": "All-Weather Championship Is Back Novice Stakes (GBB Race)",
                    "run_type": null,
                    "class": "4",
                    "distance": "7f 14y",
                    "going": "Standard",
                    "surface": "ALLWEATHER",
                    "handicap": false,
                    "runners": 10,
                    "result_available": false
                },
                {
                    "race_id": "rc_jxnrpja3",
                    "meeting_id": "mt_27reay5r",
                    "course": "Newcastle",
                    "time": "17:15",
                    "off_time": null,
                    "name": "AWC Finals Day At Newcastle 26th March Nursery",
                    "run_type": null,
                    "class": "5",
                    "distance": "1m 5y",
                    "going": "Standard",
                    "surface": "ALLWEATHER",
                    "handicap": true,
                    "runners": 5,
                    "result_available": false
                }
            ]
        }
    ],
    "meta": {
        "request_id": "05ff65a232f7aef7",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:14:03+00:00",
        "count": 5
    }
}
```

#### `GET /v1/racecards/upcoming` (Live, Archive and Complete)

Upcoming racecards. Declarations for the next few days.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/racecards-upcoming.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `days` | query | integer | no | How many days ahead, 1 to 7. Today and tomorrow when left out. Default 2. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "race_id": "rc_p0n4gn9t",
            "meeting_id": "mt_8fbc2mcy",
            "course": "Charles Town",
            "time": "00:02",
            "off_time": null,
            "name": "Race 3 - Maiden Claiming",
            "run_type": null,
            "class": null,
            "distance": "4f 110y",
            "going": null,
            "surface": "DIRT",
            "handicap": false,
            "runners": 8,
            "result_available": false,
            "date": "2026-10-30"
        },
        {
            "race_id": "rc_2pxrgadc",
            "meeting_id": "mt_dfs6rek9",
            "course": "Penn National",
            "time": "00:10",
            "off_time": null,
            "name": "Race 6 - Claiming",
            "run_type": null,
            "class": null,
            "distance": "1m 70y",
            "going": null,
            "surface": "DIRT",
            "handicap": false,
            "runners": 6,
            "result_available": false,
            "date": "2026-10-30"
        }
    ],
    "meta": {
        "request_id": "4c4926d9c4c93fd5",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:33:04+00:00",
        "count": 327
    }
}
```

#### `GET /v1/racecards/{date}`

Racecards for a date. The full UK card for any date.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/racecards-by-date. MCP tool: `racecards_for_date`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `date` | path | date | yes | A UK racing day, YYYY-MM-DD, by the course's own clock. | `2026-10-29` |
| `course` | query | course id | no | Only this course's meeting. Course ids come from GET /v1/courses. |  |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "meeting_id": "mt_b5898ppq",
            "course_id": "cr_jqze1jjy",
            "course": "Bath",
            "country": "ENG",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Soft (Heavy in places)",
            "surface": "TURF",
            "races": [
                {
                    "race_id": "rc_c2v2dgjt",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "12:42",
                    "off_time": "12:44:22",
                    "name": "David Cole Memorial EBF Novice Stakes (GBB/GBBPlus Race) (Div 1)",
                    "run_type": "Flat",
                    "class": "3",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 12,
                    "result_available": true
                },
                {
                    "race_id": "rc_dk34v84n",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "13:12",
                    "off_time": "13:15:53",
                    "name": "David Cole Memorial EBF Novice Stakes (GBB/GBBPlus Race) (Div 2)",
                    "run_type": "Flat",
                    "class": "3",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 11,
                    "result_available": true
                },
                {
                    "race_id": "rc_j4rqb8cc",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "13:42",
                    "off_time": "13:45:03",
                    "name": "Bath Luxury Toilet Hire Nursery",
                    "run_type": "Flat",
                    "class": "6",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": true,
                    "runners": 8,
                    "result_available": true
                }
            ]
        },
        {
            "meeting_id": "mt_rc6bwdyr",
            "course_id": "cr_7vbqtcfg",
            "course": "Ffos Las",
            "country": "Wale",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Heavy (Soft in places)",
            "surface": "TURF",
            "races": [
                {
                    "race_id": "rc_tkpw2q6x",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "13:30",
                    "off_time": "13:30:34",
                    "name": "bettingsites.co.uk Maiden Hurdle (GBB Race)",
                    "run_type": "Hurdle",
                    "class": "4",
                    "distance": "2m 4f",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 13,
                    "result_available": true
                },
                {
                    "race_id": "rc_xqhxz6j1",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "14:00",
                    "off_time": "14:00:28",
                    "name": "Dandara Maiden Hurdle (GBB Race)",
                    "run_type": "Hurdle",
                    "class": "4",
                    "distance": "1m 7f 182y",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 10,
                    "result_available": true
                },
                {
                    "race_id": "rc_zq7h6pfn",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "14:30",
                    "off_time": "14:31:05",
                    "name": "bettingsites.co.uk Handicap Hurdle",
                    "run_type": "Hurdle",
                    "class": "5",
                    "distance": "2m 4f",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": true,
                    "runners": 6,
                    "result_available": true
                }
            ]
        }
    ],
    "meta": {
        "request_id": "1ab14028c32b5422",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:05:06+00:00",
        "count": 4
    }
}
```

#### `GET /v1/results/latest`

Latest results. The latest settled UK races your plan can read.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/results-latest.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 25. | `5` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "race_id": "rc_s5e9rgr6",
            "meeting_id": "mt_24p8en3d",
            "course": "Newmarket",
            "time": "12:05",
            "off_time": "12:05:57",
            "name": "German G1 Racecourses Thank World Pool British EBF Novice Stakes (C & G) (Div 1)",
            "run_type": null,
            "class": "3",
            "distance": "7f",
            "going": "Good to Soft",
            "surface": "TURF",
            "handicap": false,
            "runners": 12,
            "result_available": true,
            "date": "2026-10-30",
            "winning_time": "1m 26.21s",
            "book_percentage": 122.14
        },
        {
            "race_id": "rc_syd1hjrz",
            "meeting_id": "mt_b05v6sym",
            "course": "Lyon-Parilly",
            "time": "11:50",
            "off_time": "11:53:48",
            "name": "Prix De Lacroix-laval Handicap",
            "run_type": null,
            "class": "3",
            "distance": "1m 3f 204y",
            "going": "Very Soft",
            "surface": "TURF",
            "handicap": true,
            "runners": 9,
            "result_available": true,
            "date": "2026-10-30",
            "winning_time": null,
            "book_percentage": 126.96
        }
    ],
    "meta": {
        "request_id": "3e33473236a03abd",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T12:41:32+00:00",
        "count": 5
    }
}
```

#### `GET /v1/results/yesterday`

Yesterday's results. Every settled UK race from yesterday.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/results-yesterday.

Errors: `unauthorized` (401), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "meeting_id": "mt_b5898ppq",
            "course_id": "cr_jqze1jjy",
            "course": "Bath",
            "country": "ENG",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Soft (Heavy in places)",
            "surface": "TURF",
            "races": [
                {
                    "race_id": "rc_c2v2dgjt",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "12:42",
                    "off_time": "12:44:22",
                    "name": "David Cole Memorial EBF Novice Stakes (GBB/GBBPlus Race) (Div 1)",
                    "run_type": "Flat",
                    "class": "3",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 12,
                    "result_available": true
                },
                {
                    "race_id": "rc_dk34v84n",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "13:12",
                    "off_time": "13:15:53",
                    "name": "David Cole Memorial EBF Novice Stakes (GBB/GBBPlus Race) (Div 2)",
                    "run_type": "Flat",
                    "class": "3",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 11,
                    "result_available": true
                },
                {
                    "race_id": "rc_j4rqb8cc",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "13:42",
                    "off_time": "13:45:03",
                    "name": "Bath Luxury Toilet Hire Nursery",
                    "run_type": "Flat",
                    "class": "6",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": true,
                    "runners": 8,
                    "result_available": true
                }
            ]
        },
        {
            "meeting_id": "mt_rc6bwdyr",
            "course_id": "cr_7vbqtcfg",
            "course": "Ffos Las",
            "country": "Wale",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Heavy (Soft in places)",
            "surface": "TURF",
            "races": [
                {
                    "race_id": "rc_tkpw2q6x",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "13:30",
                    "off_time": "13:30:34",
                    "name": "bettingsites.co.uk Maiden Hurdle (GBB Race)",
                    "run_type": "Hurdle",
                    "class": "4",
                    "distance": "2m 4f",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 13,
                    "result_available": true
                },
                {
                    "race_id": "rc_xqhxz6j1",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "14:00",
                    "off_time": "14:00:28",
                    "name": "Dandara Maiden Hurdle (GBB Race)",
                    "run_type": "Hurdle",
                    "class": "4",
                    "distance": "1m 7f 182y",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 10,
                    "result_available": true
                },
                {
                    "race_id": "rc_zq7h6pfn",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "14:30",
                    "off_time": "14:31:05",
                    "name": "bettingsites.co.uk Handicap Hurdle",
                    "run_type": "Hurdle",
                    "class": "5",
                    "distance": "2m 4f",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": true,
                    "runners": 6,
                    "result_available": true
                }
            ]
        }
    ],
    "meta": {
        "request_id": "3fc5b745f31684fb",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T04:03:33+00:00",
        "count": 4
    }
}
```

#### `GET /v1/results/{date}`

Results for a date. Settled UK races for a date.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/results-by-date. MCP tool: `results_for_date`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `date` | path | date | yes | A UK racing day, YYYY-MM-DD, by the course's own clock. | `2026-10-29` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "meeting_id": "mt_b5898ppq",
            "course_id": "cr_jqze1jjy",
            "course": "Bath",
            "country": "ENG",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Soft (Heavy in places)",
            "surface": "TURF",
            "races": [
                {
                    "race_id": "rc_c2v2dgjt",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "12:42",
                    "off_time": "12:44:22",
                    "name": "David Cole Memorial EBF Novice Stakes (GBB/GBBPlus Race) (Div 1)",
                    "run_type": "Flat",
                    "class": "3",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 12,
                    "result_available": true
                },
                {
                    "race_id": "rc_dk34v84n",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "13:12",
                    "off_time": "13:15:53",
                    "name": "David Cole Memorial EBF Novice Stakes (GBB/GBBPlus Race) (Div 2)",
                    "run_type": "Flat",
                    "class": "3",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 11,
                    "result_available": true
                },
                {
                    "race_id": "rc_j4rqb8cc",
                    "meeting_id": "mt_b5898ppq",
                    "course": "Bath",
                    "time": "13:42",
                    "off_time": "13:45:03",
                    "name": "Bath Luxury Toilet Hire Nursery",
                    "run_type": "Flat",
                    "class": "6",
                    "distance": "1m",
                    "going": "Soft (Heavy in places)",
                    "surface": "TURF",
                    "handicap": true,
                    "runners": 8,
                    "result_available": true
                }
            ]
        },
        {
            "meeting_id": "mt_rc6bwdyr",
            "course_id": "cr_7vbqtcfg",
            "course": "Ffos Las",
            "country": "Wale",
            "region": "GB",
            "date": "2026-10-29",
            "going": "Heavy (Soft in places)",
            "surface": "TURF",
            "races": [
                {
                    "race_id": "rc_tkpw2q6x",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "13:30",
                    "off_time": "13:30:34",
                    "name": "bettingsites.co.uk Maiden Hurdle (GBB Race)",
                    "run_type": "Hurdle",
                    "class": "4",
                    "distance": "2m 4f",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 13,
                    "result_available": true
                },
                {
                    "race_id": "rc_xqhxz6j1",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "14:00",
                    "off_time": "14:00:28",
                    "name": "Dandara Maiden Hurdle (GBB Race)",
                    "run_type": "Hurdle",
                    "class": "4",
                    "distance": "1m 7f 182y",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": false,
                    "runners": 10,
                    "result_available": true
                },
                {
                    "race_id": "rc_zq7h6pfn",
                    "meeting_id": "mt_rc6bwdyr",
                    "course": "Ffos Las",
                    "time": "14:30",
                    "off_time": "14:31:05",
                    "name": "bettingsites.co.uk Handicap Hurdle",
                    "run_type": "Hurdle",
                    "class": "5",
                    "distance": "2m 4f",
                    "going": "Heavy (Soft in places)",
                    "surface": "TURF",
                    "handicap": true,
                    "runners": 6,
                    "result_available": true
                }
            ]
        }
    ],
    "meta": {
        "request_id": "ff837b43678eb0a7",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:27:04+00:00",
        "count": 4
    }
}
```

### Races and markets

One race in full: the field, the result, the market, dividends and upsets.

#### `GET /v1/races/search` (Live, Archive and Complete)

Search races. UK races by date, course, type, going, class and field size.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/races-search. MCP tool: `search_races`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `date_from` | query | date | no | From this UK day, YYYY-MM-DD. Held to your plan's window; meta.searched says what was used. | `2026-10-29` |
| `date_to` | query | date | no | To this UK day, YYYY-MM-DD. Held to your plan's window. | `2026-10-29` |
| `course_id` | query | id | no | Our id for the course, as other answers give it (cr_ and eight characters). |  |
| `run_type` | query | string | no | The kind of race. One of: Flat, Hurdle, Chase, NH Flat. |  |
| `class` | query | string | no | The race class as published, for example Class 4. |  |
| `going` | query | string | no | The going as published, matched exactly, for example Good to Soft. |  |
| `surface` | query | string | no | Turf, or the all-weather surface by name, for example Polytrack or Tapeta. |  |
| `handicap` | query | boolean | no | true for handicaps only, false for everything else. One of: true, false. |  |
| `min_runners` | query | integer | no | Races with at least this many runners. |  |
| `max_runners` | query | integer | no | Races with at most this many runners. |  |
| `result_available` | query | boolean | no | true for settled races only. One of: true, false. |  |
| `limit` | query | integer | no | How many rows in one answer, 1 to 200. Default 50. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "race_id": "rc_676s9p1h",
            "meeting_id": "mt_4wycegh0",
            "course": "Stratford",
            "time": "13:50",
            "off_time": "13:51:40",
            "name": "EBF And Charlie Longsdon Racing 'National Hunt' Novices' Hurdle (GBB Race) (Div 1)",
            "run_type": "Hurdle",
            "class": "4",
            "distance": "2m 70y",
            "going": "Good to Soft (Soft in places)",
            "surface": "TURF",
            "handicap": false,
            "runners": 10,
            "result_available": true,
            "date": "2026-10-29"
        },
        {
            "race_id": "rc_rcq05g1h",
            "meeting_id": "mt_4wycegh0",
            "course": "Stratford",
            "time": "14:20",
            "off_time": "14:20:54",
            "name": "EBF And Charlie Longsdon Racing 'National Hunt' Novices' Hurdle (GBB Race) (Div 2)",
            "run_type": "Hurdle",
            "class": "4",
            "distance": "2m 70y",
            "going": "Good to Soft (Soft in places)",
            "surface": "TURF",
            "handicap": false,
            "runners": 10,
            "result_available": true,
            "date": "2026-10-29"
        }
    ],
    "meta": {
        "request_id": "298eb4c0af1cf035",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T12:46:35+00:00",
        "count": 5
    }
}
```

#### `GET /v1/races/{race_id}`

One race. One race: conditions, the market and every runner.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/race. MCP tool: `race_details`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": {
        "race_id": "rc_0aa1c4st",
        "meeting_id": "mt_yzs5rm2b",
        "course_id": "cr_239y20yw",
        "course": "Abu Dhabi",
        "country": "UAE",
        "region": "UAE",
        "date": "2026-10-29",
        "time": "13:00",
        "off_time": "13:01:21",
        "name": "Race 1 - Al Ghadeer Handicap",
        "run_type": "Flat",
        "class": null,
        "age": "3YO plus",
        "distance": "6f",
        "going": "Good",
        "surface": "TURF",
        "handicap": true,
        "winning_time": "1m 16.55s",
        "book_percentage": 133.36,
        "runners": [
            {
                "cloth": 6,
                "draw": 4,
                "horse_id": "hs_x73ps4xh",
                "horse": "Af Saqara",
                "age": 5,
                "weight": "8-11",
                "official_rating": null,
                "form": "11-30",
                "headgear": "Blinkers",
                "owner": "Khalid Khalifa Al Nabooda",
                "owner_id": "ow_neh55z1b",
                "trainer_id": "tr_j3qtz590",
                "trainer": "Ernst Oertel",
                "jockey_id": "jk_xr618k8m",
                "jockey": "Bernardo Pinheiro",
                "silk": "Black, white star, black sleeves, white cap",
                "sp": "7/1",
                "sp_decimal": 8,
                "price_path": {
                    "opening": null,
                    "opening_decimal": null,
                    "touched": null,
                    "sp": "7/1",
                    "sp_decimal": 8,
                    "drift": null,
                    "source": "starting_price_only"
                },
                "favourite": false,
                "market_position": 3,
                "position": 1,
                "beaten_distance": null,
                "casualty": null,
                "run_status": "ran",
                "last_run_days": 201,
                "speed_figure": null,
                "breeding": null,
                "handicap_mark": null
            },
            {
                "cloth": 11,
                "draw": 7,
                "horse_id": "hs_des8z34q",
                "horse": "Af Marmuq",
                "age": 8,
                "weight": "8-6",
                "official_rating": null,
                "form": "011506",
                "headgear": null,
                "owner": "Khalid Khalifa Al Nabooda",
                "owner_id": "ow_neh55z1b",
                "trainer_id": "tr_j3qtz590",
                "trainer": "Ernst Oertel",
                "jockey_id": "jk_bvfc3660",
                "jockey": "M Rodrigues",
                "silk": "Black, white star, black sleeves, blue cap",
                "sp": "10/1",
                "sp_decimal": 11,
                "price_path": {
                    "opening": null,
                    "opening_decimal": null,
                    "touched": null,
                    "sp": "10/1",
                    "sp_decimal": 11,
                    "drift": null,
                    "source": "starting_price_only"
                },
                "favourite": false,
                "market_position": 7,
                "position": 2,
                "beaten_distance": "3/4 length",
                "casualty": null,
                "run_status": "ran",
                "last_run_days": 208,
                "speed_figure": null,
                "breeding": null,
                "handicap_mark": null
            },
            {
                "cloth": 5,
                "draw": 8,
                "horse_id": "hs_5nzbfr73",
                "horse": "Ezzah",
                "age": 4,
                "weight": "8-13",
                "official_rating": null,
                "form": "15",
                "headgear": null,
                "owner": "Royal Cavalry Oman",
                "owner_id": "ow_2d8nknyk",
                "trainer_id": "tr_t473p4q2",
                "trainer": "I Hadhrami",
                "jockey_id": "jk_yrn5hzfm",
                "jockey": "Ray Dawson",
                "silk": "Yellow, green stripe, red sleeves, red cap",
                "sp": "8/1",
                "sp_decimal": 9,
                "price_path": {
                    "opening": null,
                    "opening_decimal": null,
                    "touched": null,
                    "sp": "8/1",
                    "sp_decimal": 9,
                    "drift": null,
                    "source": "starting_price_only"
                },
                "favourite": false,
                "market_position": 4,
                "position": 3,
                "beaten_distance": "1 3/4 length",
                "casualty": null,
                "run_status": "ran",
                "last_run_days": 201,
                "speed_figure": null,
                "breeding": null,
                "handicap_mark": null
            }
        ],
        "placed": 3,
        "stage": "WEIGHEDIN",
        "result_available": true,
        "weather": null,
        "class_figure": null,
        "speed_figure": null
    },
    "meta": {
        "request_id": "1c558294fbb3ce0b",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T10:58:35+00:00"
    }
}
```

#### `GET /v1/races/{race_id}/runners`

A race's runners. The field alone.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/race-runners.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "cloth": 6,
            "draw": 4,
            "horse_id": "hs_x73ps4xh",
            "horse": "Af Saqara",
            "age": 5,
            "weight": "8-11",
            "official_rating": null,
            "form": "11-30",
            "headgear": "Blinkers",
            "owner": "Khalid Khalifa Al Nabooda",
            "owner_id": "ow_neh55z1b",
            "trainer_id": "tr_j3qtz590",
            "trainer": "Ernst Oertel",
            "jockey_id": "jk_xr618k8m",
            "jockey": "Bernardo Pinheiro",
            "silk": "Black, white star, black sleeves, white cap",
            "sp": "7/1",
            "sp_decimal": 8,
            "price_path": {
                "opening": null,
                "opening_decimal": null,
                "touched": null,
                "sp": "7/1",
                "sp_decimal": 8,
                "drift": null,
                "source": "starting_price_only"
            },
            "favourite": false,
            "market_position": 3,
            "position": 1,
            "beaten_distance": null,
            "casualty": null,
            "run_status": "ran",
            "last_run_days": 201,
            "speed_figure": null,
            "breeding": null,
            "handicap_mark": null
        },
        {
            "cloth": 11,
            "draw": 7,
            "horse_id": "hs_des8z34q",
            "horse": "Af Marmuq",
            "age": 8,
            "weight": "8-6",
            "official_rating": null,
            "form": "011506",
            "headgear": null,
            "owner": "Khalid Khalifa Al Nabooda",
            "owner_id": "ow_neh55z1b",
            "trainer_id": "tr_j3qtz590",
            "trainer": "Ernst Oertel",
            "jockey_id": "jk_bvfc3660",
            "jockey": "M Rodrigues",
            "silk": "Black, white star, black sleeves, blue cap",
            "sp": "10/1",
            "sp_decimal": 11,
            "price_path": {
                "opening": null,
                "opening_decimal": null,
                "touched": null,
                "sp": "10/1",
                "sp_decimal": 11,
                "drift": null,
                "source": "starting_price_only"
            },
            "favourite": false,
            "market_position": 7,
            "position": 2,
            "beaten_distance": "3/4 length",
            "casualty": null,
            "run_status": "ran",
            "last_run_days": 208,
            "speed_figure": null,
            "breeding": null,
            "handicap_mark": null
        }
    ],
    "meta": {
        "request_id": "84ef039c0c69f830",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:11:03+00:00",
        "count": 12
    }
}
```

#### `GET /v1/races/{race_id}/result`

A race's result. Finishing order, casualties, dividends and prize money.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/race-result.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": {
        "race_id": "rc_0aa1c4st",
        "course": "Abu Dhabi",
        "date": "2026-10-29",
        "off_time": "13:01:21",
        "winning_time": "1m 16.55s",
        "weather": null,
        "class_figure": null,
        "speed_figure": null,
        "book_percentage": 133.36,
        "placed": 3,
        "dividends": {
            "currency": "AED",
            "straight_forecast": 85.59
        },
        "prizes": [
            {
                "position": 1,
                "prize": 39601
            },
            {
                "position": 2,
                "prize": 13202
            },
            {
                "position": 3,
                "prize": 7259
            }
        ],
        "result": [
            {
                "position": 1,
                "cloth": 6,
                "horse_id": "hs_x73ps4xh",
                "horse": "Af Saqara",
                "sp": "7/1",
                "sp_decimal": 8,
                "beaten_distance": null,
                "casualty": null,
                "run_status": "ran",
                "speed_figure": null,
                "jockey": "Bernardo Pinheiro",
                "trainer": "Ernst Oertel"
            },
            {
                "position": 2,
                "cloth": 11,
                "horse_id": "hs_des8z34q",
                "horse": "Af Marmuq",
                "sp": "10/1",
                "sp_decimal": 11,
                "beaten_distance": "3/4 length",
                "casualty": null,
                "run_status": "ran",
                "speed_figure": null,
                "jockey": "M Rodrigues",
                "trainer": "Ernst Oertel"
            },
            {
                "position": 3,
                "cloth": 5,
                "horse_id": "hs_5nzbfr73",
                "horse": "Ezzah",
                "sp": "8/1",
                "sp_decimal": 9,
                "beaten_distance": "1 3/4 length",
                "casualty": null,
                "run_status": "ran",
                "speed_figure": null,
                "jockey": "Ray Dawson",
                "trainer": "I Hadhrami"
            }
        ],
        "unplaced": [
            {
                "position": null,
                "cloth": 12,
                "horse_id": "hs_n11js1na",
                "horse": "Khattaf Wrsan",
                "sp": "25/1",
                "sp_decimal": 26,
                "beaten_distance": null,
                "casualty": null,
                "run_status": "non_runner",
                "speed_figure": null,
                "jockey": "Non Runner",
                "trainer": "J Salman"
            }
        ]
    },
    "meta": {
        "request_id": "1882fec20696a4c6",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:05:06+00:00"
    }
}
```

#### `GET /v1/races/{race_id}/market` (Live, Archive and Complete)

A race's market. Book percentage, every price and what moved.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/race-market. MCP tool: `race_market`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": {
        "race_id": "rc_0aa1c4st",
        "book_percentage": 133.36,
        "runners": [
            {
                "horse_id": "hs_x73ps4xh",
                "horse": "Af Saqara",
                "sp": "7/1",
                "sp_decimal": 8,
                "implied": 0.125,
                "price_path": {
                    "opening": null,
                    "opening_decimal": null,
                    "touched": null,
                    "sp": "7/1",
                    "sp_decimal": 8,
                    "drift": null,
                    "source": "starting_price_only"
                },
                "favourite": false,
                "market_position": 3,
                "exchange": null,
                "tote_final": null
            },
            {
                "horse_id": "hs_des8z34q",
                "horse": "Af Marmuq",
                "sp": "10/1",
                "sp_decimal": 11,
                "implied": 0.0909,
                "price_path": {
                    "opening": null,
                    "opening_decimal": null,
                    "touched": null,
                    "sp": "10/1",
                    "sp_decimal": 11,
                    "drift": null,
                    "source": "starting_price_only"
                },
                "favourite": false,
                "market_position": 7,
                "exchange": null,
                "tote_final": null
            },
            {
                "horse_id": "hs_5nzbfr73",
                "horse": "Ezzah",
                "sp": "8/1",
                "sp_decimal": 9,
                "implied": 0.1111,
                "price_path": {
                    "opening": null,
                    "opening_decimal": null,
                    "touched": null,
                    "sp": "8/1",
                    "sp_decimal": 9,
                    "drift": null,
                    "source": "starting_price_only"
                },
                "favourite": false,
                "market_position": 4,
                "exchange": null,
                "tote_final": null
            }
        ]
    },
    "meta": {
        "request_id": "24c90f9ffc95cc5e",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T08:11:33+00:00"
    }
}
```

#### `GET /v1/races/{race_id}/dividends` (Live, Archive and Complete)

A race's dividends. Tote returns and prizes.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/race-dividends.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": {
        "race_id": "rc_0aa1c4st",
        "course": "Abu Dhabi",
        "date": "2026-10-29",
        "dividends": {
            "currency": "AED",
            "straight_forecast": 85.59
        },
        "prizes": [
            {
                "position": 1,
                "prize": 39601
            },
            {
                "position": 2,
                "prize": 13202
            },
            {
                "position": 3,
                "prize": 7259
            }
        ]
    },
    "meta": {
        "request_id": "a0fec08b23811581",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T12:04:04+00:00"
    }
}
```

#### `GET /v1/races/{race_id}/analysis` (Live, Archive and Complete)

A race's analysis. Market shape and what the course and distance usually produce.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/race-analysis.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29):

```json
{
    "data": {
        "race_id": "rc_0aa1c4st",
        "course": "Abu Dhabi",
        "date": "2026-10-29",
        "conditions": {
            "run_type": "Flat",
            "distance": "6f",
            "going": "Good",
            "surface": "TURF",
            "class": null,
            "handicap": true,
            "runners": 12
        },
        "market": {
            "book_percentage": 133.36,
            "shape": {
                "shortest": 2.75,
                "longest": 26,
                "median": 10.25,
                "spread": 9.5,
                "priced": 12
            },
            "favourites": [
                {
                    "horse_id": "hs_ngjpqrbn",
                    "horse": "Es Khairiyah",
                    "sp": "7/4",
                    "position": 4
                }
            ],
            "movers": []
        },
        "at_this_course_and_distance": {
            "races": 4,
            "typical_field": 12.8,
            "typical_book": 134.7,
            "favourite_runs": 4,
            "favourite_wins": 1,
            "favourite_strike": 0.25
        },
        "note": "Context for one race. For statistics across the archive see /v1/analysis/angles and the course endpoints."
    },
    "meta": {
        "request_id": "8c77b0ee699154b5",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T09:35:33+00:00"
    }
}
```

#### `GET /v1/upsets`

The day's upsets. The day's UK shocks, scored 0 to 100.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/upsets. MCP tool: `days_upsets`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `date` | query | date | no | A UK racing day, YYYY-MM-DD. Leave it out for the latest settled day. |  |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29):

```json
{
    "data": [],
    "meta": {
        "request_id": "7cdcf0e3ff5e5615",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T10:59:03+00:00",
        "count": 0
    }
}
```

#### `GET /v1/upsets/{race_id}`

One race's upset score. One race judged by the upset rules.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/race-upset.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29):

```json
{
    "data": {
        "race_id": "rc_0aa1c4st",
        "meeting_id": "mt_yzs5rm2b",
        "course_id": "cr_239y20yw",
        "course": "Abu Dhabi",
        "country": "UAE",
        "region": "UAE",
        "date": "2026-10-29",
        "off_time": "13:01:21",
        "name": "Race 1 - Al Ghadeer Handicap",
        "runners": 11,
        "is_upset": false,
        "shock_score": 0,
        "why": [],
        "rules": [],
        "winner": {
            "horse_id": "hs_x73ps4xh",
            "horse": "Af Saqara",
            "jockey_id": "jk_xr618k8m",
            "jockey": "Bernardo Pinheiro",
            "trainer_id": "tr_j3qtz590",
            "trainer": "Ernst Oertel"
        },
        "winner_price": {
            "price": "7/1",
            "decimal": 8,
            "source": "sp"
        },
        "favourite": {
            "horse_id": "hs_ngjpqrbn",
            "horse": "Es Khairiyah",
            "position": 4
        },
        "favourite_price": {
            "price": "7/4",
            "decimal": 2.75
        },
        "rating_gap": null
    },
    "meta": {
        "request_id": "c12477664e18f0a6",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T09:26:03+00:00"
    }
}
```

### Race reports

Written accounts of UK races since 2020, with a line for every runner.

#### `GET /v1/reports` (Complete)

Search race reports. Written UK race reports since 2020.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/reports-search.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `date_from` | query | date | no | From this UK day, YYYY-MM-DD. Held to your plan's window; meta.searched says what was used. | `2026-10-29` |
| `date_to` | query | date | no | To this UK day, YYYY-MM-DD. Held to your plan's window. | `2026-10-29` |
| `course_id` | query | id | no | Our id for the course, as other answers give it (cr_ and eight characters). |  |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 25. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29):

```json
{
    "data": [],
    "meta": {
        "request_id": "cffe99c91baff1e4",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T08:11:33+00:00",
        "count": 0
    }
}
```

#### `GET /v1/reports/{race_id}` (Complete)

One race report. The written account of one race.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/race-report. MCP tool: `race_report`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `race_id` | path | id | yes | Our id for the race, as other answers give it (rc_ and eight characters). | `rc_0aa1c4st` |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29):

```json
{
    "data": {
        "race_id": "rc_0aa1c4st",
        "headline": "Af Saqara Won After 201 Days",
        "preview": "Es Khairiyah was the favourite at 7/4 in the 133.36% book, with a 26.5% fair chance, while Af Yartaad was second at 5/1. Af Saqara was third at 7/1 after 201 days off; Bassam Al Wathba and Sand Storm Aa had been away for 208 and 221 days respectively. Ernst Oertel had 1 winner from 18 runners in the previous fortnight.",
        "report": "Af Saqara returned to win at 7/1 after 201 days off; the market ranked him third and assigned him a 9.1% fair chance. Es Khairiyah, the 7/4 favourite with a 26.5% chance, finished fourth of 12. Af Marmuq was second at 10/1 and Ezzah third at 8/1. All 12 completed and no horse failed to complete, although Khattaf Wrsan has no recorded finishing position.",
        "runners": {
            "Es Khairiyah": "Es Khairiyah finished fourth of 12 at 7/4; the favourite had been assigned a 26.5% fair chance and was returning after 229 days off.",
            "Af Yartaad": "Af Yartaad, the 5/1 second favourite, finished 10th of 12 after 202 days away, with 0 wins from 1 start and 0 from 1 at Abu Dhabi.",
            "Af Saqara": "Af Saqara won at 7/1 from third in the betting, a 9.1% fair chance, on his return after 201 days off.",
            "Bassam Al Wathba": "Bassam Al Wathba finished eighth of 12 at 8/1, having had 208 days off and 0 wins from 3 starts beforehand.",
            "Ezzah": "Ezzah finished third of 12 at 8/1 and had been joint fourth in the betting before a 201-day absence.",
            "Sand Storm Aa": "Sand Storm Aa was sixth of 12 at 17/2, with 1 win from 6 starts and 221 days off beforehand.",
            "Magic Touch": "Magic Touch finished fifth of 12 at 10/1 after 208 days away, having gone off seventh in the betting with 0 wins from 2 starts.",
            "Af Marmuq": "Af Marmuq finished second of 12 at 10/1, having been seventh in the betting and returning after 208 days off.",
            "Marta De Faust": "Marta De Faust finished ninth of 12 at 14/1 after 202 days away, with 0 wins from 6 starts.",
            "Namrood": "Namrood finished 11th of 12 at 16/1, returning after 202 days with 1 win from 16 starts.",
            "Af Layth": "Af Layth was seventh of 12 at 22/1; before the off he had been away for 201 days and had 1 win from 14 starts.",
            "Khattaf Wrsan": "Khattaf Wrsan completed at 25/1 but has no recorded finishing position, having returned after 292 days off."
        },
        "written_at": "2026-10-29T14:35:51+00:00"
    },
    "meta": {
        "request_id": "226035530bb04961",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T10:49:04+00:00"
    }
}
```

### Horses

Search, records, form, breeding and every race two horses met in.

#### `GET /v1/search` (Live, Archive and Complete)

Search everything. One lookup across horses, trainers, jockeys and courses.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/search. MCP tool: `search_racing`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `q` | query | string | no | Part of a name, two letters or more. | `Star` |
| `type` | query | string | no | Only one kind of record. One of: horse, trainer, jockey, course. |  |
| `limit` | query | integer | no | How many rows in one answer, Results per type, 1 to 25. Default 10. | `5` |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "type": "horse",
            "horse_id": "hs_yct1s0c9",
            "name": "Star"
        },
        {
            "type": "horse",
            "horse_id": "hs_2da44y7h",
            "name": "Star"
        }
    ],
    "meta": {
        "request_id": "025df39c24b14b1a",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T12:19:33+00:00",
        "count": 16
    }
}
```

#### `GET /v1/horses/search` (Live, Archive and Complete)

Search horses. Horses by name.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/horses-search.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `q` | query | string | no | Part of a name, two letters or more. | `Star` |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 25. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "horse_id": "hs_yct1s0c9",
            "name": "Star",
            "sex": "g",
            "colour": null,
            "career": {
                "runs": 2,
                "wins": 0,
                "seconds": 0,
                "thirds": 0,
                "casualties": 0,
                "win_pct": 0,
                "first_run": "2021-11-16",
                "last_run": "2021-12-20"
            }
        },
        {
            "horse_id": "hs_2da44y7h",
            "name": "Star",
            "sex": "g",
            "colour": "b",
            "career": {
                "runs": 5,
                "wins": 0,
                "seconds": 0,
                "thirds": 0,
                "casualties": 0,
                "win_pct": 0,
                "first_run": "2022-09-26",
                "last_run": "2023-06-09"
            }
        }
    ],
    "meta": {
        "request_id": "540652b2feefd55f",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:26:32+00:00",
        "count": 5
    }
}
```

#### `GET /v1/horses/compare` (Live, Archive and Complete)

Compare horses. Every race two to five horses met in.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/horses-compare.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `ids` | query | ids | no | Two to five horse ids, comma separated. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/horses/{horse_id}` (Live, Archive and Complete)

One horse. A horse's record and breeding.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/horse.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `horse_id` | path | id | yes | Our id for the horse, as other answers give it (hs_ and eight characters). |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/horses/{horse_id}/form` (Live, Archive and Complete)

A horse's form. A horse's UK runs, newest first.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/horse-form. MCP tool: `horse_form`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `horse_id` | path | id | yes | Our id for the horse, as other answers give it (hs_ and eight characters). |  |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 20. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/horses/{horse_id}/pedigree` (Live, Archive and Complete)

A horse's pedigree. Sire, dam, damsire and others by the sire.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/horse-pedigree.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `horse_id` | path | id | yes | Our id for the horse, as other answers give it (hs_ and eight characters). |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

### Trainers, jockeys and owners

Search, profiles and form for the people behind every runner.

#### `GET /v1/trainers/search` (Live, Archive and Complete)

Search trainers. Trainers by name.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/trainers-search.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `q` | query | string | no | Part of a name, two letters or more. | `King` |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 25. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "trainer_id": "tr_zjh5aqvh",
            "name": "King Leatherbury"
        },
        {
            "trainer_id": "tr_5mrcnmbb",
            "name": "Kingston"
        }
    ],
    "meta": {
        "request_id": "ead33a190e731b4d",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T04:25:05+00:00",
        "count": 5
    }
}
```

#### `GET /v1/trainers/{trainer_id}` (Live, Archive and Complete)

One trainer. A trainer's runners, wins and horses.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/trainer.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `trainer_id` | path | id | yes | Our id for the trainer, as other answers give it (tr_ and eight characters). |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/trainers/{trainer_id}/form` (Live, Archive and Complete)

A trainer's form. A trainer's UK runners, newest first.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/trainer-form.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `trainer_id` | path | id | yes | Our id for the trainer, as other answers give it (tr_ and eight characters). |  |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 20. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/jockeys/search` (Live, Archive and Complete)

Search jockeys. Jockeys by name.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/jockeys-search.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `q` | query | string | no | Part of a name, two letters or more. | `Moore` |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 25. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29, trimmed):

```json
{
    "data": [
        {
            "jockey_id": "jk_st6bzh4s",
            "name": "Andrew Moore"
        },
        {
            "jockey_id": "jk_6647p5pw",
            "name": "Andy Moore"
        }
    ],
    "meta": {
        "request_id": "2794656568b22f9c",
        "plan": "complete",
        "window": "January 2017 to the next 3 days",
        "data_as_of": "2026-10-30T11:23:03+00:00",
        "count": 5
    }
}
```

#### `GET /v1/jockeys/{jockey_id}` (Live, Archive and Complete)

One jockey. A jockey's rides and wins.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/jockey.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `jockey_id` | path | id | yes | Our id for the jockey, as other answers give it (jk_ and eight characters). |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/jockeys/{jockey_id}/form` (Live, Archive and Complete)

A jockey's form. A jockey's UK rides, newest first.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/jockey-form.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `jockey_id` | path | id | yes | Our id for the jockey, as other answers give it (jk_ and eight characters). |  |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 20. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `outside_plan_window` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/owners/search` (Live, Archive and Complete)

Search owners. Owners by name.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/owners-search.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `q` | query | string | no | Part of a name, two letters or more. | `Racing` |
| `limit` | query | integer | no | How many rows in one answer, 1 to 100. Default 25. | `5` |
| `cursor` | query | string | no | next_cursor from the previous answer, to read the next rows. Never build one. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/owners/{owner_id}` (Live, Archive and Complete)

One owner. An owner's runners, trainers and horses.

Plans: Live, Archive and Complete. Page: https://horseracingapi.co.uk/documentation/owner.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `owner_id` | path | id | yes | Our id for the owner, as other answers give it (ow_ and eight characters). |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

### Statistics

Strike rate, A/E and level stakes, by course, rider, yard and more.

#### `GET /v1/trainers/{trainer_id}/stats` (Complete)

A trainer's statistics. Strike rate, A/E and level stakes, by any dimension.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/trainer-stats. MCP tool: `trainer_stats`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `trainer_id` | path | id | yes | Our id for the trainer, as other answers give it (tr_ and eight characters). |  |
| `by` | query | string | no | How to split the figures. Leave it out for the totals. One of: course, region, run_type, distance, going, surface, class, year, month, draw, field_size, layoff, sp_band, jockey, owner, sire. | `course` |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/trainers/{trainer_id}/courses` (Complete)

A trainer by course. A trainer's record by UK course.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/trainer-courses.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `trainer_id` | path | id | yes | Our id for the trainer, as other answers give it (tr_ and eight characters). |  |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/trainers/{trainer_id}/jockeys` (Complete)

A trainer's jockeys. Which riders have paid for the yard.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/trainer-jockeys.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `trainer_id` | path | id | yes | Our id for the trainer, as other answers give it (tr_ and eight characters). |  |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/jockeys/{jockey_id}/stats` (Complete)

A jockey's statistics. A jockey's strike rate and A/E, by any dimension.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/jockey-stats. MCP tool: `jockey_stats`.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `jockey_id` | path | id | yes | Our id for the jockey, as other answers give it (jk_ and eight characters). |  |
| `by` | query | string | no | How to split the figures. Leave it out for the totals. One of: course, region, run_type, distance, going, surface, class, year, month, draw, field_size, layoff, sp_band, trainer, owner, sire. | `course` |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/jockeys/{jockey_id}/trainers` (Complete)

A jockey's trainers. Which yards a rider does well for.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/jockey-trainers.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `jockey_id` | path | id | yes | Our id for the jockey, as other answers give it (jk_ and eight characters). |  |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/owners/{owner_id}/stats` (Complete)

An owner's statistics. An owner's strike rate and A/E, by any dimension.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/owner-stats.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `owner_id` | path | id | yes | Our id for the owner, as other answers give it (ow_ and eight characters). |  |
| `by` | query | string | no | How to split the figures. Leave it out for the totals. One of: course, region, run_type, distance, going, surface, class, year, month, draw, field_size, layoff, sp_band, trainer, jockey, sire. | `course` |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/owners/{owner_id}/courses` (Complete)

An owner by course. Where the colours have done well.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/owner-courses.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `owner_id` | path | id | yes | Our id for the owner, as other answers give it (ow_ and eight characters). |  |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

#### `GET /v1/owners/{owner_id}/jockeys` (Complete)

An owner's jockeys. Riders used, and how they paid.

Plans: Complete. Page: https://horseracingapi.co.uk/documentation/owner-jockeys.

| Parameter | In | Type | Required | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `owner_id` | path | id | yes | Our id for the owner, as other answers give it (ow_ and eight characters). |  |
| `min_runs` | query | integer | no | Only rows with at least this many runs. Thirty or more before you act on a figure. Default 1. |  |

Errors: `unauthorized` (401), `upgrade_required` (403), `bad_request` (400), `unknown_parameter` (422), `not_found` (404), `rate_limited` (429), `quota_exceeded` (429).

### Your key

What your key reads and how much it has used.

#### `GET /v1/usage`

Your usage. Your plan, window and calls used.

Plans: Every plan, free key included. Page: https://horseracingapi.co.uk/documentation/usage.

Errors: `unauthorized` (401), `unknown_parameter` (422), `rate_limited` (429), `quota_exceeded` (429).

Sample answer (2026-10-29):

```json
{
    "data": {
        "plan": "complete",
        "plan_name": "Complete",
        "window": {
            "from": "2017-01-01",
            "to": "2026-11-02",
            "words": "January 2017 to the next 3 days"
        },
        "calls_today": 214,
        "calls_this_month": 18410,
        "per_minute": 180,
        "per_month": 400000,
        "resets": "2026-11-01",
        "house_key": false
    },
    "meta": {
        "request_id": "ff8b7aad6fe5ff6a",
        "plan": "complete",
        "window": "January 2017 to the next 3 days"
    }
}
```

## MCP server

Address: https://horseracingapi.co.uk/mcp. Every tool calls the API with the caller's own key, so plans and limits apply.

| Tool | What it does | Calls |
| --- | --- | --- |
| `list_courses` | Every British and Northern Irish course, with where it is and which way round it runs. | `GET /v1/courses` |
| `course_details` | One course in full: what is raced there and over which distances. | `GET /v1/courses/{course_id}` |
| `todays_racecards` | Today's UK cards, every meeting and race in the order they are due off. | `GET /v1/racecards/today` |
| `racecards_for_date` | The full UK card for one day, with results where the races are settled. | `GET /v1/racecards/{date}` |
| `results_for_date` | Every settled UK race on a day: finishing order, starting prices and the rest. | `GET /v1/results/{date}` |
| `race_details` | One race: its conditions, the market and every runner. | `GET /v1/races/{race_id}` |
| `race_market` | A race's market: the book, every price and what moved. | `GET /v1/races/{race_id}/market` |
| `search_races` | Find UK races by date, course, type, going, class and field size. | `GET /v1/races/search` |
| `search_racing` | Look up a horse, trainer, jockey or course by name and get its id. | `GET /v1/search` |
| `horse_form` | A horse's UK runs, newest first. | `GET /v1/horses/{horse_id}/form` |
| `trainer_stats` | A trainer's strike rate, A/E and level stakes, split any way. | `GET /v1/trainers/{trainer_id}/stats` |
| `jockey_stats` | A jockey's strike rate, A/E and level stakes, split any way. | `GET /v1/jockeys/{jockey_id}/stats` |
| `race_report` | The written account of one race, with a line for every runner. | `GET /v1/reports/{race_id}` |
| `days_upsets` | The day's UK shocks, each scored 0 to 100 with the reasons. | `GET /v1/upsets` |

## Guides

### Quick start

A key, your first call and how to read the answer, in two minutes. https://horseracingapi.co.uk/documentation/quick-start

The API answers on `https://api.horseracingapi.co.uk/v1`. Every answer is JSON, every call is a GET, and every call carries your key in a header.

#### 1. Get a key

Sign in with Google on the [free key page](https://horseracingapi.co.uk/free-key). Your key appears straight away on the free plan, which reads yesterday's UK racing. It is kept in this browser too, so Run works on every page of these docs.

#### 2. Make a call

Yesterday's results are the first call most people make, and every plan reads them.

```
curl https://api.horseracingapi.co.uk/v1/results/yesterday \
  -H "X-API-Key: $HRUK_KEY"
```

#### 3. Read the answer

Every answer has two parts. `data` is the record, or a list of them. `meta` says which plan answered, the days it reads, when the data was last brought up to date and, for lists, how many rows came back.

```
{
  "data": [ { "race_id": "rc_...", "course": "...", "race_time": "13:20" } ],
  "meta": { "request_id": "...", "plan": "free", "window": "yesterday only", "count": 31 }
}
```

#### What it is, and is not

Factual racing data for Great Britain and Northern Ireland: courses, cards, results, prices, reports and the people behind every runner. There are no tips, ratings or predictions on any endpoint, no sectional times and no live bookmaker feed.

#### Ids

Every id is ours: `cr_` courses, `mt_` meetings, `rc_` races, `hs_` horses, `tr_` trainers, `jk_` jockeys and `ow_` owners, each with eight characters. They are stable and safe to store. Take them from answers; an id that is not ours is a 404.

#### Next

- [Authentication](https://horseracingapi.co.uk/documentation/authentication): the two headers, and rotating your key.
- [Plans and limits](https://horseracingapi.co.uk/documentation/plans-and-limits): what each plan reads.
- [Racecards and results](https://horseracingapi.co.uk/documentation/racecards-and-results): the calls most products are built on.

### Authentication

Your key, the two headers that carry it, and rotating it. https://horseracingapi.co.uk/documentation/authentication

Every call needs your key. Send it in one of two headers:

```
X-API-Key: hruk_live_...
Authorization: Bearer hruk_live_...
```

A key in the address (`?key=` or `?api_key=`) is refused with a 400 `bad_request`, so keys never end up in logs and browser histories.

#### One key, following your plan

Your account has one key. The plan is read from your account on every call, so an upgrade reaches further on your very next call with the same key.

#### Rotating

Rotate makes a new key on your [account page](https://horseracingapi.co.uk/account). The old key keeps working for 24 hours, so a deploy is never broken mid-day. The new key is shown once; it is also kept in this browser for these docs.

#### In the browser

The API answers this site's own pages from the browser. For your own front end, call the API from your server so the key stays private.

### Plans and limits

What each plan reads, its rate limit and its monthly calls. https://horseracingapi.co.uk/documentation/plans-and-limits

Plans differ in the days they read and how many calls they make. Every plan returns the same fields.

| Plan | Price | Reads | Per minute | Per month |
| --- | --- | --- | --- | --- |
| Free key | Free | yesterday only | 60 | 50 |
| Live | £35 a month, £350 a year | today and the next 3 days | 180 | 250,000 |
| Archive | £60 a month, £600 a year | January 2017 to yesterday | 90 | 150,000 |
| Complete | £89 a month, £890 a year | January 2017 to the next 3 days | 180 | 400,000 |

Annual plans cost ten months. Prices are in pounds. Race reports and statistics are on Complete.

#### The free key

The free key reads yesterday's UK racing, by each course's own day. Prices (starting prices, the market and dividends) come back as `null` with a note in `meta`: the fields stay, so nothing breaks when you upgrade.

#### Rate limits

Every answer carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (Unix seconds), and `X-Quota-Remaining` for the month. Too many calls in a minute is a 429 `rate_limited` with `Retry-After`; the month used up is a 429 `quota_exceeded` saying when it resets.

#### Checking your key

[`GET /v1/usage`](https://horseracingapi.co.uk/documentation/usage) gives your plan, its window and the calls used today and this month. It does not count against your calls.

Compare the plans on the [pricing page](https://horseracingapi.co.uk/pricing).

### Pagination

Reading long lists a page at a time with limit and next_cursor. https://horseracingapi.co.uk/documentation/pagination

Long lists come back a page at a time. Set the page size with `limit`. When there is more, `meta.has_more` is true and `meta.next_cursor` holds where to carry on.

#### The loop

1. Make the call with your parameters.
2. Keep the rows.
3. While `meta.has_more` is true, make the same call with every other parameter the same and `cursor` set to `meta.next_cursor`.

```
import requests
url = "https://api.horseracingapi.co.uk/v1/races/search"
params = {"date_from": "2026-10-01", "date_to": "2026-10-07", "limit": 200}
rows = []
while True:
    r = requests.get(url, params=params, headers={"X-API-Key": KEY}).json()
    rows += r["data"]
    if not r["meta"].get("has_more"):
        break
    params["cursor"] = r["meta"]["next_cursor"]
```

A cursor is sealed. Never build or change one: anything that is not a cursor we gave is a 400 `bad_request`.

### Errors

Every error code, what it means and what to do. https://horseracingapi.co.uk/documentation/errors

An error answer has an `error` object in place of `data`. Branch on `code`, which never changes; `message` is for people.

```
{
  "error": {
    "code": "outside_plan_window",
    "message": "That date is outside what your plan reads (yesterday only).",
    "plan": "free",
    "request_id": "8c1f0a2b9d3e4f51",
    "docs": "https://horseracingapi.co.uk/documentation/errors"
  }
}
```

| Code | Status | Means | What to do |
| --- | --- | --- | --- |
| `bad_request` | 400 | A value is the wrong shape: a date that is not YYYY-MM-DD, a cursor that is not ours, or a key sent in the address. | Fix the value the message names and send it again. |
| `unauthorized` | 401 | No key was sent, or the key is not one of ours. | Send your key in X-API-Key or as Authorization: Bearer. Copy it again from your account. |
| `upgrade_required` | 403 | Your plan does not reach this endpoint. The answer names the plans that do. | Choose a plan that has it on the pricing page; the same key reaches further at once. |
| `outside_plan_window` | 403 | The day asked for is outside what your plan reads. The answer gives your window and the day you asked for. | Ask for a day inside your window, or move to a plan that reads it. |
| `not_found` | 404 | No record has that id, or it is not British or Northern Irish racing. | Take ids from other answers; never build one. |
| `unknown_parameter` | 422 | A parameter this endpoint does not take. The answer lists the ones it does. | Remove it, or check its spelling against the list. |
| `rate_limited` | 429 | Too many calls this minute for your plan. | Wait for the seconds in Retry-After, then carry on at a steadier pace. |
| `quota_exceeded` | 429 | Your plan's calls for the month are used. The answer says when they reset. | Wait for the 1st (UTC), or move to a plan with more calls. |
| `server_error` | 503 | The data is not available just now. | Try again in a minute. It is logged and looked at. |

A 403 is never temporary: retrying it only uses calls. An empty list is not an error; it is a 200 with `meta.count` 0. Quote `request_id` when you [ask for help](https://horseracingapi.co.uk/support).

### Courses

Every UK course: where it is, which way round, what it races and its fixtures. https://horseracingapi.co.uk/documentation/courses

Every racecourse in England, Scotland, Wales and Northern Ireland, with its town, county, nation and position, which way round it runs and the kinds of racing it holds.

- [`GET /v1/courses`](https://horseracingapi.co.uk/documentation/courses-list): Every UK course, busiest first.
- [`GET /v1/courses/{course_id}`](https://horseracingapi.co.uk/documentation/course): One course: what is raced there and the distances.
- [`GET /v1/courses/{course_id}/fixtures`](https://horseracingapi.co.uk/documentation/course-fixtures): The meetings ahead at one course.

#### How it links

A course's `course_id` is the one every card, result and search uses. Pass it as `course` on the racecards, or `course_id` on race and report searches.

#### Common jobs

- A map of UK courses: [`GET /v1/courses`](https://horseracingapi.co.uk/documentation/courses-list) gives every course with `lat` and `lng`.
- A course page: [`GET /v1/courses/{course_id}`](https://horseracingapi.co.uk/documentation/course), then its next meetings from [`GET /v1/courses/{course_id}/fixtures`](https://horseracingapi.co.uk/documentation/course-fixtures).
- Every race run at a course in a season: [`GET /v1/races/search`](https://horseracingapi.co.uk/documentation/races-search) with `course_id`, `date_from` and `date_to`.

### Racecards and results

Meetings, cards and results by day, and how race times work. https://horseracingapi.co.uk/documentation/racecards-and-results

The day's racing in three shapes: meetings (one row per course per day, with going and weather), racecards (every race and runner) and results (settled races, with finishing order and starting prices).

- [`GET /v1/meetings/calendar`](https://horseracingapi.co.uk/documentation/meetings-calendar): Thirty days back and the week ahead, one row per UK course per day.
- [`GET /v1/meetings/{date}`](https://horseracingapi.co.uk/documentation/meetings-by-date): Every UK meeting on a date, with going and weather.
- [`GET /v1/meetings/{meeting_id}`](https://horseracingapi.co.uk/documentation/meeting): One meeting and every race on it.
- [`GET /v1/racecards/today`](https://horseracingapi.co.uk/documentation/racecards-today): Today's UK cards, grouped by meeting.
- [`GET /v1/racecards/upcoming`](https://horseracingapi.co.uk/documentation/racecards-upcoming): Declarations for the next few days.
- [`GET /v1/racecards/{date}`](https://horseracingapi.co.uk/documentation/racecards-by-date): The full UK card for any date.
- [`GET /v1/results/latest`](https://horseracingapi.co.uk/documentation/results-latest): The latest settled UK races your plan can read.
- [`GET /v1/results/yesterday`](https://horseracingapi.co.uk/documentation/results-yesterday): Every settled UK race from yesterday.
- [`GET /v1/results/{date}`](https://horseracingapi.co.uk/documentation/results-by-date): Settled UK races for a date.

#### Days and times

A date is the course's own racing day, `YYYY-MM-DD`. A race time is the racecourse clock. Every other time is UTC.

#### How it links

Each meeting has a `meeting_id` and each race a `race_id`: pass a race id to the race endpoints for its market, result and dividends.

#### Common jobs

- Today's cards on your site: [`GET /v1/racecards/today`](https://horseracingapi.co.uk/documentation/racecards-today), refreshed every couple of minutes on race days.
- Yesterday's results every morning: [`GET /v1/results/yesterday`](https://horseracingapi.co.uk/documentation/results-yesterday), on every plan.
- A month's fixtures: [`GET /v1/meetings/calendar`](https://horseracingapi.co.uk/documentation/meetings-calendar).
- Any day since 2017: [`GET /v1/racecards/{date}`](https://horseracingapi.co.uk/documentation/racecards-by-date) or [`GET /v1/results/{date}`](https://horseracingapi.co.uk/documentation/results-by-date) on Archive and Complete.

### Races and markets

One race in full, its market and moves, dividends and upsets. https://horseracingapi.co.uk/documentation/races-and-markets

Everything about one race: its conditions, the field, the result with beaten distances and casualties, the market with every price and move, and the tote.

- [`GET /v1/races/search`](https://horseracingapi.co.uk/documentation/races-search): UK races by date, course, type, going, class and field size.
- [`GET /v1/races/{race_id}`](https://horseracingapi.co.uk/documentation/race): One race: conditions, the market and every runner.
- [`GET /v1/races/{race_id}/runners`](https://horseracingapi.co.uk/documentation/race-runners): The field alone.
- [`GET /v1/races/{race_id}/result`](https://horseracingapi.co.uk/documentation/race-result): Finishing order, casualties, dividends and prize money.
- [`GET /v1/races/{race_id}/market`](https://horseracingapi.co.uk/documentation/race-market): Book percentage, every price and what moved.
- [`GET /v1/races/{race_id}/dividends`](https://horseracingapi.co.uk/documentation/race-dividends): Tote returns and prizes.
- [`GET /v1/races/{race_id}/analysis`](https://horseracingapi.co.uk/documentation/race-analysis): Market shape and what the course and distance usually produce.
- [`GET /v1/upsets`](https://horseracingapi.co.uk/documentation/upsets): The day's UK shocks, scored 0 to 100.
- [`GET /v1/upsets/{race_id}`](https://horseracingapi.co.uk/documentation/race-upset): One race judged by the upset rules.

#### Prices

Starting prices come fractional (`sp`) and decimal (`sp_decimal`), with the chance each implies. `book_percentage` is the whole market added up. On the free key every price is `null`.

#### Upsets

[`GET /v1/upsets`](https://horseracingapi.co.uk/documentation/upsets) scores each day's shocks 0 to 100 and says why, in plain words. It is history, never a prediction.

#### Common jobs

- A race page: [`GET /v1/races/{race_id}`](https://horseracingapi.co.uk/documentation/race).
- How the market moved: [`GET /v1/races/{race_id}/market`](https://horseracingapi.co.uk/documentation/race-market).
- Every handicap chase on soft ground in a season: [`GET /v1/races/search`](https://horseracingapi.co.uk/documentation/races-search) with `run_type=Chase`, `handicap=true` and `going`.

### Race reports

Written accounts of UK races since 2020, on Complete. https://horseracingapi.co.uk/documentation/race-reports

A written account of how each race was run, with a line for every runner. Reports start in 2020 and are on Complete.

- [`GET /v1/reports`](https://horseracingapi.co.uk/documentation/reports-search): Written UK race reports since 2020.
- [`GET /v1/reports/{race_id}`](https://horseracingapi.co.uk/documentation/race-report): The written account of one race.

#### Common jobs

- The story under a result: [`GET /v1/reports/{race_id}`](https://horseracingapi.co.uk/documentation/race-report) with the same race id.
- Every report from a course in a month: [`GET /v1/reports`](https://horseracingapi.co.uk/documentation/reports-search) with `course_id`, `date_from` and `date_to`.

### Horses

Finding a horse, its record, form, breeding and head to heads. https://horseracingapi.co.uk/documentation/horses

Every horse that has run in Britain or Northern Ireland since 2017: its record, its UK runs and its breeding.

- [`GET /v1/search`](https://horseracingapi.co.uk/documentation/search): One lookup across horses, trainers, jockeys and courses.
- [`GET /v1/horses/search`](https://horseracingapi.co.uk/documentation/horses-search): Horses by name.
- [`GET /v1/horses/compare`](https://horseracingapi.co.uk/documentation/horses-compare): Every race two to five horses met in.
- [`GET /v1/horses/{horse_id}`](https://horseracingapi.co.uk/documentation/horse): A horse's record and breeding.
- [`GET /v1/horses/{horse_id}/form`](https://horseracingapi.co.uk/documentation/horse-form): A horse's UK runs, newest first.
- [`GET /v1/horses/{horse_id}/pedigree`](https://horseracingapi.co.uk/documentation/horse-pedigree): Sire, dam, damsire and others by the sire.

#### Common jobs

- From a name to an id: [`GET /v1/horses/search`](https://horseracingapi.co.uk/documentation/horses-search) or [`GET /v1/search`](https://horseracingapi.co.uk/documentation/search).
- A form guide: [`GET /v1/horses/{horse_id}/form`](https://horseracingapi.co.uk/documentation/horse-form), newest first, with the days between runs.
- Who beat whom: [`GET /v1/horses/compare`](https://horseracingapi.co.uk/documentation/horses-compare) with two to five horse ids.

### Trainers, jockeys and owners

Search, profiles and form for the people behind every runner. https://horseracingapi.co.uk/documentation/trainers-jockeys-and-owners

The yards, riders and owners behind every UK runner, each with a profile and their UK form.

- [`GET /v1/trainers/search`](https://horseracingapi.co.uk/documentation/trainers-search): Trainers by name.
- [`GET /v1/trainers/{trainer_id}`](https://horseracingapi.co.uk/documentation/trainer): A trainer's runners, wins and horses.
- [`GET /v1/trainers/{trainer_id}/form`](https://horseracingapi.co.uk/documentation/trainer-form): A trainer's UK runners, newest first.
- [`GET /v1/jockeys/search`](https://horseracingapi.co.uk/documentation/jockeys-search): Jockeys by name.
- [`GET /v1/jockeys/{jockey_id}`](https://horseracingapi.co.uk/documentation/jockey): A jockey's rides and wins.
- [`GET /v1/jockeys/{jockey_id}/form`](https://horseracingapi.co.uk/documentation/jockey-form): A jockey's UK rides, newest first.
- [`GET /v1/owners/search`](https://horseracingapi.co.uk/documentation/owners-search): Owners by name.
- [`GET /v1/owners/{owner_id}`](https://horseracingapi.co.uk/documentation/owner): An owner's runners, trainers and horses.

#### How it links

Every runner carries `trainer_id`, `jockey_id` and `owner_id`, the same ids these endpoints take.

#### Common jobs

- A trainer page: [`GET /v1/trainers/{trainer_id}`](https://horseracingapi.co.uk/documentation/trainer) and [`GET /v1/trainers/{trainer_id}/form`](https://horseracingapi.co.uk/documentation/trainer-form).
- Who rides most for a yard: [`GET /v1/trainers/{trainer_id}/jockeys`](https://horseracingapi.co.uk/documentation/trainer-jockeys) on Complete.

### Statistics

Strike rate, A/E and level stakes, split by course, going, rider and more, on Complete. https://horseracingapi.co.uk/documentation/statistics

How trainers, jockeys and owners have done in UK racing, with the figures people judge them by: runs, wins, places, strike rate, actual over expected (A/E) and level stakes to a one-pound stake at SP. They are on Complete.

- [`GET /v1/trainers/{trainer_id}/stats`](https://horseracingapi.co.uk/documentation/trainer-stats): Strike rate, A/E and level stakes, by any dimension.
- [`GET /v1/trainers/{trainer_id}/courses`](https://horseracingapi.co.uk/documentation/trainer-courses): A trainer's record by UK course.
- [`GET /v1/trainers/{trainer_id}/jockeys`](https://horseracingapi.co.uk/documentation/trainer-jockeys): Which riders have paid for the yard.
- [`GET /v1/jockeys/{jockey_id}/stats`](https://horseracingapi.co.uk/documentation/jockey-stats): A jockey's strike rate and A/E, by any dimension.
- [`GET /v1/jockeys/{jockey_id}/trainers`](https://horseracingapi.co.uk/documentation/jockey-trainers): Which yards a rider does well for.
- [`GET /v1/owners/{owner_id}/stats`](https://horseracingapi.co.uk/documentation/owner-stats): An owner's strike rate and A/E, by any dimension.
- [`GET /v1/owners/{owner_id}/courses`](https://horseracingapi.co.uk/documentation/owner-courses): Where the colours have done well.
- [`GET /v1/owners/{owner_id}/jockeys`](https://horseracingapi.co.uk/documentation/owner-jockeys): Riders used, and how they paid.

#### Splitting the figures

The stats endpoints take `by`: course, region, run_type, distance, going, surface, class, year, month, draw, field_size, layoff, sp_band, sire, and the other people (a trainer splits by jockey or owner, a jockey by trainer or owner, an owner by trainer or jockey).

#### Reading them

A/E above 1 means more winners than the starting prices expected. Small samples lie: set `min_runs` to 30 or more before acting on a figure, and look at `low_sample`.

### MCP server

Add the API to Claude, ChatGPT, Cursor or Claude Code and ask in plain English. https://horseracingapi.co.uk/documentation/mcp

The MCP server puts the API in front of an assistant as tools. Ask "what runs at Cheltenham today?" and it calls the right endpoint with your key.

#### The address

```
https://horseracingapi.co.uk/mcp
```

#### Adding it

- Claude and ChatGPT: add a custom connector with the address above. You sign in and allow it once; it uses your own key and plan.
- Claude Code: `claude mcp add --transport http horseracingapi https://horseracingapi.co.uk/mcp --header "X-API-Key: YOUR_KEY"`
- Cursor and other clients: the same address, with your key in the `X-API-Key` header.

#### An example

Asked "who won the big handicap at Musselburgh yesterday, and how did the market move?", the assistant calls `results_for_date`, picks the race, then calls `race_market` with its id, and answers with the winner, the starting price and the move.

#### Plans

Every tool calls the API with your key, so your plan's window and limits apply. A tool your plan does not reach says which plan has it.

Every tool is on the [MCP tools page](https://horseracingapi.co.uk/documentation/mcp-tools). Teach an agent the whole API with the [agent skill](https://horseracingapi.co.uk/documentation/agent-skill).

### Agent skill

One file that teaches an AI agent to use the API well. https://horseracingapi.co.uk/documentation/agent-skill

The skill is one markdown file that tells an agent what the API is for, how to get a key, which calls answer the common questions, the limits and the errors.

- [Download skill.md](https://horseracingapi.co.uk/skill.md)
- Discovery index: [/.well-known/agent-skills/index.json](https://horseracingapi.co.uk/.well-known/agent-skills/index.json)

#### Adding it

In Claude Code, save it as `~/.claude/skills/horseracingapi-uk/SKILL.md`. In Claude, upload it as a skill in Settings. Other agents read it from the address above.

For the whole API in one file, give your assistant the [manual](https://horseracingapi.co.uk/documentation/manual.md).

### Changelog

What changed, newest first. https://horseracingapi.co.uk/documentation/changelog

The API keeps to one rule in v1: fields are only ever added, never renamed or removed.

- 2026-10-29: MCP server at /mcp: 14 tools for Claude, ChatGPT, Cursor and Claude Code, with sign-in for the connectors.
- 2026-10-29: Documentation published: a page for every endpoint and guide, the manual, llms.txt, the agent skill and OpenAPI.
- 2026-10-29: The first 46 endpoints: courses, cards and results, races and markets, race reports, horses, trainers, jockeys and owners, and statistics.

## Errors

An error answer is `{"error": {"code", "message", "request_id", "docs"}}`, with `plan` and more where they help. Branch on `code`. Every code: https://horseracingapi.co.uk/documentation/errors

## About this document

Generated from the endpoint registry, the guides and the plan configuration; it is never edited by hand. The Generated date above is the newest change to those sources, so it tells a stale copy from a current one. Machine-readable alternatives: https://horseracingapi.co.uk/openapi.json, https://horseracingapi.co.uk/postman-collection.json and https://horseracingapi.co.uk/mcp. The agent skill: https://horseracingapi.co.uk/skill.md.
