APIHorseRacing

Documentation / Guides

Authentication

One key, two ways to send it, and what a refusal looks like.

One key

One account, one key, and it never needs replacing. Your entitlement is read from your plan on every single request, so upgrading widens what the key you already hold can reach. There is nothing to reissue and nothing to re-integrate.

That is a deliberate choice. Most APIs make you rotate keys to change plan, which means a plan change is a deployment. Here it is a database read.

Two ways to send it

The header, which you should use

curl https://api.apihorseracing.com/v1/countries \
  -H "X-API-Key: ahr_..."

The query string, which exists for tools that cannot set headers

curl "https://api.apihorseracing.com/v1/countries?key=ahr_..."

The second one is convenient for a spreadsheet, a browser tab or a quick look. It is also worse everywhere else: a key in a URL ends up in server logs, browser history, referer headers and anything the link is pasted into. Use the header unless you cannot.

What a refusal looks like

Three different things can go wrong with a key, and they are three different responses on purpose.

StatusCodeMeans
401unauthorized No key, or one we do not recognise. Check the header name and that the key has not been rotated.
403upgrade_required The key is valid; the plan does not reach this endpoint. The body names every plan that does.
403outside_window The key is valid and the endpoint is allowed; the date is outside what your plan reads. The body names the window and the date you asked for.

None of those is transient. Retrying will produce the same answer, and a client that retries a 403 on a backoff is just burning its own quota.

{
  "error": {
    "code": "upgrade_required",
    "message": "Your plan does not reach this endpoint.",
    "your_plan": "complete",
    "reaches_on": ["analyst"],
    "doc_url": "https://apihorseracing.com/documentation/trainers-stats"
  }
}

Keeping it safe

  • Never put it in client-side code. Anything shipped to a browser is public. Proxy through your own server.
  • Never commit it. Environment variable, secrets manager, anything but a repository.
  • Do not share it across organisations. Usage counts against your quota whoever made the request.
  • If it leaks, rotate it from your account page. The new key works immediately and the old one stops immediately, so plan the swap before you press it.

We will never ask you for your key. If you are reporting a problem, send the request_id instead: it identifies the request without identifying the credential.