GET /races#
Version générique : tous les champs sont listés avec la formule minimale qui y donne accès (FREE, PRO, PARTNER). Envoyez votre clé API (
Authorization: Bearer th_live_…) ou connectez-vous à votre espace développeur pour obtenir la version personnalisée.
GET https://dev.trailhorizon.fr/api/v1/races
Liste des courses publiées, paginée par curseur. Tri sur id, pagination par curseur.
Paramètres#
| Paramètre | Emplacement | Type | Requis | Description |
|---|---|---|---|---|
cursor | query | string | non | Curseur renvoyé par la page précédente (nextCursor). |
limit | query | integer | non | Taille de page, de 1 à la taille maximale de votre formule. Défaut : 50. |
country | query | string | non | Slug du pays (ex. france). |
region | query | string | non | Slug de la région (ex. auvergne-rhone-alpes). |
nextEditionFrom | query | date ISO 8601 | non | Prochaine édition à partir de cette date (incluse). |
nextEditionTo | query | date ISO 8601 | non | Prochaine édition jusqu'à cette date. Une date seule (2026-12-31) inclut toute la journée. |
Un paramètre inconnu est ignoré. Une valeur invalide renvoie 422 invalid_parameter (ex. limit au-delà de la taille de page maximale, nextEditionFrom postérieur à nextEditionTo).
Pagination#
La réponse contient nextCursor et hasMore. Tant que hasMore vaut true, rappelez l'endpoint avec cursor=<nextCursor>. Le curseur est l'id de la dernière course de la page.
Réponse 200#
{
"data": [
{
"id": "clx1a2b3c0000abcd1234efgh",
"slug": "trail-des-cretes-fictives",
"name": "Trail des Crêtes Fictives",
"url": "https://dev.trailhorizon.fr/races/europe/france/auvergne-rhone-alpes/trail-des-cretes-fictives",
"nextEditionDate": "2027-06-12T00:00:00.000Z",
"lastEditionDate": "2026-06-13T00:00:00.000Z",
"firstEditionDate": "2019-06-15T00:00:00.000Z",
"updatedAt": "2026-10-20T08:30:00.000Z",
"status": "ACTIVE",
"verifiedAt": "2026-10-15T10:00:00.000Z",
"averageRating": 4.5,
"location": {
"city": "Exempleville",
"lat": 45.1234,
"lon": 6.5678,
"region": "Auvergne-Rhône-Alpes",
"country": "France",
"continent": "Europe"
},
"links": {
"website": "https://exemple.org/trail",
"registration": "https://exemple.org/trail/inscriptions",
"facebook": "https://facebook.com/exemple-trail",
"instagram": "https://instagram.com/exemple_trail",
"youtube": null
},
"images": {
"logo": "https://files.example.com/trail-des-cretes/logo.png",
"card": "https://files.example.com/trail-des-cretes/card.jpg",
"coverDesktop": "https://files.example.com/trail-des-cretes/cover-desktop.jpg",
"coverPhone": "https://files.example.com/trail-des-cretes/cover-phone.jpg"
},
"formats": [
{
"id": "clx9z8y7x0001abcd5678ijkl",
"name": "Le Grand Tour",
"type": "STANDARD",
"distance": 52.4,
"elevation": 3100,
"category": "50K",
"price": 85,
"currency": "EUR",
"startAt": "2027-06-12T05:00:00.000Z",
"hasStartTime": true,
"timezone": "Europe/Paris",
"duration": null,
"traceUrl": "https://tracedetrail.fr/trace/0000",
"registrationStatus": "NOT_YET_OPEN",
"registrationOpensAt": "2027-01-15T08:00:00.000Z",
"maxParticipants": 800,
"practicalInfo": "Matériel obligatoire : Veste imperméable, EMERGENCY_BLANKET\nDépart : Place du village\nArrivée : Place du village\nTemps limite : 14 h 0 min\nRavitaillements : Col des Exemples (km 18)",
"practicalInfoStructured": {
"requiredGear": [
{
"code": "WATERPROOF_JACKET",
"label": null,
"quantity": null
},
{
"code": "EMERGENCY_BLANKET",
"label": null,
"quantity": null
}
],
"recommendedGear": [],
"start": {
"location": "Place du village",
"details": null
},
"finish": {
"location": "Place du village",
"details": null
},
"access": null,
"timeLimit": {
"totalMinutes": 840,
"cutoffs": []
},
"aidStations": [
{
"name": "Col des Exemples",
"km": 18,
"kind": "FULL"
}
],
"kidsAgeRange": null,
"relay": null,
"stageRace": null,
"notes": null
},
"rankingTypes": [
"ITRA"
],
"tags": [
"panoramique",
"technique"
]
},
{
"id": "clx9z8y7x0002abcd5678mnop",
"name": "La Petite Boucle",
"type": "STANDARD",
"distance": 21.2,
"elevation": 1100,
"category": "20K",
"price": 38,
"currency": "EUR",
"startAt": "2027-06-12T08:30:00.000Z",
"hasStartTime": true,
"timezone": "Europe/Paris",
"duration": null,
"traceUrl": null,
"registrationStatus": "NOT_YET_OPEN",
"registrationOpensAt": "2027-01-15T08:00:00.000Z",
"maxParticipants": 400,
"practicalInfo": null,
"practicalInfoStructured": null,
"rankingTypes": [],
"tags": []
}
]
}
],
"nextCursor": "clx1a2b3c0000abcd1234efgh",
"hasMore": true
}
Les courses DISCONTINUED sont renvoyées avec leur status.
Exemple#
curl -H "Authorization: Bearer th_live_VOTRE_CLE" \
"https://dev.trailhorizon.fr/api/v1/races?country=france&limit=20"
Erreurs#
| Statut | Code | Signification |
|---|---|---|
| 401 | missing_api_key | Header Authorization absent. |
| 401 | invalid_api_key | Clé mal formée ou inconnue. |
| 401 | api_key_revoked | Clé révoquée. |
| 403 | account_suspended / account_revoked | Compte suspendu ou révoqué. |
| 403 | tos_not_accepted / tos_outdated | Conditions d'utilisation de l'API non acceptées, ou à accepter de nouveau. |
| 403 | field_not_allowed | Filtre category demandé sans accès aux champs des formats. |
| 422 | invalid_parameter | Paramètre invalide. |
| 429 | rate_limit_exceeded | Trop de requêtes dans la minute. Voir Retry-After. |
| 429 | daily_quota_exceeded | Quota journalier atteint. Voir Retry-After. |
| 500 |
L'exemple ci-dessus décrit une course fictive. Il contient tous les champs ; voir le catalogue pour les formules.

