API BOFiP — référence v1.
Toute la doctrine fiscale française en JSON propre. Recherche plein texte, sémantique, navigation hiérarchique et graphe de citations. Source : BOFiP — Etalab 2.0.
https://api.bofip.dev · Auth : X-API-Key: bk_… · Format : JSON UTF-8Authentification.
Toutes les requêtes (sauf /v1/health et /v1/stats) nécessitent un en-tête X-API-Key. Les clés ont le format bk_… et se gèrent depuis votre tableau de bord.
curl https://api.bofip.dev/v1/health \ -H "X-API-Key: bk_xxxxxxxxxxxxxxxxxxxx"
Sécurité. Une clé révoquée cesse d'être valide en moins d'une minute (cache TTL court). Ne jamais exposer une clé côté navigateur — l'API est conçue pour appels serveur-à-serveur.
Quotas et rate-limit.
Les quotas se réinitialisent au premier jour de chaque mois (UTC). Le rate-limit s'évalue sur des fenêtres glissantes d'une minute. Détails par plan sur la page tarifs.
- HTTP 402 · quota mensuel dépassé. La réponse contient un champ
upgrade_url. - HTTP 429 · rate-limit minute dépassé. Réessayer après 60 secondes.
- HTTP 403 · accès sémantique non autorisé sur ce plan (Free uniquement). Code
semantic_not_allowed.
Codes d'erreur.
Toute erreur renvoie un objet JSON { error: { code, message } }. Les codes 5xx sont remontés en interne, les 4xx documentent une erreur côté client.
Paramètre manquant ou invalide.
En-tête X-API-Key manquant ou invalide.
Quota mensuel dépassé. Upgrade requis.
Endpoint sémantique non disponible sur ce plan.
Document BOI ou route inconnue.
Trop de requêtes par minute.
Erreur serveur — réessayez ou contactez le support.
Endpoints
/v1/searchAuth requiseRecherche full-text FTS5.
Paramètres| Champ | Type | Défaut | Description |
|---|---|---|---|
qquery | string | requis | Requête FTS5 |
limitquery | integer | 20 | |
offsetquery | integer | 0 | |
domainequery | string | — | Filtre par domaine fiscal (IS, IR, TVA, BIC, ...) |
| Code | Description |
|---|---|
200 | OK |
400 | |
401 | |
402 | |
429 |
curl https://api.bofip.dev/v1/search?q=cession+titres&limit=10&offset=…&domaine=IS \ -H "X-API-Key: $BOFIP_API_KEY"
const res = await fetch(`https://api.bofip.dev/v1/search`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/search",
params={"q": "…", "limit": "…", "offset": "…", "domaine": "IS"}, headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/boi/{id}Auth requiseRécupère un document BOI complet.
Paramètres| Champ | Type | Défaut | Description |
|---|---|---|---|
idpath | string | requis |
| Code | Description |
|---|---|
200 | OK — payload complet avec contenu_html, contenu_texte, plan_classement, references |
400 | |
401 | |
404 | |
429 |
curl https://api.bofip.dev/v1/boi/BOI-IS-BASE-35-30-10 \ -H "X-API-Key: $BOFIP_API_KEY"
const id = "BOI-IS-BASE-35-30-10"
const res = await fetch(`https://api.bofip.dev/v1/boi/${id}`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/boi/{id}",
headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/boi/{id}/graphAuth requiseGraphe de références croisées.
Paramètres| Champ | Type | Défaut | Description |
|---|---|---|---|
idpath | string | requis | |
depthquery | integer | 1 | |
directionquery | string | cites | cites = sortants (BOI cités par celui-ci) ; citants = entrants (BOI qui le citent) ; both = bidirectionnel. |
| Code | Description |
|---|---|
200 | OK — {root, depth, nodes[], edges[]} |
400 | |
401 | |
404 | |
429 |
curl https://api.bofip.dev/v1/boi/BOI-IS-BASE-35-30-10/graph?depth=1&direction=… \ -H "X-API-Key: $BOFIP_API_KEY"
const id = "BOI-IS-BASE-35-30-10"
const res = await fetch(`https://api.bofip.dev/v1/boi/${id}/graph`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/boi/{id}/graph",
params={"depth": "…", "direction": "…"}, headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/boi/{id}/historiqueAuth requiseHistorique des versions du BOI.
Paramètres| Champ | Type | Défaut | Description |
|---|---|---|---|
idpath | string | requis |
| Code | Description |
|---|---|
200 | OK — {boi_id, versions:[{date_publication, date_mise_a_jour, statut, current}]} |
400 | |
401 | |
404 | |
429 |
curl https://api.bofip.dev/v1/boi/BOI-IS-BASE-35-30-10/historique \ -H "X-API-Key: $BOFIP_API_KEY"
const id = "BOI-IS-BASE-35-30-10"
const res = await fetch(`https://api.bofip.dev/v1/boi/${id}/historique`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/boi/{id}/historique",
headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/plan/{chemin}Auth requiseNavigation hiérarchique du plan de classement.
Paramètres| Champ | Type | Défaut | Description |
|---|---|---|---|
cheminpath | string | — | Chemin segmenté (ex: IS/BASE/35). Vide = racine. |
| Code | Description |
|---|---|
200 | OK — {chemin, children[], documents[]} |
400 | |
401 | |
429 |
curl https://api.bofip.dev/v1/plan/IS/BASE/35/30 \ -H "X-API-Key: $BOFIP_API_KEY"
const chemin = "IS/BASE/35/30"
const res = await fetch(`https://api.bofip.dev/v1/plan/${chemin}`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/plan/{chemin}",
headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/search/semanticAuth requiseRecherche sémantique (BGE-M3 / Workers AI + Vectorize).
Corps de requête (JSON){
"type": "object",
"required": [
"question"
],
"properties": {
"question": {
"type": "string",
"minLength": 3,
"maxLength": 500
},
"top_k": {
"type": "integer",
"default": 10,
"maximum": 50
}
}
}Réponses| Code | Description |
|---|---|
200 | OK — {results: [{boi_id, titre, extrait, score}]} |
400 | |
401 | |
402 | |
403 | Tier sans accès sémantique (code: semantic_not_allowed) — upgrade vers Solo IA ou supérieur |
429 |
curl https://api.bofip.dev/v1/search/semantic \
-X POST \
-H "X-API-Key: $BOFIP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"question": "Comment calculer une plus-value de cession ?",
"top_k": 10
}'const res = await fetch(`https://api.bofip.dev/v1/search/semantic`, {
method: 'POST',
headers: { 'X-API-Key': process.env.BOFIP_API_KEY!, 'Content-Type': 'application/json' },
body: JSON.stringify({
"question": "Comment calculer une plus-value de cession ?",
"top_k": 10
}),
})
const data = await res.json()import os, requests
r = requests.post(
f"https://api.bofip.dev/v1/search/semantic",
headers={"X-API-Key": os.environ["BOFIP_API_KEY"], "Content-Type": "application/json"},
json={
"question": "Comment calculer une plus-value de cession ?",
"top_k": 10
},
)
data = r.json()Le playground est disponible sur les endpoints GET. Pour cet endpoint POST, copiez le snippet ci-dessus.
/v1/changesAuth requiseDocuments publiés ou modifiés depuis une date.
Paramètres| Champ | Type | Défaut | Description |
|---|---|---|---|
sincequery | string | requis | Date ISO YYYY-MM-DD |
limitquery | integer | 500 |
| Code | Description |
|---|---|
200 | OK — {since, count, changes[]} |
400 | |
401 | |
429 |
curl https://api.bofip.dev/v1/changes?since=2024-01-01&limit=10 \ -H "X-API-Key: $BOFIP_API_KEY"
const res = await fetch(`https://api.bofip.dev/v1/changes`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/changes",
params={"since": "…", "limit": "…"}, headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/suggestAuth requiseAutocomplete sur les titres BOI.
Paramètres| Champ | Type | Défaut | Description |
|---|---|---|---|
qquery | string | requis | |
limitquery | integer | 10 |
| Code | Description |
|---|---|
200 | OK — {q, suggestions[]} |
400 | |
401 | |
429 |
curl https://api.bofip.dev/v1/suggest?q=cession+titres&limit=10 \ -H "X-API-Key: $BOFIP_API_KEY"
const res = await fetch(`https://api.bofip.dev/v1/suggest`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/suggest",
params={"q": "…", "limit": "…"}, headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/healthPublicHealth check (public).
Réponses| Code | Description |
|---|---|
200 | OK — {status, timestamp, service, version, source} |
curl https://api.bofip.dev/v1/health \ -H "X-API-Key: $BOFIP_API_KEY"
const res = await fetch(`https://api.bofip.dev/v1/health`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/health",
headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/statsPublicStatistiques publiques (public).
Réponses| Code | Description |
|---|---|
200 | OK — {total_documents, domaines[], last_import, source} |
curl https://api.bofip.dev/v1/stats \ -H "X-API-Key: $BOFIP_API_KEY"
const res = await fetch(`https://api.bofip.dev/v1/stats`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/stats",
headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
/v1/statusPublicStatus détaillé des bindings (D1/KV/R2/Vectorize).
Réponses| Code | Description |
|---|---|
200 | Tous bindings opérationnels |
503 | Au moins un binding dégradé — voir checks.{d1,kv,r2,vectorize}.ok |
curl https://api.bofip.dev/v1/status \ -H "X-API-Key: $BOFIP_API_KEY"
const res = await fetch(`https://api.bofip.dev/v1/status`, { headers: { 'X-API-Key': process.env.BOFIP_API_KEY! } })
const data = await res.json()import os, requests
r = requests.get(
f"https://api.bofip.dev/v1/status",
headers={"X-API-Key": os.environ["BOFIP_API_KEY"]},
)
data = r.json()▾ Essayer cet endpoint
Concepts
Identifiants BOI.
Chaque document du BOFiP possède un identifiant canonique de la forme BOI-DOMAINE-CHAPITRE-…-FEUILLET. Exemple : BOI-IS-BASE-35-30-10 = IS, Base d'imposition, chapitre 35, section 30, sous-section 10. Cet identifiant est stable dans le temps — la DGFiP en garantit l'URL canonique.
Plan de classement.
Le plan de classement structure tous les BOI en arborescence. L'endpoint GET /v1/plan/:chemin? permet de naviguer de proche en proche. Domaines de premier niveau : IS, IR, TVA, BIC, BNC, RPPM, CF, ENR, IF, PAT, TPS, REC.
Licence Etalab 2.0.
Le contenu BOFiP est diffusé sous Licence Ouverte Etalab 2.0. Chaque réponse de l'API contient un champ source: "BOFiP — Etalab 2.0" dont la mention est obligatoire dans toute réutilisation. Service indépendant, non affilié à la DGFiP.