API d'entreprises belges : exemples en curl, JavaScript et Python
Exemples de code fonctionnels pour l'API d'entreprises belges : fiche par numéro, recherche par nom et code postal, TVA, gestion des erreurs et des quotas.
Pour prendre en main une API, rien ne vaut quelques exemples que l’on peut exécuter tout de suite. Vous trouverez ici du code en curl, en JavaScript (fetch, Node 18 ou plus récent) et en Python (requests) pour les quatre opérations les plus courantes : obtenir la fiche d’une entreprise à partir de son numéro, chercher par nom et code postal, contrôler un numéro de TVA, puis gérer proprement les erreurs et les limites de débit. Pour la vue d’ensemble d’une intégration, consultez d’abord le guide d’intégration de l’API.
Avant de commencer
Tous les appels visent https://api.kvkbase.nl et portent l’en-tête Authorization: Bearer YOUR_API_KEY. Vous obtenez votre clé en créant un compte : le plan gratuit comprend 50 tokens par mois, sans carte bancaire. Les plans supérieurs sont détaillés sur la page des tarifs.
Dans les exemples, la clé est lue dans la variable d’environnement KVKBASE_API_KEY. Le numéro 0123.456.789 est purement illustratif : remplacez-le par un numéro que vous connaissez. La liste complète des champs se trouve dans la référence de l’API.
Obtenir une fiche à partir du numéro d’entreprise
Le numéro peut s’écrire avec ou sans points, avec ou sans préfixe BE. Le paramètre facultatif lang (nl, fr, de ou en) choisit la langue des libellés, comme la forme juridique. Pour un affichage francophone, passez lang=fr.
curl -s "https://api.kvkbase.nl/v1/be/lookup/0123.456.789?lang=fr" \
-H "Authorization: Bearer YOUR_API_KEY"
En JavaScript, une petite fonction d’aide suffit. Elle lève une exception qui porte le statut HTTP, le code d’erreur et le délai d’attente éventuel, ce qui simplifie le code appelant.
const BASE = "https://api.kvkbase.nl";
const KEY = process.env.KVKBASE_API_KEY;
async function api(path, init = {}) {
const res = await fetch(`${BASE}${path}`, {
...init,
headers: { Authorization: `Bearer ${KEY}`, ...init.headers },
signal: AbortSignal.timeout(10_000),
});
if (!res.ok) {
const body = await res.json().catch(() => ({}));
throw Object.assign(new Error(body?.error?.message ?? `HTTP ${res.status}`), {
status: res.status,
code: body?.error?.code,
retryAfter: Number(res.headers.get("Retry-After")) || null,
});
}
return res.json();
}
const entreprise = await api("/v1/be/lookup/0123.456.789?lang=fr");
console.log(entreprise.name, entreprise.legalFormShort, entreprise.isActive);
L’équivalent en Python avec requests :
import os
import requests
BASE = "https://api.kvkbase.nl"
SESSION = requests.Session()
SESSION.headers["Authorization"] = f"Bearer {os.environ['KVKBASE_API_KEY']}"
def api(path, **kwargs):
r = SESSION.get(f"{BASE}{path}", timeout=10, **kwargs)
r.raise_for_status()
return r.json()
entreprise = api("/v1/be/lookup/0123.456.789", params={"lang": "fr"})
print(entreprise["name"], entreprise["legalFormShort"], entreprise["isActive"])
La réponse contient notamment cbeNumber, cbeNumberFormatted, name, tradingNames, legalForm, legalFormShort, entityType, address, isActive, juridicalSituation, activities, establishments et vat. Le bloc source indique, avec cachedAt et stale, l’âge de la donnée servie.
Rechercher par nom et code postal
Sans numéro, utilisez GET /v1/be/search. Passez un nom dans q (deux caractères au minimum), un postalCode de quatre chiffres, ou les deux. La combinaison donne les résultats les plus précis.
curl -s "https://api.kvkbase.nl/v1/be/search?q=boulangerie&postalCode=4000&pageSize=10" \
-H "Authorization: Bearer YOUR_API_KEY"
const params = new URLSearchParams({ q: "boulangerie", postalCode: "4000", pageSize: "10" });
const { results, capped } = await api(`/v1/be/search?${params}`);
for (const hit of results) {
console.log(hit.cbeNumberFormatted, hit.name, hit.postalCode, hit.city);
}
if (capped) console.log("Il y a peut-être d'autres résultats : affinez la recherche.");
data = api("/v1/be/search", params={"q": "boulangerie", "postalCode": "4000", "pageSize": 10})
for hit in data["results"]:
print(hit["cbeNumberFormatted"], hit["name"], hit["postalCode"], hit["city"])
if data["capped"]:
print("Il y a peut-être d'autres résultats : affinez la recherche.")
Une recherche ne renvoie jamais plus de 25 résultats, même si vous augmentez page : page et pageSize ne découpent que ces 25 résultats. Quand capped vaut true, la liste est peut-être incomplète et il faut préciser les critères. Le guide sur la recherche par code postal et par secteur approfondit ce point.
Contrôler un numéro de TVA
Pour la TVA, appelez GET /v1/be/validate/vat/{numero}. Un numéro de TVA belge se compose de BE suivi du numéro d’entreprise, sans points.
curl -s "https://api.kvkbase.nl/v1/be/validate/vat/BE0123456789" \
-H "Authorization: Bearer YOUR_API_KEY"
const tva = await api("/v1/be/validate/vat/BE0123456789");
if (tva.status === "validated") {
console.log(tva.valid ? "Numéro de TVA actif" : "Numéro de TVA non valide", tva.name);
} else if (tva.status === "stale") {
console.log("Ancienne réponse VIES datée du", tva.validatedAt, "(VIES injoignable)");
} else {
console.log("Format ou clé de contrôle incorrects");
}
La réponse comprend vatNumber, valid, name, address, validatedAt, status et checksumValid. Le statut validated indique que VIES a répondu. Si VIES est momentanément injoignable, status peut valoir stale (réponse antérieure, datée) et un numéro qui échoue au contrôle de la clé reçoit malformed. Ne traitez jamais stale comme une confirmation fraîche. Pour comprendre la clé de contrôle, lisez le guide sur la structure du numéro de TVA belge.
Gérer les erreurs
Toutes les erreurs ont la même forme : {"error": {"code": "...", "message": "..."}}. Décidez à partir du statut HTTP et du code.
| Code | Statut | Action |
|---|---|---|
INVALID_CBE_NUMBER | 400 | Ne pas réessayer, faire corriger la saisie |
INVALID_QUERY | 400 | Corriger la recherche (nom trop court, code postal sans quatre chiffres) |
NOT_FOUND | 404 | Ne pas réessayer, le numéro n’existe pas dans les données |
RATE_LIMIT_EXCEEDED / QUOTA_EXCEEDED | 429 | Voir la section suivante |
UPSTREAM_ERROR | 502 | Réessayer un nombre limité de fois, avec délai croissant |
UPSTREAM_BUDGET | 503 | Attendre la durée de Retry-After, puis réessayer |
La distinction essentielle : un 404 dit que le numéro n’existe pas, tandis qu’un 502 ou un 503 dit que nous n’avons pas pu vérifier à cet instant. Les confondre ferait passer une entreprise existante pour inconnue.
Limites de débit et nouvelles tentatives
Un 429 a deux causes possibles. En cas de limite de débit, vous allez trop vite : la réponse contient Retry-After en secondes, et les en-têtes X-RateLimit-Limit et X-RateLimit-Remaining indiquent votre marge. Si le quota mensuel est épuisé, attendre est inutile : il faut changer de plan ou patienter jusqu’au mois suivant.
async function apiWithRetry(path, attempts = 4) {
for (let i = 0; i < attempts; i++) {
try {
return await api(path);
} catch (e) {
const retryable = [429, 502, 503].includes(e.status) && e.code !== "QUOTA_EXCEEDED";
if (!retryable || i === attempts - 1) throw e;
const wait = e.retryAfter ?? 2 ** i;
await new Promise((r) => setTimeout(r, wait * 1000));
}
}
}
import time
def api_with_retry(path, attempts=4, **kwargs):
for i in range(attempts):
try:
return api(path, **kwargs)
except requests.HTTPError as e:
r = e.response
code = (r.json().get("error") or {}).get("code") if r.content else None
retryable = r.status_code in (429, 502, 503) and code != "QUOTA_EXCEEDED"
if not retryable or i == attempts - 1:
raise
time.sleep(int(r.headers.get("Retry-After", 2 ** i)))
Si vous enchaînez beaucoup d’appels, surveillez X-RateLimit-Remaining pour ralentir à temps au lieu de réagir après coup.
Bonnes pratiques en production
- Fixez toujours un délai maximal sur chaque appel.
- Validez les numéros localement avant d’appeler, comme l’explique le guide sur la clé de contrôle.
- Stockez les réponses avec votre propre horodatage pour ne pas payer à chaque affichage.
- N’exposez pas sans précaution les personnes physiques (indépendants en nom propre) : leur adresse peut être privée.
Pour aller plus loin
Pour traiter toute une liste de numéros d’un coup, lisez le guide pour vérifier des entreprises en masse. La page d’accueil belge présente le produit, et vous pouvez d’abord tester l’outil gratuit pour rechercher un numéro d’entreprise. Sur la différence entre les deux numéros, voyez le guide numéro d’entreprise et numéro de TVA.