{
    "titre": "API turf.bzh v1",
    "version": "1.2.0",
    "genere_le": "2026-09-12",
    "base_url": "https://www.turf.bzh/api",
    "resume": "Acces programmatique aux donnees hippiques turf.bzh (programme, partants exacts, cotes PMU en direct, arrivees, indicateurs premium) et a ChatBZH. Reservee aux abonnes actifs titulaires de la Licence API (paiement unique). Une cle, deux usages : les endpoints DONNEES sont illimites (rate limit technique 60/min, 10 000/jour) ; POST /chat consomme les credits IA du compte. Aucune reponse ne garantit un gain : jeu responsable. Depuis le 03/08/2026 : une journee entiere de partants en un appel (/v1/journees/{date}/partants), des exports mensuels de la base entiere (/v1/exports), et un dictionnaire des champs avec leur taux de remplissage reel (/v1/schema). Depuis le 08/09/2026, chaque reponse dit ou en est votre quota : bloc meta.quota (limite_minute, restant_minute, limite_jour, restant_jour et les secondes avant chaque remise a zero) et en-tetes X-RateLimit-*.",
    "sections": [
        {
            "id": "a-lire-en-premier",
            "titre": "À lire en premier",
            "blocs": [
                {
                    "t": "p",
                    "v": "Ce document est généré automatiquement depuis le code de l'API : le contrat OpenAPI pour les adresses et leurs paramètres, le catalogue des colonnes pour les champs, et les taux de remplissage mesurés chaque nuit. Il ne peut donc pas décrire une version de l'API qui n'est pas celle en service."
                },
                {
                    "t": "liste",
                    "v": [
                        "Base des URL : https://www.turf.bzh/api",
                        "Toutes les dates s'écrivent AAAA-MM-JJ. Une date future est refusée en 422.",
                        "Toutes les réponses sont du JSON UTF-8, enveloppées dans data et meta.",
                        "Aucune réponse ne garantit un gain. Chaque taux publié porte son échantillon."
                    ]
                },
                {
                    "t": "note",
                    "v": "Pour un assistant : lisez la section des adresses pour savoir quoi appeler, puis le dictionnaire des champs pour savoir ce que vaut chaque colonne. La section des pièges évite les erreurs qui ne se voient pas."
                },
                {
                    "t": "p",
                    "v": "Acces programmatique aux donnees hippiques turf.bzh (programme, partants exacts, cotes PMU en direct, arrivees, indicateurs premium) et a ChatBZH. Reservee aux abonnes actifs titulaires de la Licence API (paiement unique). Une cle, deux usages : les endpoints DONNEES sont illimites (rate limit technique 60/min, 10 000/jour) ; POST /chat consomme les credits IA du compte. Aucune reponse ne garantit un gain : jeu responsable. Depuis le 03/08/2026 : une journee entiere de partants en un appel (/v1/journees/{date}/partants), des exports mensuels de la base entiere (/v1/exports), et un dictionnaire des champs avec leur taux de remplissage reel (/v1/schema). Depuis le 08/09/2026, chaque reponse dit ou en est votre quota : bloc meta.quota (limite_minute, restant_minute, limite_jour, restant_jour et les secondes avant chaque remise a zero) et en-tetes X-RateLimit-*."
                },
                {
                    "t": "p",
                    "v": "Version 1.1.0 (11/09/2026) : les endpoints qui servent des partants acceptent le parametre champs et rendent par defaut toutes les colonnes exploitables de la base. Seize indicateurs qui figuraient au catalogue de /v1/tops sans etre lisibles sur le partant le sont desormais, ELO_Proprio et ELO_Eleveur compris. Les colonnes ajoutees le sont a la fin, les positions d'un CSV existant ne bougent pas. Correction de documentation du meme jour : Taux_Victoire, Taux_Place et Taux_Incident sont des fractions entre 0 et 1, et non des pourcentages comme /v1/schema l'annoncait ; Taux_Place compte la victoire comme une place, alors que nombre_place ne compte que les places hors victoire."
                },
                {
                    "t": "p",
                    "v": "Version 1.2.0 (12/09/2026) : les non partants ne sont plus servis comme des partants. Un cheval declare forfait figure bien dans la base, avec Rank = NP, et les deux endpoints qui servent des partants ne le filtraient pas : 3 768 lignes et 2 741 courses sur les 8 530 mesurees du 1er janvier au 8 juin 2026, soit une course sur trois. Chaque partant porte desormais partant (booleen), statut_partant et, sur un forfait, source_statut. Chaque course porte nombre_partants_initial (le peloton engage, forfaits compris), nombre_partants_reel (ceux qui prennent le depart) et nombre_non_partants, avec leurs numeros. Ces deux nombres sont comptes ligne a ligne et non deduits de la colonne nombre_partants, qui reste servie sous le nom nombre_partants_declare : sur les courses avec forfait, elle vaut le peloton engage 85,6 % du temps et le peloton reel 10,0 % seulement, et l'ecart est signale quand il existe. Pour la journee en cours, /v1/courses/{date}/{rc} interroge le flux PMU en direct, seule source des forfaits de derniere minute ; la base, elle, ne porte que ceux declares tot. Le parametre non_partants (inclus, exclus, seuls) filtre la liste sans toucher aux comptes. Signale par un client le 11/09/2026."
                }
            ]
        },
        {
            "id": "authentification",
            "titre": "Authentification",
            "blocs": [
                {
                    "t": "p",
                    "v": "Cle personnelle tbz_live_... a generer sur https://www.turf.bzh/api-cle.php"
                },
                {
                    "t": "code",
                    "v": "curl -H \"Authorization: Bearer tbz_live_VOTRE_CLE\" \\\n  \"https://www.turf.bzh/api/v1/statut\""
                },
                {
                    "t": "liste",
                    "v": [
                        "Bearer est la forme recommandée.",
                        "L'en-tête X-Api-Key est accepté.",
                        "Le paramètre ?api_key= est toléré : pratique pour un tableur ou un navigateur, mais il laisse la clé dans les journaux.",
                        "La clé est nominative et porte votre quota : ne la partagez pas."
                    ]
                }
            ]
        },
        {
            "id": "quotas",
            "titre": "Quotas",
            "blocs": [
                {
                    "t": "p",
                    "v": "Les adresses de données sont illimitées en volume ; seules deux limites techniques s'appliquent, à la minute et à la journée. POST /v1/chat, lui, consomme les crédits IA du compte."
                },
                {
                    "t": "p",
                    "v": "Chaque réponse 200 porte un bloc meta.quota et six en-têtes X-RateLimit-* : limite et restant sur la minute, limite et restant sur la journée, et le nombre de SECONDES avant chaque remise à zéro. C'est un délai d'attente, pas un horodatage. Les mêmes valeurs accompagnent un 429, où quota rejoint retry_after et scope dans error."
                },
                {
                    "t": "note",
                    "v": "Quand le compteur est indisponible, rien n'est émis plutôt qu'un chiffre faux : testez la présence du bloc, pas sa valeur."
                }
            ]
        },
        {
            "id": "erreurs",
            "titre": "Erreurs",
            "blocs": [
                {
                    "t": "p",
                    "v": "Toute erreur rend un objet error portant code, message, status et doc. Le message est en français et dit quoi faire, pas seulement ce qui ne va pas."
                },
                {
                    "t": "tableau",
                    "entetes": [
                        "Statut",
                        "code",
                        "Ce qui s'est passe",
                        "Quoi faire"
                    ],
                    "lignes": [
                        [
                            "401",
                            "unauthorized",
                            "clé absente, mal formée ou révoquée",
                            "vérifier l'en-tête Authorization"
                        ],
                        [
                            "403",
                            "forbidden",
                            "clé valide mais droit absent (Licence API, abonnement)",
                            "vérifier l'état du compte sur /v1/me"
                        ],
                        [
                            "404",
                            "not_found",
                            "la ressource n'existe pas à cette date",
                            "la réponse liste souvent ce qui existe ce jour-là"
                        ],
                        [
                            "422",
                            "invalid_params",
                            "un paramètre est invalide",
                            "le message nomme les valeurs acceptées"
                        ],
                        [
                            "429",
                            "rate_limited",
                            "limite à la minute ou à la journée atteinte",
                            "dormir retry_after secondes, puis réessayer"
                        ],
                        [
                            "503",
                            "upstream_unavailable",
                            "source indisponible (base, flux PMU)",
                            "réessayer plus tard ; la réponse ne sert jamais une donnée à moitié vraie"
                        ]
                    ]
                },
                {
                    "t": "note",
                    "v": "Un paramètre mal écrit n'est jamais ignoré en silence : il répond 422 en nommant les valeurs acceptées. Servir autre chose que ce qui est demandé sans le dire serait pire qu'une erreur."
                }
            ]
        },
        {
            "id": "adresses",
            "titre": "Les 36 adresses",
            "blocs": [
                {
                    "t": "p",
                    "v": "Chemins relatifs à la base des URL. Les paramètres marqués requis font partie du chemin ; les autres se passent en paramètres de requête."
                }
            ],
            "routes": [
                {
                    "methode": "GET",
                    "chemin": "/v1/schema",
                    "resume": "Dictionnaire des champs et taux de remplissage",
                    "description": "Pour chaque champ servi : le nom expose, le nom en base, le type, l'unite, une description, et le taux de remplissage reel mesure sur toute la table. Sur 80 colonnes, 38 sont renseignees a 100 % et 14 le sont a moins de 65 % : Rapport_SG a 8,5 %, Cote_BZH a 50,3 %. Cinq champs changent de nom entre la base et l'API : Course devient code_course, Numero devient num, Cheval devient name, Driver devient jockey_driver, Entraineur devient trainer. A lire avant de batir une hypothese.",
                    "groupe": "Compte",
                    "parametres": [
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur."
                        }
                    ]
                },
                {
                    "methode": "POST",
                    "chemin": "/v1/chat",
                    "resume": "Poser une question a ChatBZH (consomme les credits IA du compte)",
                    "description": "Reponse synchrone (30-180 s possibles). Refus 402 AVANT l'appel si solde insuffisant ou si l'estimation depasse max_credits. Forfaits automatiques : application de methode 60 cr, backtest 100 cr.",
                    "groupe": "Donnees",
                    "parametres": []
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/chevaux",
                    "resume": "Recherche d'un cheval par nom",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "recherche",
                            "ou": "query",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "limit",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 5,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/chevaux/{id}/historique",
                    "resume": "Dernieres courses d'un cheval (max 50 par appel)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "id",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "limit",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 10,
                            "description": ""
                        },
                        {
                            "nom": "discipline",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "debut",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Borne basse de la periode, au format YYYY-MM-DD. Ajoute le 03/08/2026 : rend exprimable « ce cheval sur l'hiver 2025 », qui imposait sinon de tout tirer et de filtrer chez soi."
                        },
                        {
                            "nom": "fin",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Borne haute de la periode, au format YYYY-MM-DD. Ajoute le 03/08/2026 : rend exprimable « ce cheval sur l'hiver 2025 », qui imposait sinon de tout tirer et de filtrer chez soi."
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur : une ligne par course courue par le cheval."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/chevaux/{id}/lectures",
                    "resume": "Lectures expertes actives du jour pour un cheval",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "id",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "date",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/chevaux/{id}/renifleur",
                    "resume": "Toutes les notes du Renifleur sur un cheval",
                    "description": "L'historique des notes ecrites sur ce cheval, de la plus recente a la plus ancienne. nb_notes vaut 0 si le cheval n'a jamais ete repere sur la periode conservee, soit 400 jours. Contenu editorial exclusif turf.bzh, ce n'est PAS un signal de pari. Mesure sur 2 411 rentrees : les chevaux reperes terminent dans les trois premiers 35,9 % du temps contre 27,8 % pour l'ensemble des partants, mais a cote egale l'ecart n'est pas significatif et le retour est de 0,72 EUR pour 1 EUR joue. Chaque reponse porte un champ avertissement qui le rappelle.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "id",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "n_last",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 10,
                            "description": "Nombre de notes a retourner, 1 a 40. Defaut 10."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/chevaux/{id}/stats",
                    "resume": "Stats agregees d'un cheval",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "id",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "periode_jours",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{code_course}/rapports",
                    "resume": "Rapports definitifs collectes d'une course, les deux masses PMU",
                    "description": "Lit les rapports collectes chaque nuit depuis le 1er janvier, et non le flux PMU en direct : tout l'historique est donc disponible, la ou /arrivee ne sert que la journee en cours. Chaque ligne porte DEUX montants : rapport_pour_1_euro, ce que le PMU publie, et rapport_pour_la_mise_de_base, ce qu'un ticket encaisse reellement. La mise de base n'est pas la meme partout (1 EUR au simple gagnant en ligne, 2 EUR au point de vente, 3 EUR au Multi et au 2 sur 4) : servir un seul des deux obligerait chaque consommateur a refaire la multiplication.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "code_course",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "masse",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "en_ligne",
                                "point_de_vente"
                            ],
                            "defaut": null,
                            "description": "Masse PMU servie. Le flux nu rend le point de vente, ?specialisation=INTERNET la masse en ligne (types prefixes E_). Elles ne paient pas pareil : releve du 20/07/2026, couple place 15-7 a 17,80 EUR au point de vente contre 30,10 EUR en ligne. Sans ce parametre, les deux sont servies."
                        },
                        {
                            "nom": "pari",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Filtre sur le type de pari, sans distinction de masse : TRIO retient aussi E_TRIO. Exemples : SIMPLE_GAGNANT, COUPLE_PLACE, DEUX_SUR_QUATRE, TRIO, TIERCE, QUARTE_PLUS, QUINTE_PLUS, MULTI, MINI_MULTI."
                        },
                        {
                            "nom": "payants",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "0",
                                "1"
                            ],
                            "defaut": null,
                            "description": "1 = ne garder que les rapports qui ont paye. Par defaut TOUT ce que le PMU a publie est servi, y compris les rapports a zero : ils prouvent que la formule etait proposee et que personne ne l'a trouvee, ce qui n'est pas une absence."
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "csv"
                            ],
                            "defaut": null,
                            "description": "csv pour un tableau (UTF-8 BOM, separateur point-virgule)."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}",
                    "resume": "Fiche course + partants exacts (fonctionne sur tout l'historique)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur : une ligne par partant. Refuse en 422 sur une course ambigue (deux reunions au meme code) : precisez hippodrome, un tableau ne peut pas porter l'avertissement."
                        },
                        {
                            "nom": "hippodrome",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Dix courses de l'historique, reparties sur trois journees (2025-11-15, 2025-11-16, 2026-07-17), portent le meme code RxCy sous deux hippodromes, soit 0,036 % des codes. Sans ce parametre la reponse melange les deux pelotons et porte ambigu: true, avec le nom de l'hippodrome dont le peloton est complet."
                        },
                        {
                            "nom": "champs",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "base",
                                "indicateurs",
                                "tout"
                            ],
                            "defaut": "tout",
                            "description": "Jeu de colonnes rendu. base = les colonnes servies avant le 11/09/2026, meme ordre, pour un script deja ecrit. indicateurs = base plus l'identite proprietaire et eleveur et les seize indicateurs du catalogue /v1/tops qui manquaient sur le partant (ELO_Proprio, ELO_Eleveur, Sigma_Horse, IMDC, Synergie_JCh, Turf_Points, TPch_90, Moy_TPch_90, Rang_J, TPJ_90, Taux_Incident, nombre_victoire, nombre_place, Gains_Totaux, Gains_Course, distanceRecord_sec). tout = toute la base exploitable, et c'est le defaut. Les colonnes ajoutees le sont a la fin : les positions d'un CSV existant ne bougent pas. Le dictionnaire complet, avec le jeu de chaque champ et son taux de remplissage, est sur /v1/schema."
                        },
                        {
                            "nom": "non_partants",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "inclus",
                                "exclus",
                                "seuls"
                            ],
                            "defaut": "inclus",
                            "description": "Que faire des chevaux qui ne prennent pas le depart. inclus = tous les chevaux, chacun portant partant (booleen) et statut_partant (partant ou non_partant) ; c'est le defaut, pour qu'un script deja ecrit garde le meme nombre de lignes. exclus = seulement ceux qui partent. seuls = seulement les forfaits. Les comptes de la course (nombre_partants_initial, nombre_partants_reel, nombre_non_partants, numeros_non_partants) sont les memes quel que soit le mode : le filtre ne change que les lignes rendues."
                        },
                        {
                            "nom": "non_partants_direct",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": "1",
                            "description": "Interroger le flux PMU en direct pour connaitre les forfaits de derniere minute. ACTIF par defaut sur cet endpoint, et il ne coute qu'un seul appel sortant, mutualise par un cache de 45 secondes. Il ne se declenche que sur une course du jour non encore courue : sur une date passee la base porte le releve definitif. Mettre 0 pour une reponse sans aucun appel sortant, au prix des forfaits tardifs. Si le flux PMU ne repond pas, la reponse sort quand meme avec ce que la base connait, et non_partants_direct passe a false."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/analyse",
                    "resume": "Classement multi-features (rank_partants) + LigneBZH du jour",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/arrivee",
                    "resume": "Arrivee + rapports (quasi temps reel le jour J)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/cotes",
                    "resume": "Cotes PMU en direct, ecart depuis le matin et sur quelques minutes",
                    "description": "Pour chaque partant : cote (temps reel), cote_ref (cote de reference de la matinee), evolution_ouverture / evolution_ouverture_pct / sens_ouverture (ecart avec la cote du matin, le seul recul qui couvre la journee entiere), cote_5min_ago / evolution_5min (ecart avec une mesure plus ancienne) et comparaison_age_sec qui donne l'age REEL de cette mesure en secondes. Le champ se nomme cote_5min_ago pour raison de compatibilite, mais l'ecart peut porter sur plus de 5 minutes : lisez comparaison_age_sec avant d'annoncer une duree. Ces deux champs valent null tant qu'aucune mesure assez ancienne n'existe pour la course. tendance et tendance_pct viennent du PMU et mesurent l'ecart depuis son dernier rapport, dont la date n'est pas publiee : ne leur attribuez aucune duree.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur : une ligne par partant, cote du moment comprise."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/cotes/historique",
                    "resume": "Serie complete des cotes de la course, du matin au depart",
                    "description": "La courbe, la ou /cotes ne donne que l'instantane et /cotes/mouvements une fenetre de deux heures. Chaque entree de mesures porte t (horodatage unix), heure (Europe/Paris), cotes (cote du moment par numero) et cotes_reference (cote de reference du matin). Un numero absent d'un releve n'avait pas de cote a cet instant : non-partant, ou marche pas encore ouvert (le PMU renvoie 0 dans ce cas, nous ne le publions pas comme une cote car il fausserait toute moyenne ; la cellule CSV est vide). Un releve ou aucun numero n'avait de cote n'apparait pas. Le flux PMU ne publie pas de serie : celle-ci est collectee par turf.bzh depuis le 27/07/2026, une course anterieure repond 404 et le passe n'est pas rattrapable. La cadence se resserre a l'approche du depart (30 min au-dela de 2 h, 10 min entre 2 h et 30 min, 5 min ensuite) mais ne peut pas etre plus fine que la frequence d'appel du collecteur, aujourd'hui de 5 minutes : les dernieres minutes avant le depart sont couvertes par un a deux releves. En format=csv la sortie est en forme longue, une ligne par mesure et par partant, colonnes date;code_course;t;heure;num;cote;cote_ref.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur, en forme longue : une ligne par releve et par partant."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/cotes/mouvements",
                    "resume": "Plus gros mouvements de cote sur une fenetre glissante",
                    "description": "Chaque ligne porte cote, cote_avant, delta, delta_pct et sens, plus cote_ouverture / delta_ouverture / delta_ouverture_pct pour le recul depuis le matin. La reponse contient fenetre_reelle_sec : la duree effectivement couverte, qui peut depasser le parametre fenetre si les mesures intermediaires manquent. Une cote qui baisse signale de l'argent qui rentre sur le cheval, ce n'est pas une prevision.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "fenetre",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 5,
                            "description": ""
                        },
                        {
                            "nom": "limit",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 5,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/dossier",
                    "resume": "Le dossier complet d'une course en un seul appel",
                    "description": "Tout ce que turf.bzh sait de la course {rc} du {date}, assemble cote serveur : la fiche et ses partants, les indicateurs calcules, le classement, LigneBZH, les ecarts, le carnet du Renifleur, EcurieBZH, les cotes PMU en direct et leurs mouvements pour une course du jour, les rapports definitifs pour une course passee, et l'historique recent de chaque partant. Remplace sept appels de course plus un appel par cheval : sur un peloton de quatorze, vingt et un appels deviennent un seul. Il compte pour UN appel de quota, comme n'importe quelle autre route. Aucune section n'est bloquante sauf la course elle-meme : une section indisponible revient en disponible=false avec sa raison, le reste est servi. Le champ meta.appels_economises dit combien d'appels cette reponse a remplaces.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "inclure",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Liste de sections separees par des virgules, parmi indicateurs, classement, ligne_bzh, ecarts, renifleur, ecuriebzh, cotes, mouvements, arrivee, rapports, historique. Omis, le dossier sert les sections qui ont un sens pour la date demandee (les cotes en direct pour aujourd'hui, les rapports definitifs pour une course passee). La valeur tout force les onze sections."
                        },
                        {
                            "nom": "historique",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 3,
                            "description": "Nombre de dernieres sorties rendues par partant, de 0 a 10 (defaut 3). C'est la partie qui coute une requete par cheval : 0 supprime la section et allege la reponse."
                        },
                        {
                            "nom": "hippodrome",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Dix courses de la base partagent leur code RxCy avec une autre reunion le meme jour. Ce parametre leve l'ambiguite, comme sur /v1/courses/{date}/{rc}."
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "csv",
                                "xlsx"
                            ],
                            "defaut": null,
                            "description": "Omis, la reponse est le JSON complet. csv rend UNE ligne par partant, les champs de course repetes sur chaque ligne et les sections rabattues sur le cheval qu'elles decrivent (prefixe par le nom de la section) : la forme qu'un tableur sait filtrer. xlsx rend un classeur, un onglet par section plus un onglet Partants a plat et un onglet Course. Ce que ces deux formats ne peuvent pas porter (l'historique detaille de chaque cheval, les structures imbriquees) reste dans le JSON, qui fait foi."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/ecarts",
                    "resume": "Ecarts de victoires/places (par cheval et par numero)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/ecuriebzh",
                    "resume": "EcurieBZH : ecuries engagees dans une course qui sortent de l'ordinaire",
                    "description": "Les ecuries ayant au moins un cheval engage dans la course {rc} du {date} et qui sortent de leurs habitudes, avec le detail de leurs deplacements du jour. Lecture descriptive, jamais un pronostic (champ avertissement).",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/indicateurs",
                    "resume": "Features calculees par partant (ELO trends, forme, affinites, synergie, IMDC...)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "champs",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "base",
                                "indicateurs",
                                "tout"
                            ],
                            "defaut": "tout",
                            "description": "Jeu de colonnes rendu. base = les colonnes servies avant le 11/09/2026, meme ordre, pour un script deja ecrit. indicateurs = base plus l'identite proprietaire et eleveur et les seize indicateurs du catalogue /v1/tops qui manquaient sur le partant (ELO_Proprio, ELO_Eleveur, Sigma_Horse, IMDC, Synergie_JCh, Turf_Points, TPch_90, Moy_TPch_90, Rang_J, TPJ_90, Taux_Incident, nombre_victoire, nombre_place, Gains_Totaux, Gains_Course, distanceRecord_sec). tout = toute la base exploitable, et c'est le defaut. Les colonnes ajoutees le sont a la fin : les positions d'un CSV existant ne bougent pas. Le dictionnaire complet, avec le jeu de chaque champ et son taux de remplissage, est sur /v1/schema."
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "csv"
                            ],
                            "defaut": null,
                            "description": "Sortie CSV (UTF-8 BOM, separateur ;) pour tableurs"
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/courses/{date}/{rc}/renifleur",
                    "resume": "Carnet de notes du Renifleur sur une course",
                    "description": "Deux blocs. carnet_de_course : le resume redige par Le Renifleur apres l'arrivee de cette course et le cheval retenu pour la prochaine fois, null si la course n'a pas encore ete debriefee. deja_reperes : les partants engages qui avaient ete reperes a leur derniere sortie, avec la note d'alors, sa date, l'hippodrome et le numero porte ce jour-la. Contenu editorial exclusif turf.bzh, ce n'est PAS un signal de pari. Mesure sur 2 411 rentrees : les chevaux reperes terminent dans les trois premiers 35,9 % du temps contre 27,8 % pour l'ensemble des partants, mais a cote egale l'ecart n'est pas significatif et le retour est de 0,72 EUR pour 1 EUR joue. Chaque reponse porte un champ avertissement qui le rappelle.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "rc",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/ecuriebzh",
                    "resume": "EcurieBZH : ecuries qui sortent de leurs habitudes (jour courant)",
                    "description": "Lecture DESCRIPTIVE du comportement des ecuries engagees au programme du jour, compare a leurs habitudes des dix-huit derniers mois : trajet inhabituel / plus loin que jamais, trois chevaux dans la meme course, premiere venue sur un hippodrome, monte confiee ou reprise, retour d'un cheval, premiere sortie chez un entraineur. Ce n'est PAS un pronostic : une ecurie qui se deplace loin, aligne plusieurs chevaux ou decouvre un hippodrome ne gagne pas plus souvent pour autant, le champ avertissement le rappelle. Reponse : ecuries[] (nom + deplacements {hippodrome, heure, faits}), chaque fait portant le libelle, la phrase redigee et les km. nb = nombre d'ecuries concernees, date = jour analyse. Donnee proprietaire turf.bzh, la meme qui alimente le pictogramme et l'onglet EcurieBZH du tableau des partants.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "ecurie",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Nom d'une ecurie / entraineur (ex: 'S. Roger') pour n'interroger que celle-ci. Vide = toutes les ecuries hors habitude de la journee."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/exports",
                    "resume": "Liste des exports mensuels",
                    "description": "La base entiere, en CSV compresse, un fichier par mois, avec taille, nombre de lignes et empreinte SHA-256. Mesure exacte : 83,8 Mo en CSV, 28,4 Mo compresses. Le mois en cours porte partiel: true, il est incomplet et sa derniere journee n'a pas encore ses cotes de depart. A preferer a toute extraction massive.",
                    "groupe": "Donnees",
                    "parametres": []
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/exports/{fichier}",
                    "resume": "Telechargement d'un export mensuel",
                    "description": "Rend le fichier gzip. Le nom doit avoir la forme partants-AAAA-MM.csv.gz ; la liste est sur /v1/exports. Le telechargement passe par l'API et reste donc soumis a la cle.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "fichier",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Nom du fichier, tel que donne par /v1/exports."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/journees/{date}/ecuriebzh",
                    "resume": "EcurieBZH pour une journee passee (archive datee)",
                    "description": "Le meme panorama que /v1/ecuriebzh, mais pour une journee passee archivee (fichier ecuries_<date>.json depose chaque matin). Utile pour juger sur pieces : ce jour-la, ces ecuries sortaient de leurs habitudes. 404 si aucune archive n'est disponible pour la date demandee.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "ecurie",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Nom d'une ecurie / entraineur pour n'interroger que celle-ci. Vide = toutes."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/journees/{date}/partants",
                    "resume": "Tous les partants d'une journee, en un seul appel",
                    "description": "Sert la journee entiere : tous les partants de toutes les courses, avec la cote de depart, les indicateurs et le rang d'arrivee. C'est l'endpoint des etudes sur plusieurs jours. Reconstituer la base course par course demande environ 28 000 appels, soit trois jours compte tenu du plafond de 10 000 appels quotidiens ; par journee, 548 appels et une dizaine de minutes. Les plages de dates sont refusees : bouclez sur les dates, ou prenez /v1/exports. La cote est vide pour la journee en cours, et pour la toute derniere journee de la base : elle arrive au rafraichissement du lendemain matin. /v1/statut donne la derniere date exploitable.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Jour demande, au format YYYY-MM-DD."
                        },
                        {
                            "nom": "discipline",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Filtre : plat, trot attele, trot monte, obstacle, ou le code d'une lettre (P, A, M, H, S, C)."
                        },
                        {
                            "nom": "hippodrome",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Filtre partiel, insensible a la casse."
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur ; memes colonnes d'une journee a l'autre."
                        },
                        {
                            "nom": "champs",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "base",
                                "indicateurs",
                                "tout"
                            ],
                            "defaut": "tout",
                            "description": "Jeu de colonnes rendu. base = les colonnes servies avant le 11/09/2026, meme ordre, pour un script deja ecrit. indicateurs = base plus l'identite proprietaire et eleveur et les seize indicateurs du catalogue /v1/tops qui manquaient sur le partant (ELO_Proprio, ELO_Eleveur, Sigma_Horse, IMDC, Synergie_JCh, Turf_Points, TPch_90, Moy_TPch_90, Rang_J, TPJ_90, Taux_Incident, nombre_victoire, nombre_place, Gains_Totaux, Gains_Course, distanceRecord_sec). tout = toute la base exploitable, et c'est le defaut. Les colonnes ajoutees le sont a la fin : les positions d'un CSV existant ne bougent pas. Le dictionnaire complet, avec le jeu de chaque champ et son taux de remplissage, est sur /v1/schema."
                        },
                        {
                            "nom": "non_partants",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "inclus",
                                "exclus",
                                "seuls"
                            ],
                            "defaut": "inclus",
                            "description": "Que faire des chevaux qui ne prennent pas le depart. inclus = tous les chevaux, chacun portant partant (booleen) et statut_partant (partant ou non_partant) ; c'est le defaut, pour qu'un script deja ecrit garde le meme nombre de lignes. exclus = seulement ceux qui partent. seuls = seulement les forfaits. Les comptes de la course (nombre_partants_initial, nombre_partants_reel, nombre_non_partants, numeros_non_partants) sont les memes quel que soit le mode : le filtre ne change que les lignes rendues."
                        },
                        {
                            "nom": "non_partants_direct",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": "0",
                            "description": "Interroger le flux PMU en direct pour la journee EN COURS. Inactif par defaut : une journee compte jusqu'a une quarantaine de courses, soit autant d'appels sortants pour une seule requete. Sur une journee passee il n'apprend rien, la base porte alors le releve definitif, et le parametre est ignore. Mettre 1 pour l'activer : les courses non encore courues sont relevees en parallele, avec un cache de 45 secondes et un plafond de 25 appels par requete (au-dela, la note de reponse le dit). Pour une course precise, /v1/courses/{date}/{rc} le fait d'office et ne coute qu'un appel."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/me",
                    "resume": "Etat du compte (licence, abonnement, cle, credits IA, usage API)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": []
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/methodes",
                    "resume": "Liste des methodes BZH du compte (appliquer/backtester : via POST /v1/chat, forfaits 60/100 cr)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": []
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/performances",
                    "resume": "Taux de couverture mesure de nos selections, et palmares",
                    "description": "Le taux de couverture est la part des courses ou la combinaison gagnante d'un pari etait entierement contenue dans nos N premiers chevaux. Il est mesure sur TOUTES les courses de la periode ou le PMU a publie cette formule, jamais sur une selection des meilleures. Chaque ligne porte le nombre de combinaisons a jouer (tickets) et leur cout (engage_eur) : un taux sans son prix ne veut rien dire. Ce n'est ni un rendement ni une promesse ; le meta porte l'avertissement, qui n'est pas decoratif. Meme source que la page /meilleures-performances.php.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "fenetre",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "7j",
                                "14j",
                                "30j",
                                "90j",
                                "annee"
                            ],
                            "defaut": "30j",
                            "description": ""
                        },
                        {
                            "nom": "famille",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Filtre : SIMPLE_GAGNANT, COUPLE_GAGNANT, COUPLE_PLACE, DEUX_SUR_QUATRE, TRIO, TIERCE, QUARTE_PLUS, QUINTE_PLUS, MULTI, MINI_MULTI."
                        },
                        {
                            "nom": "palmares",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "0",
                                "1"
                            ],
                            "defaut": null,
                            "description": "1 pour joindre les plus gros rapports couverts. Absent par defaut : la mesure pese moins que la vitrine."
                        },
                        {
                            "nom": "n",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 10,
                            "description": "Lignes de palmares, 1 a 100."
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "csv"
                            ],
                            "defaut": null,
                            "description": "csv pour un tableau (UTF-8 BOM, separateur point-virgule)."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/personnes",
                    "resume": "Recherche jockey/driver/entraineur/proprietaire/eleveur (semantique + fallback)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "recherche",
                            "ou": "query",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "type",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "jockey",
                                "driver",
                                "entraineur",
                                "proprietaire",
                                "eleveur"
                            ],
                            "defaut": "jockey",
                            "description": ""
                        },
                        {
                            "nom": "limit",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 5,
                            "description": ""
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/personnes/{type}/{id}/stats",
                    "resume": "Stats d'un jockey, entraineur, proprietaire ou eleveur (periode, discipline ; hippodrome pour les jockeys)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "type",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [
                                "jockey",
                                "driver",
                                "entraineur",
                                "proprietaire",
                                "eleveur"
                            ],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "id",
                            "ou": "path",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "periode_jours",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 90,
                            "description": ""
                        },
                        {
                            "nom": "discipline",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "hippodrome",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "debut",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Borne basse de la periode, au format YYYY-MM-DD. Ajoute le 03/08/2026. Des qu'une de ces deux bornes est fournie, periode_jours cesse de s'appliquer et le champ period_days de la reponse porte la duree reellement couverte."
                        },
                        {
                            "nom": "fin",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Borne haute de la periode, au format YYYY-MM-DD. Ajoute le 03/08/2026. Des qu'une de ces deux bornes est fournie, periode_jours cesse de s'appliquer et le champ period_days de la reponse porte la duree reellement couverte."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/programme",
                    "resume": "Programme du jour (reunions, courses, heures, Quinte+)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "filter",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "all",
                                "upcoming",
                                "completed"
                            ],
                            "defaut": "all",
                            "description": ""
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur : une ligne par course du programme."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/quinte",
                    "resume": "La course du Quinte+ du jour (source officielle turf.bzh)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": []
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/rapports",
                    "resume": "Rapports definitifs collectes d'une journee entiere",
                    "description": "Meme source et memes champs que la route par course, sur toute une journee : environ 340 rapports sur 40 courses. Le meta porte nb_courses, paris_presents et les bornes de la collecte.",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Defaut : aujourd'hui. Une date future renvoie 422."
                        },
                        {
                            "nom": "code_course",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "masse",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "en_ligne",
                                "point_de_vente"
                            ],
                            "defaut": null,
                            "description": "Masse PMU servie. Le flux nu rend le point de vente, ?specialisation=INTERNET la masse en ligne (types prefixes E_). Elles ne paient pas pareil : releve du 20/07/2026, couple place 15-7 a 17,80 EUR au point de vente contre 30,10 EUR en ligne. Sans ce parametre, les deux sont servies."
                        },
                        {
                            "nom": "pari",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Filtre sur le type de pari, sans distinction de masse : TRIO retient aussi E_TRIO. Exemples : SIMPLE_GAGNANT, COUPLE_PLACE, DEUX_SUR_QUATRE, TRIO, TIERCE, QUARTE_PLUS, QUINTE_PLUS, MULTI, MINI_MULTI."
                        },
                        {
                            "nom": "payants",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "0",
                                "1"
                            ],
                            "defaut": null,
                            "description": "1 = ne garder que les rapports qui ont paye. Par defaut TOUT ce que le PMU a publie est servi, y compris les rapports a zero : ils prouvent que la formule etait proposee et que personne ne l'a trouvee, ce qui n'est pas une absence."
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "csv"
                            ],
                            "defaut": null,
                            "description": "csv pour un tableau (UTF-8 BOM, separateur point-virgule)."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/resultats",
                    "resume": "Arrivees et rapports des courses terminees d'une journee (aujourd'hui ou une date passee)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "date",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Journee servie. Defaut : aujourd'hui. Toute date passee presente en base est acceptee ; une date future renvoie 422."
                        },
                        {
                            "nom": "code_course",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "hippodrome",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Filtre sur le nom de l'hippodrome, recherche partielle et insensible a la casse (ex: enghien). 40 caracteres maximum."
                        },
                        {
                            "nom": "arrivee",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [
                                "complete",
                                "top5"
                            ],
                            "defaut": "complete",
                            "description": "complete (defaut) = ordre d'arrivee entier ; top5 = les cinq premiers seulement"
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/statut",
                    "resume": "Fraicheur de la base (healthcheck) : fresh / stale / empty",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": []
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/tops",
                    "resume": "Top N du jour par indicateur (34 indicateurs du catalogue)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "indicateur",
                            "ou": "query",
                            "requis": true,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "n",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 10,
                            "description": ""
                        },
                        {
                            "nom": "date",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "discipline",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur : une ligne par cheval du classement."
                        }
                    ]
                },
                {
                    "methode": "GET",
                    "chemin": "/v1/value-bets",
                    "resume": "Value bets du jour (composite Cote_BZH_fiable)",
                    "description": "",
                    "groupe": "Donnees",
                    "parametres": [
                        {
                            "nom": "n",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": 10,
                            "description": ""
                        },
                        {
                            "nom": "date",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": ""
                        },
                        {
                            "nom": "format",
                            "ou": "query",
                            "requis": false,
                            "valeurs": [],
                            "defaut": null,
                            "description": "Mettre csv pour une sortie tableur : une ligne par candidat."
                        }
                    ]
                }
            ]
        },
        {
            "id": "non-partants",
            "titre": "Qui prend le départ",
            "blocs": [
                {
                    "t": "p",
                    "v": "Point à lire avant tout calcul sur un peloton. Un cheval déclaré forfait n'est pas absent de la base : il y figure comme les autres, avec Rank = NP. Jusqu'au 12/09/2026, les deux adresses qui servent des partants ne le distinguaient pas. Portée mesurée sur les 8 530 courses courues du 1er janvier au 8 juin 2026 : 3 768 lignes portent ce code, sur 2 741 courses, soit 32,1 % de la période."
                },
                {
                    "t": "tableau",
                    "entetes": [
                        "Champ",
                        "Sur",
                        "Ce que c'est"
                    ],
                    "lignes": [
                        [
                            "partant",
                            "chaque partant",
                            "booléen. false : ce cheval ne prend pas le départ. En CSV, 1 ou 0."
                        ],
                        [
                            "statut_partant",
                            "chaque partant",
                            "partant ou non_partant."
                        ],
                        [
                            "source_statut",
                            "un forfait",
                            "base ou pmu_direct, d'où vient l'information."
                        ],
                        [
                            "nombre_partants_initial",
                            "la course",
                            "le peloton engagé, forfaits compris."
                        ],
                        [
                            "nombre_partants_reel",
                            "la course",
                            "ceux qui prennent le départ. initial = réel + non partants, sans exception."
                        ],
                        [
                            "nombre_non_partants",
                            "la course",
                            "les forfaits connus à l'instant de l'appel."
                        ],
                        [
                            "numeros_non_partants",
                            "la course",
                            "leurs numéros, triés."
                        ],
                        [
                            "nombre_partants_declare",
                            "la course",
                            "le chiffre annoncé par la source, tel quel."
                        ]
                    ]
                },
                {
                    "t": "p",
                    "v": "N'UTILISEZ PAS nombre_partants pour compter les chevaux au départ. Sur les 2 741 courses à forfait de la période mesurée, cette colonne vaut le peloton engagé 85,6 % du temps et le peloton réel 10,0 % seulement. Les deux nombres servis sont comptés ligne à ligne et non déduits d'elle ; le chiffre annoncé est servi à côté sous nombre_partants_declare, et note_partants_declare signale l'écart quand il existe, soit 398 courses sur 8 530 (4,7 %)."
                },
                {
                    "t": "p",
                    "v": "Les autres codes de Rank ne désignent pas des forfaits. D disqualifié, A arrêté, T tombé, R et N s'appliquent à des chevaux qui ont pris le départ. NP est le seul code de forfait. Les effectifs de chaque code figurent dans la description du champ Rank, au dictionnaire."
                },
                {
                    "t": "p",
                    "v": "Le jour J, la base ne suffit pas. Le code NP arrive tôt pour les forfaits déclarés à l'avance, et seulement avec l'ingestion de l'arrivée pour les autres, donc après la course. Relevé du 08/06/2026 : 4 forfaits posés sur 678 lignes encore sans résultat, pour une journée qui en comptera entre 26 et 52. /v1/courses/{date}/{rc} interroge donc le flux PMU en direct PAR DÉFAUT sur une course du jour non encore courue : c'est la seule source d'un forfait de dernière minute. Sur /v1/journees/{date}/partants c'est en option, non_partants_direct=1, parce qu'une journée compte jusqu'à une quarantaine de courses."
                },
                {
                    "t": "code",
                    "v": "# le peloton réel d'une course du jour\nGET /v1/courses/{date}/{rc}?non_partants=exclus\n\n# les seuls forfaits, pour un rapprochement\nGET /v1/courses/{date}/{rc}?non_partants=seuls\n\n# la journée entière, avec le relevé PMU en direct\nGET /v1/journees/{date}/partants?non_partants_direct=1"
                },
                {
                    "t": "note",
                    "v": "Le filtre non_partants ne change que la liste rendue : les cinq nombres de course et les numéros des forfaits sont identiques dans les trois modes. Si le flux PMU ne répond pas, la réponse sort quand même avec le relevé de la base et non_partants_direct passe à false."
                }
            ]
        },
        {
            "id": "champs",
            "titre": "Le dictionnaire des champs",
            "blocs": [
                {
                    "t": "p",
                    "v": "Le catalogue des colonnes servies sur un partant, tel qu'il vit dans le code. Le paramètre champs choisit le jeu : base rend les 45 colonnes servies avant le 11/09/2026 dans le même ordre, indicateurs y ajoute l'identité propriétaire et éleveur et les 16 indicateurs du catalogue /v1/tops, tout rend l'ensemble et c'est le défaut. Les colonnes ajoutées le sont à la fin : les positions d'un CSV existant ne bougent pas."
                },
                {
                    "t": "p",
                    "v": "La portée dit si la valeur est propre au cheval ou commune à toute la course. Sur /v1/courses/{date}/{rc}, les valeurs de portée course sont hissées dans l'en-tête de la réponse au lieu d'être répétées sur chaque ligne."
                },
                {
                    "t": "note",
                    "v": "Les taux de remplissage portent sur la table entière et sont recalculés chaque nuit ; dernière mesure le 2026-09-11T05:55:26+02:00. Un taux bas n'est pas une anomalie : il dit que la source ne publie cette information que dans certains cas. Vérifiez-le avant de bâtir une hypothèse sur un champ."
                }
            ],
            "champs": [
                {
                    "champ": "date",
                    "colonne": "date",
                    "jeu": "base",
                    "portee": "course",
                    "type": "date",
                    "unite": "YYYY-MM-DD",
                    "description": "Jour de la course."
                },
                {
                    "champ": "code_course",
                    "colonne": "Course",
                    "jeu": "base",
                    "portee": "course",
                    "type": "texte",
                    "unite": "RxCy",
                    "description": "Code reunion et course, par exemple R1C3. Attention : dix courses de l'historique, reparties sur trois journees (2025-11-15, 2025-11-16, 2026-07-17), portent le meme code sous deux hippodromes differents, soit 0,036 % des codes. Sur celles-la, la reponse porte ambigu: true et un des deux pelotons est incomplet en base. Utilisez le parametre hippodrome pour les separer."
                },
                {
                    "champ": "hippodrome",
                    "colonne": "hippodrome",
                    "jeu": "base",
                    "portee": "course",
                    "type": "texte",
                    "unite": null,
                    "description": "Nom de l'hippodrome."
                },
                {
                    "champ": "num",
                    "colonne": "Numero",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Numero du partant, celui qu'on coche sur un ticket."
                },
                {
                    "champ": "idcheval",
                    "colonne": "idcheval",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Identifiant stable du cheval. A preferer au nom : deux chevaux peuvent porter le meme nom."
                },
                {
                    "champ": "name",
                    "colonne": "Cheval",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Nom du cheval."
                },
                {
                    "champ": "Sexe",
                    "colonne": "Sexe",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": "H/F/M",
                    "description": "Sexe du cheval."
                },
                {
                    "champ": "age",
                    "colonne": "age",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "annees",
                    "description": "Age du cheval le jour de la course."
                },
                {
                    "champ": "jockey_driver",
                    "colonne": "Driver",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Jockey au plat et a l'obstacle, driver au trot."
                },
                {
                    "champ": "trainer",
                    "colonne": "Entraineur",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Entraineur."
                },
                {
                    "champ": "idjockey",
                    "colonne": "idjockey",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Identifiant stable du jockey ou driver."
                },
                {
                    "champ": "identraineur",
                    "colonne": "identraineur",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Identifiant stable de l'entraineur."
                },
                {
                    "champ": "Cote",
                    "colonne": "Cote",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "pour 1 euro",
                    "description": "LA COTE DE DEPART, pas celle du matin. Verification sur la base : la somme des inverses des cotes d'une course a une mediane de 1,189, soit un prelevement de 18,9 %, ce qui est la signature d'un pool ferme au depart ; et sur 27 198 gagnants ayant aussi un rapport, l'ecart median entre les deux est nul. Vide pour la journee en cours (valeur non rafraichie) et pour la toute derniere journee de la base (la cote de depart arrive au rafraichissement du lendemain)."
                },
                {
                    "champ": "Cote_BZH",
                    "colonne": "Cote_BZH",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "pour 1 euro",
                    "description": "Cote estimee par turf.bzh a partir des chances du cheval. Ce n'est pas une cote de marche."
                },
                {
                    "champ": "Note_IA",
                    "colonne": "Note_IA",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Note de synthese, forme courte."
                },
                {
                    "champ": "Note_IA_Decimale",
                    "colonne": "Note_IA_Decimale",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "sur 20",
                    "description": "Note de synthese sur vingt."
                },
                {
                    "champ": "ELO_Cheval",
                    "colonne": "ELO_Cheval",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Classement ELO du cheval."
                },
                {
                    "champ": "ELO_Jockey",
                    "colonne": "ELO_Jockey",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Classement ELO du jockey ou driver."
                },
                {
                    "champ": "ELO_Entraineur",
                    "colonne": "ELO_Entraineur",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Classement ELO de l'entraineur."
                },
                {
                    "champ": "IA_Gagnant",
                    "colonne": "IA_Gagnant",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "probabilite",
                    "description": "Chance estimee de gagner. C'est le bouton IA GAGNANT du tableau des partants."
                },
                {
                    "champ": "IA_Couple",
                    "colonne": "IA_Couple",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "probabilite",
                    "description": "Chance estimee de figurer dans les deux premiers. C'est le bouton IA COUPLE du tableau des partants. Servie par l'API depuis le 09/09/2026."
                },
                {
                    "champ": "IA_Trio",
                    "colonne": "IA_Trio",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "probabilite",
                    "description": "Chance estimee de figurer dans les trois premiers. C'est le bouton IA TRIO du tableau des partants. Servie par l'API depuis le 09/09/2026."
                },
                {
                    "champ": "IA_Multi",
                    "colonne": "IA_Multi",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "probabilite",
                    "description": "Chance estimee de figurer dans les quatre premiers. C'est le bouton IA MULTI du tableau des partants. Servie par l'API depuis le 09/09/2026."
                },
                {
                    "champ": "IA_Quinte",
                    "colonne": "IA_Quinte",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "probabilite",
                    "description": "Chance estimee de figurer dans les cinq premiers. C'est le bouton IA QUINTE du tableau des partants."
                },
                {
                    "champ": "ferrure",
                    "colonne": "ferrure",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Ferrure annoncee (D4 deferre des quatre, DA deferre anterieurs, DP deferre posterieurs...)."
                },
                {
                    "champ": "Musique",
                    "colonne": "Musique",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Musique du cheval, ses dernieres performances."
                },
                {
                    "champ": "Rank",
                    "colonne": "Rank",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Rang d'arrivee. Valeurs numeriques 1, 2, 3... pour les chevaux classes. Codes non numeriques REELLEMENT presents en base, avec leurs effectifs mesures au 03/08/2026 : D 31 174, NP 12 405, A 3 209, T 1 474, R 35, N 2. Vide sur 3 144 lignes, quand la source ne publie pas la place (gros pelotons etrangers, ou course pas encore depouillee). Le sens exact de D et de R n'est pas tranche dans nos sources : ne les interpretez pas, traitez-les comme non classe. NP est le seul code qui signale un cheval qui N'A PAS pris le depart : D, A, T, R et N designent des chevaux qui sont partis. Depuis le 12/09/2026 vous n'avez plus a le deduire, le champ partant le dit, et sur une course du jour il tient compte des forfaits de derniere minute releves en direct sur le flux PMU, que la base ne connait pas encore."
                },
                {
                    "champ": "supplemente",
                    "colonne": "supplemente",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Cheval engage en supplement."
                },
                {
                    "champ": "ExFav",
                    "colonne": "ExFav",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Etait favori lors d'une sortie precedente."
                },
                {
                    "champ": "Poids",
                    "colonne": "Poids",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "kg",
                    "description": "Poids porte. Sans objet au trot attele."
                },
                {
                    "champ": "Valeur",
                    "colonne": "Valeur",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": null,
                    "description": "Valeur handicap officielle."
                },
                {
                    "champ": "Place_Corde",
                    "colonne": "Place_Corde",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Place a la corde. Sans objet dans les disciplines sans corde."
                },
                {
                    "champ": "avis_entraineur",
                    "colonne": "avis_entraineur",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Avis publie par l'entraineur, quand il y en a un."
                },
                {
                    "champ": "Taux_Victoire",
                    "colonne": "Taux_Victoire",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "fraction de 0 a 1",
                    "description": "Taux de victoire du cheval. CE N'EST PAS UN POURCENTAGE : c'est une fraction entre 0 et 1, et 0,21 se lit 21 %. Le champ etait documente en pourcentage jusqu'au 11/09/2026, a tort. Formule verifiee sur la base entiere ce jour-la : nombre_victoire divise par Courses_courues, exacte sur 266 483 lignes sur 266 483. Les deux termes sortent avec le jeu tout : un taux sans son effectif ne se lit pas."
                },
                {
                    "champ": "Taux_Place",
                    "colonne": "Taux_Place",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "fraction de 0 a 1",
                    "description": "Taux de place du cheval, LA VICTOIRE COMPRISE, comme le turfiste l'entend. Fraction entre 0 et 1, pas un pourcentage. Formule verifiee sur la base entiere le 11/09/2026 : nombre_victoire plus nombre_place, divise par Courses_courues, exacte sur 265 589 lignes sur 266 483, soit 99,7 %. Attention en consequence : nombre_place ne compte QUE les places hors victoire."
                },
                {
                    "champ": "Popularite",
                    "colonne": "Popularite",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": null,
                    "description": "Popularite du cheval aupres des parieurs : nombre de turfistes qui l'ont mis a suivre depuis sa derniere course."
                },
                {
                    "champ": "prec_popularite",
                    "colonne": "prec_popularite",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": null,
                    "description": "Popularite lors de la sortie precedente."
                },
                {
                    "champ": "Evo_Popul",
                    "colonne": "Evo_Popul",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": null,
                    "description": "Evolution de la popularite depuis la sortie precedente."
                },
                {
                    "champ": "Rapport_SG",
                    "colonne": "Rapport_SG",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "euros pour 1 euro",
                    "description": "Rapport du Simple gagnant. Renseigne uniquement pour le gagnant, et seulement quand la source le publie : c'est la colonne la moins remplie de la base."
                },
                {
                    "champ": "Rapport_SP",
                    "colonne": "Rapport_SP",
                    "jeu": "base",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "euros pour 1 euro",
                    "description": "Rapport du Simple place, pour les chevaux places."
                },
                {
                    "champ": "discipline",
                    "colonne": "discipline",
                    "jeu": "base",
                    "portee": "course",
                    "type": "texte",
                    "unite": "code",
                    "description": "P plat, A trot attele, M trot monte, H haies, S steeple, C cross."
                },
                {
                    "champ": "distance",
                    "colonne": "distance",
                    "jeu": "base",
                    "portee": "course",
                    "type": "entier",
                    "unite": "metres",
                    "description": "Distance de la course."
                },
                {
                    "champ": "allocation",
                    "colonne": "allocation",
                    "jeu": "base",
                    "portee": "course",
                    "type": "entier",
                    "unite": "euros",
                    "description": "Allocation totale de la course. Sert a mesurer le niveau : un cheval qui passe de 100 000 a 20 000 euros descend de categorie."
                },
                {
                    "champ": "heure",
                    "colonne": "heure",
                    "jeu": "base",
                    "portee": "course",
                    "type": "texte",
                    "unite": "HH:MM",
                    "description": "Heure de depart, heure de Paris."
                },
                {
                    "champ": "nombre_partants",
                    "colonne": "nombre_partants",
                    "jeu": "base",
                    "portee": "course",
                    "type": "entier",
                    "unite": null,
                    "description": "Nombre de partants annonce par la source. C'est le peloton ENGAGE, forfaits compris : sur les 2 741 courses a forfait mesurees de janvier a juin 2026, il vaut le total des lignes 2 345 fois (85,6 %) et le total moins les non partants 275 fois seulement (10,0 %). Ne vous en servez donc pas pour compter les chevaux au depart : depuis le 12/09/2026 la reponse porte nombre_partants_initial et nombre_partants_reel, comptes ligne a ligne, et ce chiffre-ci est servi tel quel sous le nom nombre_partants_declare. Il peut aussi differer du nombre de lignes rendues quand la source ne publie pas tout le peloton : 398 courses sur les 8 530 mesurees (4,7 %)."
                },
                {
                    "champ": "owner",
                    "colonne": "Proprietaire",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Proprietaire du cheval. Colonne ajoutee retroactivement le 25/08/2026 (jointure sur l'historique) : elle n'est pas renseignee a 100 %, voyez le taux de remplissage sur /v1/schema avant d'en tirer une conclusion."
                },
                {
                    "champ": "breeder",
                    "colonne": "Eleveur",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Eleveur, ou naisseur, du cheval. Meme ajout retroactif que le proprietaire, meme reserve sur le taux de remplissage."
                },
                {
                    "champ": "idproprio",
                    "colonne": "idproprio",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Identifiant stable du proprietaire, calcule comme idjockey (empreinte du nom). A preferer au nom pour appeler /v1/personnes."
                },
                {
                    "champ": "ideleveur",
                    "colonne": "ideleveur",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Identifiant stable de l'eleveur, calcule comme idjockey. A preferer au nom pour appeler /v1/personnes."
                },
                {
                    "champ": "ELO_Proprio",
                    "colonne": "ELO_Proprio",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Classement ELO du proprietaire, sur la meme echelle que les autres ELO. Il figurait deja au catalogue de /v1/tops sans etre lisible sur le partant : servi ici depuis le 11/09/2026."
                },
                {
                    "champ": "ELO_Eleveur",
                    "colonne": "ELO_Eleveur",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Classement ELO de l'eleveur, sur la meme echelle que les autres ELO. Meme correction que l'ELO proprietaire, meme date."
                },
                {
                    "champ": "Sigma_Horse",
                    "colonne": "Sigma_Horse",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": null,
                    "description": "Fiabilite de l'estimation ELO du cheval : plus elle est haute, plus le classement repose sur un historique fourni. Le composite ELO_Cheval_fiable de /v1/tops ne retient que les chevaux au-dessus de 60."
                },
                {
                    "champ": "IMDC",
                    "colonne": "IMDC",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Montee (+) ou descente (-) de categorie depuis la sortie precedente, cinq points par echelon (Course F vers Course E = +5, Course F vers Course D = +10). LISEZ CECI AVANT DE VOUS EN SERVIR : la base stocke 0 aussi bien quand le cheval reste dans sa categorie que quand l'indice n'est pas calculable (maiden, handicap, a reclamer, internationale, course a rating, ou cheval debutant). Sur 202 732 partants mesures, 51,6 % des IMDC a zero ne sont PAS calculables. Croisez avec Classe_Groupe avant de conclure."
                },
                {
                    "champ": "Turf_Points",
                    "colonne": "Turf_Points",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "points",
                    "description": "Points turf du cheval, indicateur de forme du catalogue /v1/tops."
                },
                {
                    "champ": "TPch_90",
                    "colonne": "TPch_90",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "points",
                    "description": "Points turf du cheval sur les 90 derniers jours."
                },
                {
                    "champ": "Moy_TPch_90",
                    "colonne": "Moy_TPch_90",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "points",
                    "description": "Moyenne des points turf du cheval sur 90 jours."
                },
                {
                    "champ": "Rang_J",
                    "colonne": "Rang_J",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "rang",
                    "description": "Rang du jockey ou driver au classement. Plus le nombre est petit, mieux c'est : /v1/tops trie cet indicateur en ordre croissant."
                },
                {
                    "champ": "TPJ_90",
                    "colonne": "TPJ_90",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "points",
                    "description": "Points turf du jockey ou driver sur les 90 derniers jours."
                },
                {
                    "champ": "Synergie_JCh",
                    "colonne": "Synergie_JCh",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "pourcentage",
                    "description": "Synergie entre le driver et le cheval. Renseignee sur un peu plus de quatre lignes sur dix : lisez le taux sur /v1/schema avant d'en faire un critere eliminatoire."
                },
                {
                    "champ": "distanceRecord_sec",
                    "colonne": "distanceRecord_sec",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "secondes",
                    "description": "Record chronometrique du cheval ramene a la distance. Plus le chiffre est bas, mieux c'est."
                },
                {
                    "champ": "Taux_Incident",
                    "colonne": "Taux_Incident",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "fraction de 0 a 1",
                    "description": "Taux d'incident du cheval. Fraction, pas un pourcentage, et arrondie a deux decimales : incident divise par Courses_courues, verifie sur la base le 11/09/2026. Plus le chiffre est bas, mieux c'est. Dix lignes sur 286 850 depassent 1, un cheval pouvant cumuler plusieurs incidents sur une meme course."
                },
                {
                    "champ": "nombre_victoire",
                    "colonne": "nombre_victoire",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Nombre de victoires du cheval sur son historique. C'est le numerateur de Taux_Victoire."
                },
                {
                    "champ": "nombre_place",
                    "colonne": "nombre_place",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Nombre de places du cheval HORS victoires. Ce n'est donc pas a lui seul le numerateur de Taux_Place : celui-ci vaut nombre_victoire plus nombre_place. Verifie sur la base le 11/09/2026."
                },
                {
                    "champ": "Gains_Totaux",
                    "colonne": "Gains_Totaux",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "euros",
                    "description": "Gains cumules du cheval sur toute sa carriere."
                },
                {
                    "champ": "Gains_Course",
                    "colonne": "Gains_Course",
                    "jeu": "indicateurs",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "euros",
                    "description": "Gains moyens du cheval par course. Formule verifiee sur la base entiere le 11/09/2026 : Gains_Totaux divise par Courses_courues, exacte sur 266 483 lignes sur 266 483. Vous pouvez donc le recalculer vous-meme si vous preferez une autre fenetre."
                },
                {
                    "champ": "Courses_courues",
                    "colonne": "Courses_courues",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Nombre de courses courues par le cheval. C'est le DENOMINATEUR commun de Taux_Victoire, Taux_Place, Taux_Incident et Gains_Course, les quatre formules ayant ete verifiees sur la base entiere le 11/09/2026. Un taux de 0,50 sur deux courses et un taux de 0,50 sur quarante ne disent pas la meme chose : c'est ce champ qui fait la difference."
                },
                {
                    "champ": "incident",
                    "colonne": "incident",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "entier",
                    "unite": null,
                    "description": "Nombre d'incidents releves sur l'historique du cheval. C'est le numerateur de Taux_Incident, dont le denominateur est Courses_courues."
                },
                {
                    "champ": "Repos",
                    "colonne": "Repos",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "jours",
                    "description": "Nombre de jours ecoules depuis la sortie precedente."
                },
                {
                    "champ": "Classe_Groupe",
                    "colonne": "Classe_Groupe",
                    "jeu": "tout",
                    "portee": "course",
                    "type": "texte",
                    "unite": null,
                    "description": "Classe ou groupe de la course (Classe 2, Classe 3, A reclamer, Internationale...). A lire avec IMDC : c'est elle qui dit si la categorie est comparable d'une sortie a l'autre."
                },
                {
                    "champ": "Moy_Alloc",
                    "colonne": "Moy_Alloc",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "euros",
                    "description": "Allocation moyenne des dernieres courses du cheval. Se croise avec allocation pour mesurer une montee ou une descente de niveau en valeur, la ou IMDC la mesure en echelons."
                },
                {
                    "champ": "Moy_TPch_365",
                    "colonne": "Moy_TPch_365",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "points",
                    "description": "Moyenne des points turf du cheval sur 365 jours."
                },
                {
                    "champ": "TPJ_365",
                    "colonne": "TPJ_365",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "entier",
                    "unite": "points",
                    "description": "Points turf du jockey ou driver sur 365 jours."
                },
                {
                    "champ": "Moy_TPJ_365",
                    "colonne": "Moy_TPJ_365",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Moyenne des points turf du jockey ou driver sur 365 jours."
                },
                {
                    "champ": "Moy_TPJ_90",
                    "colonne": "Moy_TPJ_90",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": "points",
                    "description": "Moyenne des points turf du jockey ou driver sur 90 jours."
                },
                {
                    "champ": "PC",
                    "colonne": "PC",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "decimal",
                    "unite": null,
                    "description": "Colonne PC de la base, servie telle quelle. Nous ne publions pas de definition pour celle-ci tant qu'elle n'est pas etablie de source sure : si vous vous en servez, mesurez-la vous-meme avant de lui faire confiance."
                },
                {
                    "champ": "ferrure_prec",
                    "colonne": "ferrure_prec",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "texte",
                    "unite": null,
                    "description": "Ferrure de la sortie precedente (FERRE, DEFERRE_ANTERIEURS, DEFERRE_POSTERIEURS, PROTEGE_ANTERIEURS...). A lire avec changement_ferrure."
                },
                {
                    "champ": "changement_ferrure",
                    "colonne": "changement_ferrure",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "texte",
                    "unite": "Oui/Non",
                    "description": "La ferrure change-t-elle par rapport a la sortie precedente."
                },
                {
                    "champ": "changement_driver",
                    "colonne": "changement_driver",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "texte",
                    "unite": "Oui/Non",
                    "description": "Le driver ou jockey change-t-il par rapport a la sortie precedente."
                },
                {
                    "champ": "Evo_Distance",
                    "colonne": "Evo_Distance",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "texte",
                    "unite": "Hausse/Baisse/Identique",
                    "description": "Evolution de la distance par rapport a la sortie precedente."
                },
                {
                    "champ": "Evo_Poids",
                    "colonne": "Evo_Poids",
                    "jeu": "tout",
                    "portee": "partant",
                    "type": "texte",
                    "unite": "Hausse/Baisse/Identique",
                    "description": "Evolution du poids porte par rapport a la sortie precedente. Sans objet au trot attele."
                }
            ]
        },
        {
            "id": "csv",
            "titre": "Sortie tableur",
            "blocs": [
                {
                    "t": "p",
                    "v": "Ajoutez format=csv pour recevoir un fichier au lieu du JSON : UTF-8 avec marque d'ordre (Excel français), séparateur point-virgule, une ligne par enregistrement. Les booléens s'écrivent 1 ou 0, jamais une cellule vide, pour qu'un faux ne se confonde pas avec une donnée manquante. Le seul /dossier accepte aussi format=xlsx."
                },
                {
                    "t": "liste",
                    "v": [
                        "/v1/chevaux/{id}/historique",
                        "/v1/courses/{date}/{code_course}/rapports",
                        "/v1/courses/{date}/{rc}",
                        "/v1/courses/{date}/{rc}/cotes",
                        "/v1/courses/{date}/{rc}/cotes/historique",
                        "/v1/courses/{date}/{rc}/dossier",
                        "/v1/courses/{date}/{rc}/indicateurs",
                        "/v1/journees/{date}/partants",
                        "/v1/performances",
                        "/v1/programme",
                        "/v1/rapports",
                        "/v1/schema",
                        "/v1/tops",
                        "/v1/value-bets"
                    ]
                },
                {
                    "t": "note",
                    "v": "Liste construite à partir du contrat OpenAPI : elle ne peut pas vieillir. Si une adresse y manque alors qu'elle sert un CSV, c'est le contrat qui est en retard, pas cette liste."
                }
            ]
        },
        {
            "id": "pieges",
            "titre": "Les pièges, mesurés",
            "blocs": [
                {
                    "t": "p",
                    "v": "Chacun a coûté du temps à quelqu'un. Ils sont ici avec leur portée mesurée, pas en généralités."
                },
                {
                    "t": "liste",
                    "v": [
                        "La cote du jour n'est pas dans la colonne Cote. Elle est vide pour la journée en cours et pour la toute dernière journée de la base : elle arrive au rafraîchissement du lendemain matin. Pour le jour même, appelez /cotes. /v1/statut donne la dernière date exploitable.",
                        "Dix courses de l'historique partagent leur code RxCy avec une autre réunion le même jour (2025-11-15, 2025-11-16, 2026-07-17), soit 0,036 % des codes. La réponse porte alors ambigu: true et un avertissement ; ajoutez hippodrome= pour n'obtenir qu'un peloton. En CSV la demande est refusée en 422, un tableau ne pouvant pas porter l'avertissement.",
                        "Le PMU publie deux montants pour le même pari, en_ligne et point_de_vente, et ils ne paient pas pareil. Chaque ligne de /rapports porte rapport_pour_1_euro, ce que le PMU publie, et rapport_pour_la_mise_de_base, ce qu'un ticket encaisse.",
                        "Les rapports à zéro ne sont pas une absence : ils prouvent que la formule était proposée et que personne ne l'a trouvée. Filtrer par défaut sur les payants biaise à la hausse tout taux de réussite calculé ensuite.",
                        "Taux_Victoire, Taux_Place et Taux_Incident sont des fractions entre 0 et 1, pas des pourcentages : 0,21 se lit 21 %. Taux_Place compte la victoire comme une place, alors que nombre_place ne compte que les places hors victoire.",
                        "Les non partants : voir la section dédiée. C'est le piège le plus coûteux, parce qu'il ne se voit pas."
                    ]
                }
            ]
        },
        {
            "id": "cadre",
            "titre": "Cadre d'usage",
            "blocs": [
                {
                    "t": "liste",
                    "v": [
                        "Aucune réponse de cette API ne garantit un gain, et aucune ne doit être présentée comme telle. Tout taux publié porte son échantillon.",
                        "Les données restent soumises aux conditions d'usage de turf.bzh. La clé est nominative : ne la redistribuez pas.",
                        "Le jeu comporte des risques : endettement, isolement, dépendance. Interdit aux mineurs. Jouez avec modération."
                    ]
                }
            ]
        }
    ]
}
