Authentification
Toutes les routes /v1/* (sauf /v1/health) exigent une clé d'API passée dans l'en-tête X-API-Key. Les clés ont le préfixe bk_.
curl https://api.legifrance.dev/v1/article/777 \ -H "X-API-Key: bk_votre_cle"
Recherche fédérée
POST /v1/search
Une requête, quatre corpus entrelacés par pertinence : articles de loi (versionnés), doctrine fiscale (BOFiP), jurisprudence administrative (CE, CAA) et judiciaire (Cassation). Chaque résultat porte son type, sa référence citable et sa source datée.
| Champ | Type | Description |
|---|---|---|
| query | corps | question en langage naturel (2–500 caractères) |
| topK | option | 1–20 ; défaut 10 |
| profile | option | ai (compact, défaut) ou expert (chaque corpus pertinent représenté) |
| sources | option | sous-ensemble de articles, doctrine_fiscale, jurisprudence_administrative, jurisprudence_judiciaire |
| filters | option | typés PAR source : articles.asOf/code · doctrine_fiscale.domaine · jurisprudence_*.juridiction/dateMin/dateMax — asOf ne s'applique jamais à une décision |
curl -X POST https://api.legifrance.dev/v1/search \
-H "X-API-Key: bk_…" -H "Content-Type: application/json" \
-d '{"query":"abattement donation entre parents et enfants","topK":6}'
# → results: [
# {"type":"doctrine_fiscale","boi":{"boi_id":"BOI-ENR-DMTG-20-30-20-20",…}},
# {"type":"article","article":{"code":"CGI","num":"779",…}},
# {"type":"decision","decision":{"juridiction":"Conseil d'État","publication":"A",…}}
# ] — chacun avec score et source Etalab.Article par numéro
GET /v1/article/:num
Renvoie l'unique version d'un article en vigueur à une date. Sans asOf, la version en vigueur aujourd'hui.
| Paramètre | Type | Description |
|---|---|---|
| num | chemin | numéro de l'article (ex. 777) |
| asOf | query · option | date YYYY-MM-DD ; défaut = aujourd'hui |
| code | query · option | code visé ; défaut CGI |
{
"legiarti_id": "LEGIARTI000020549039",
"code": "CGI", "num": "777", "etat": "MODIFIE",
"date_debut": "2009-04-10", "date_fin": "2010-05-01",
"asOf": "2010-01-01", "version_label": "9.0",
"texte": "…", "url": "https://www.legifrance.gouv.fr/codes/article_lc/…",
"source": "Légifrance — Etalab 2.0"
}404 si aucune version n'est en vigueur à la date demandée (vacance de texte).
Recherche plein-texte
GET /v1/article
Recherche FTS5 (français, stemmée) restreinte par défaut aux versions en vigueur à asOf.
| Paramètre | Type | Description |
|---|---|---|
| q | query | requête (2–200 caractères) |
| asOf | query · option | date de validité ; défaut aujourd'hui |
| code | query · option | filtre par code |
| limit | query · option | 1–100 ; défaut 20 |
{
"total": 2, "asOf": "2026-06-04",
"results": [{ "legiarti_id": "LEGIARTI000033809289", "num": "784",
"extrait": "…<mark>donation</mark>…", "score": 8.4 }],
"source": "Légifrance — Etalab 2.0"
}Recherche sémantique
POST /v1/article/semantic
Recherche par le sens (embeddings), avec le même post-filtre temporel asOf. Corps JSON : query, topK (1–20), asOf?, code?.
curl -X POST https://api.legifrance.dev/v1/article/semantic \
-H "X-API-Key: bk_…" -H "Content-Type: application/json" \
-d '{"query":"abattement transmission entre vifs","topK":5}'Décisions & citator
GET /v1/decision/:id
Une décision (id CETATEXT…/JURITEXT…) avec son texte intégral, ses textes appliqués (références d'articles extraites et résolues — jamais inventées) et son citator : statut de validité machine-lisible (followed, contradicted, abandoned = revirement, cited, standalone), autorité (Lebon/Bulletin, formation, juridiction), citations entrantes et sortantes. Un signal négatif n'est jamais masqué.
GET /v1/article/:num/decisions
L'inverse : toutes les décisions qui appliquent un article (?code=CGI&sort=date|authority). Chaque décision porte son signal d'autorité.
Vérifier une citation
POST /v1/verify/citation
Anti-hallucination : une référence (article ou décision) existe-t-elle, est-elle encore valable ? Article → exists, en_vigueur à la date, drapeaux (etat_abroge, unknown_reference…). Décision → correspondances par ECLI ou numéro, chacune avec son statut citator ; une ambiguïté renvoie tous les candidats.
{"type":"article","code":"CGI","num":"777"}
# → {"exists":true,"en_vigueur":true,"version":{…},"flags":[]}
{"type":"decision","numero":"421444"}
# → {"exists":true,"matches":[{…,"citator":{"status":"followed",…}}]}Analytics jurisprudentielle
GET /v1/analytics/decisions
Agrégats par juridiction, par mois ou par article appliqué (le top du contentieux par texte) : ?groupBy=juridiction|month|article&code=&dateMin=&dateMax=. Conforme art. 33 de la loi 2019-222 — jamais de statistique par magistrat.
Webhooks
POST /v1/webhooks
« Préviens-moi quand l'article change (article_changed) ou quand une décision le cite (article_cited) ». Corps : url (https), kind, code, num. Livraisons quotidiennes signées HMAC-SHA256 (en-tête X-Legifrance-Signature) ; le secret n'est renvoyé qu'à la création. GET pour lister, DELETE /v1/webhooks/:id pour supprimer.
Statut
GET /v1/health
Public, sans clé. Renvoie l'état du service.
Serveur MCP
Branche un assistant (Claude, ChatGPT, Cursor, MS365 Copilot…) sur le droit applicable via le Model Context Protocol. Quatre outils : legifrance_article (version à une date), legifrance_search (plein-texte), legifrance_semantic_search et legifrance_search_all (recherche fédérée 4 corpus) ; ressources legifrance://article/… et legifrance://decision/…. Deux transports : HTTP (https://mcp.legifrance.dev/mcp) ou stdio (package npm).
{
"mcpServers": {
"legifrance": {
"command": "npx",
"args": ["@legifrance/mcp-server"],
"env": { "LEGIFRANCE_API_KEY": "bk_…" }
}
}
}Complément Word
Cherchez, insérez des citations datées (« CGI, art. 777 (en vigueur depuis le …) », « CE, …, publié au Lebon ») et vérifiez les références de votre document sans quitter Word.
- Word pour le web : Insertion → Compléments → Charger mon complément → coller https://api.legifrance.dev/office/manifest.xml
- La clé API est saisie dans le volet (jamais stockée côté serveur de page)
Erreurs
- 401 — clé absente, inconnue ou révoquée
- 400 — requête invalide (ex. asOf mal formée)
- 404 — article ou version introuvable
- 403 — endpoint sémantique sur un tier sans accès (upgrade requis)
- 429 / 402 — rate-limit / quota atteint
- 503 — recherche fédérée momentanément indisponible (tous moteurs)
Le contrat complet est décrit dans /openapi.json (OpenAPI 3).