Hyrox Result API

API documentation

Hyrox Result API is a versioned JSON HTTP API for HYROX race data: seasons, events, results, athlete search, split times, division statistics, and simulator benchmarks.

Interactive OpenAPI explorer

Try endpoints, inspect schemas, and export the contract.

Open Swagger UI

Use these docs with an LLM

Copy the full API reference as plain text (llms.txt) and paste it into ChatGPT, Claude, or Cursor to build against the API.

Quick start

  1. Register and subscribe , then create an API token under API tokens.
  2. Search for an athlete by surname and given name.
  3. Copy the race ID (id field) from a search hit.
  4. Fetch race detail and split times with that race ID.
# 1. Search
curl -sS "https://hyroxresultapi.com/api/v1/athletes/search?last=McIntyre&first=Hunter" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"

# 2. Detail (use the id field from the search response)
curl -sS "https://hyroxresultapi.com/api/v1/athletes/RACE_ID_FROM_SEARCH" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"

# 3. Splits (same race ID)
curl -sS "https://hyroxresultapi.com/api/v1/athletes/RACE_ID_FROM_SEARCH/splits" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"

Identifiers

The API returns opaque strings for athlete lookups. Pass them back exactly as received. Do not decode or construct them.

Name Where you get it Use on
Race ID id on search hits Detail, splits, and single race results
Person ref person_ref on search hits Result history and splits (not detail)
Stored athlete ID athlete_id on ingested result rows All athlete routes; optional result_id on splits
Event ID id on event resources Division results and event statistics

Base URL

Product endpoints live under /api/v1 on your deployment host. Examples use https://hyroxresultapi.com.

Authentication

Protected routes require a bearer token and an active subscription. Send both headers on every request:

Authorization: Bearer <your-token>
Accept: application/json

GET /api/user (no /v1 prefix) returns your plan and rate limit. It requires a token but not a subscription.

Rate limits

Limits apply per account based on your plan. Exceeding the limit returns 429 Too Many Requests with Retry-After and X-RateLimit-* headers.

Response format

{
  "data": …,
  "meta": { "data_source": "database" | "live", … },
  "errors": null
}

Athlete routes set meta.data_source to database (catalog) or live (on demand). Errors return errors.title, errors.detail, and errors.status.

Endpoints

Paths are relative to /api/v1 unless noted.

Public

Race calendar

Upcoming races, published months ahead. One row per race — use this to let someone pick the event they are training for. It is deliberately separate from /events, which is one row per division per day and only appears once results are staged, roughly a week before race day: Rome is a single entry here and seventeen there.

EndpointDescription
GET /races The HYROX race calendar: name, city code, country, continent, category and dates, plus a ticket link. country_code is resolved from the race venue and is null when it cannot be established yet — it is never guessed from the city code. Upcoming by default and soonest first — pass upcoming=false for the full listing. Filter with from, to, continent (europe, north-america, asia-pacific, africa, south-america), category (adults or youngstars) and country (ISO alpha-2) and city_code. A race weekend already under way still counts; races the organiser has not dated yet are omitted.
GET /events?upcoming=true The same window seen through the results catalogue: division-level rows, ordered soonest first, for races whose result pages already exist. Useful once a race is imminent; use /races to plan ahead.

Catalog

EndpointDescription
GET /seasonsList HYROX seasons. Use each slug to filter events.
GET /eventsList events. Filter by season, country, or date range.
GET /events/{slug}Single event by slug.
GET /events/{slug}/divisionsDivisions for an event. Division id equals the event id.
GET /divisions/{id}/resultsPaginated finishers with cursor support. id is the event integer ID.

Athletes

EndpointDescriptionAccepts
GET /athletes/search Search by q (surname) and first (given name). Returns race ID and person ref per hit. Query params
GET /athletes/{id} Race detail for one result. Race ID, stored athlete ID
GET /athletes/{id}/results Result history for an athlete. Person ref, race ID, stored athlete ID
GET /athletes/{id}/splits Station split times. Race ID, person ref, stored athlete ID
GET /athletes/{id}/pacing Pro plan. One race broken down: run fade from lap 1 to lap 8, lap consistency, roxzone share, and how the finish time splits across running, stations and transitions. Includes the finish-time percentile. Needs a stored split set. Race ID, stored athlete ID
GET /athletes/{id}/partners Pro plan. Doubles and relay team-mates, with a person ref for each so you can follow one into their own history. Returns is_team_entry: false for a solo race. Race ID, stored athlete ID

Stats & simulator

EndpointDescription
GET /percentilePro plan. Where one finish time ranks across the whole catalogue. Pass total_time_ms and division, optionally sex and age_group. Answers in one call what a whole finisher list would otherwise be pulled for. Cohorts widen when the exact one is too thin, and widened says so.
GET /stats/divisions/{id}Precomputed event statistics, bucketed by division × gender × age group. Per-station field medians (buckets[].splits) are Scale-only; on other plans the object is present but empty and meta.field_splits.included is false.
GET /stats/divisions/{id}/splitsScale plan. Per-station medians for a whole race field. Races from the last 14 days are harvested every night; an older race is backfilled on request (one race at a time, up to 5,000 finishers a day on Scale) and returns 202 until ready. Honour Retry-After; a 404 means nothing is on the way.
GET /simulator/benchmarksEvent-specific simulator benchmarks from stored aggregates.
GET /simulator/division-benchmarksGlobal division benchmarks by code (e.g. HYROX_MEN). Station means across all races, not one event.
GET /events/{slug}/ingest-statusHow far this event has progressed through ingestion — rankings and field splits — so you can stop polling blind after a race. Includes the division's own race day within a multi-day race weekend (race.race_date, race.phase), so an empty ranking that simply has not raced yet is distinguishable from a stalled ingest.

Admin ingestion and maintenance routes under /api/v1/admin/* are documented in OpenAPI and require an admin token.

Interactive docs

Explore and try endpoints in Swagger UI. The OpenAPI contract file is at GET /api/v1/openapi.yaml.

CORS

For browser clients, set CORS_ALLOWED_ORIGINS in .env to a comma separated list of allowed origins.