Documentation de l'API
L'API EdgeLab sert en JSON les données du site : programme des matchs et mouvement des cotes, analyse complète d'une rencontre, profils de joueurs, confrontations, suivi des signaux. Toutes les routes sont en lecture seule et authentifiées.
1. Authentification
Une clé se fabrique depuis votre compte. Elle ne s'affiche qu'une fois : nous n'en conservons que l'empreinte, donc une clé perdue ne se retrouve pas, elle se remplace.
curl -s "https://mma.edge-lab.io/api/v1/matches" \
-H "Authorization: Bearer $EDGELAB_API_KEY"Sans clé valide : 401. Une clé révoquée cesse de fonctionner au premier appel suivant, sans délai ni cache : c'est ce qui rend la coupure crédible, et c'est aussi pourquoi la clé est vérifiée en base à chaque requête.
2. L'enveloppe des réponses
Un succès porte toujours { "data": …, "meta": … }, une erreur toujours { "error": { "code": …, "message": … } }. Les codes d'erreur sont stables : unauthorized (401), bad_request (400), not_found (404), rate_limited (429), incomplete_response (500).
Testez error.code, jamais le message : le message est écrit pour un humain et peut être reformulé ; le code, lui, fait partie du contrat. Le détail de chaque réponse, champ par champ, vit dans la référence interactive.
3. Quotas et en-têtes de limite
Deux plans, et ils ne se comptent pas de la même façon.
- Essai : 20 appels au total, à vie. Il n'y a pas de fenêtre qui se rouvre, donc pas de
Retry-After: le message dit de souscrire, pas d'attendre. Remplacer sa clé ne rend pas les appels consommés. - Abonnement : 2000 appels par jour de Paris. La fenêtre se rouvre à minuit, heure de Paris, et
X-RateLimit-Resetle dit.
Toutes les réponses, succès compris, portent X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Window (day ou lifetime). Le dépassement rend 429, jamais une réponse tronquée.
4. Le paramètre viewer, et ce que votre plan en fait
Trois routes acceptent ?viewer=free|premium. La clé dit qui appelle ; viewer dit pour qui vous demandez la donnée : vous êtes autorité sur le palier de VOS lecteurs. Absent, il vaut premium.
⚠️ Le plan de la clé plafonne ce paramètre. Une clé d'essai est servie en viewer=free quoi qu'elle demande : les probabilités du modèle et leurs poids, le signal de value, la matrice de score et les statistiques de service sont absents du corps, qui porte alors locked: true. C'est ce que l'essai montre : la forme des réponses, pas la donnée qu'on vend. GET /api/v1/capabilities répond du point de vue de VOTRE clé et le dit explicitement.
Une valeur inconnue rend 400 : nous ne devinons pas à votre place.
5. Deux règles de lecture qui évitent les surprises
Les identifiants de joueurs sont opaques. Un player_key n'a de sens que dans cette API : comparez-les entre eux, ne les interprétez pas, ne les joignez à aucune source externe. Un même joueur a un identifiant par circuit, et une clé peut valoir null sur un match ancien dont l'identité n'est pas certaine : traitez ce cas comme « identité inconnue », jamais comme « match invalide ».
Rien n'est recalculé après coup. Un signal de value est figé au moment de la prédiction, et l'analyse d'un match commencé montre la photo d'avant-match. C'est ce qui rend le suivi vérifiable, et c'est aussi pourquoi une valeur ne changera jamais rétroactivement dans vos réponses.
6. Versionnement, et ce qui a déjà changé
Le préfixe /api/v1 est stable. Nous pouvons ajouter des champs ou des routes sans prévenir : votre client doit ignorer ce qu'il ne connaît pas. Retirer ou renommer un champ existant demanderait une nouvelle version.
Tout ce qui suit est déjà en ligne. C'est ici parce que deux de ces entrées ont changé la valeur d'un champ que vous lisiez peut-être déjà :
- 2026-08-11 (MCP endpoint) - The API speaks MCP at `/api/mcp` (streamable HTTP): point an agent at that URL with your key and the routes appear as tools. One tool call costs one API call.
- 2026-08-10 (field metadata) - Every field published by `/capabilities` now carries `type`, and `nullable`, `format` or `enumValues` when they apply. Deserialise from the catalogue instead of guessing from an example.
- 2026-08-10 (OpenAPI spec) - The API publishes its OpenAPI 3.1 spec at `/openapi.json`, in the clear and without a key.
- 2026-08-10 (response examples) - The spec carries real response bodies, captured on production. Paid fields carry a typed placeholder and data sources are redacted; nothing else is invented.
- 2026-08-10 (reference page) - The spec has a page: `/reference`, public and keyless. It is generated from `/openapi.json`, so it cannot drift from what the API serves.
- 2026-08-09 (viewer, trial keys) - A trial key (`plan: free`, 20 calls for life) is always served as `viewer=free`, whatever `?viewer=` asks for. `meta.viewer` tells you the tier actually served, and `/capabilities` publishes your key's own plan.
- 2026-08-05 (model_prob, edge) - Probability scale corrected: values SHRINK, shape is unchanged (an edge of 16 becomes ~6). Signals captured before this date keep the old scale - `captured_at` decides.
- 2026-08-05 (player career records) - `overall` and `bySurface` now carry the OFFICIAL career scope (ATP + Challenger main draws; qualifying and ITF excluded), so the numbers dropped for players who came through the Futures. `byTier`, `form`, `charge` and `recent` are unchanged. `careerScope` says which scope a profile carries.
7. Ce que le contrat autorise
L'usage de l'API est régi par les conditions de l'API, qui sont un contrat distinct de celui du site. En deux mots : intégrer nos analyses dans votre produit, oui ; revendre le flux en l'état ou reconstituer la base, non.
Une question, un besoin de volume, un cas d'usage particulier : hello@edge-lab.io.
8. Brancher votre agent
Cette API se décrit elle-même, et c'est fait pour : un agent n'a pas à lire cette page pour savoir quoi appeler. Deux adresses suffisent, et toutes deux répondent sans clé.
⚠️ Ces deux adresses vivent à la racine du site, derrière la protection anti-robots qui couvre les pages : un client automatisé qui n'est pas un robot reconnu y reçoit un défi (429). Ouvrez-les dans un navigateur. Le préfixe /api/v1 n'est pas concerné : c'est là que votre programme appelle.
https://mma.edge-lab.io/openapi.json- la spec OpenAPI 3.1 complète : routes, paramètres, forme des réponses, palier de chaque champ, et de vrais corps d'exemple. C'est ce qu'un générateur de client consomme.- https://mma.edge-lab.io/reference - la même chose pour un humain, avec un bouton pour essayer chaque route.
Une fois la clé posée, GET /api/v1/capabilities répond du point de vue de cette clé : le palier réellement servi, les champs de chaque réponse et leur tier, les interrupteurs actifs. Un agent qui commence par là ne demandera pas ce qu'il ne peut pas recevoir.
# ce que VOTRE clé peut obtenir
curl -s https://mma.edge-lab.io/api/v1/capabilities \
-H "Authorization: Bearer $EDGELAB_API_KEY"
# la carte du jour
curl -s https://mma.edge-lab.io/api/v1/matches \
-H "Authorization: Bearer $EDGELAB_API_KEY"Votre agent parle MCP ? Collez https://mma.edge-lab.io/api/mcp dans votre client, avec votre clé en jeton Bearer. Les neuf routes y apparaissent comme des outils, avec leurs paramètres, plus deux raccourcis pour les parcours courants (la value du jour, l'analyse d'un match par les noms des joueurs).
⚠️ Un appel d'outil consomme un appel de votre quota, refus compris. C'est écrit dans la description de chaque outil, mais un agent qui boucle sur une erreur épuise son essai vite.
L'essai gratuit vaut 20 appels et sert de la donnée réelle - il n'y a pas de bac à sable, donc rien à réapprendre au moment de passer en production. Comptez que chaque tentative refusée consomme un appel : un agent qui boucle sur une erreur épuise son essai.