KVKBase Team

Intégrer une API d'entreprises belges : guide développeur

Intégrer une API de données d'entreprises belges : authentification, consultation, recherche, lots, erreurs, cache et autocomplétion au paiement.

belgiqueapiintégrationdéveloppeur

Intégrer des données d’entreprises belges dans un CRM, un outil de facturation ou un formulaire de commande demande peu de code, mais quelques choix de conception évitent de gaspiller des appels. Ce guide parcourt l’API KVKBase dans l’ordre où vous la rencontrerez : authentification, consultation, recherche, lots, gestion des erreurs, cache, puis le scénario d’autocomplétion le plus courant, celui du paiement en ligne. Les endpoints complets sont décrits dans la référence de l’API.

Authentification et base

Tous les appels vont vers https://api.kvkbase.nl et portent l’en-tête Authorization: Bearer YOUR_API_KEY. Les réponses sont en JSON. Gardez la clé côté serveur : un appel direct depuis le navigateur l’expose à quiconque ouvre les outils de développement. Créez votre clé après l’inscription (le plan gratuit offre 50 tokens par mois, sans carte bancaire).

EndpointRôleCoût
GET /v1/be/lookup/{numero}Fiche complète d’une entreprise1 token
GET /v1/be/search?q=...Recherche par nom (25 résultats max)1 token
GET /v1/be/validate/vat/{numero}Contrôle VIES1 token
POST /v1/be/lookup/batchJusqu’à 25 numéros1 token par numéro

Le paramètre optionnel ?lang=nl|fr|de|en localise les libellés (forme juridique, situation juridique). La valeur par défaut est nl : passez lang=fr pour une interface francophone. L’endpoint générique GET /v1/lookup/{number} accepte aussi les numéros belges.

Normaliser et valider avant d’appeler

Un numéro d’entreprise compte dix chiffres et commence par 0 ou 1. Les deux derniers chiffres forment une paire de contrôle : 97 moins (les huit premiers chiffres modulo 97). Le rejet côté serveur est gratuit, mais le faire dès la saisie donne un retour immédiat à l’utilisateur et protège votre propre quota de requêtes. Les anciens numéros de TVA à neuf chiffres reçoivent un 0 en tête.

export function normalizeNumber(input) {
  let digits = String(input).replace(/^BE/i, "").replace(/\D/g, "");
  if (digits.length === 9) digits = "0" + digits;
  return digits;
}

export function hasValidCheckPair(digits) {
  if (!/^[01]\d{9}$/.test(digits)) return false;
  return 97 - (Number(digits.slice(0, 8)) % 97) === Number(digits.slice(8));
}

Testez-la avec des numéros que vous connaissez. Ceux des exemples ci-dessous, comme 0123.456.789, sont purement illustratifs. Pour la différence entre numéro d’entreprise et numéro de TVA, voyez ce guide.

Consultation : un numéro, une fiche

curl -s "https://api.kvkbase.nl/v1/be/lookup/0123.456.789?lang=fr" \
  -H "Authorization: Bearer YOUR_API_KEY"

La réponse contient notamment cbeNumber, cbeNumberFormatted, name, tradingNames[], legalForm, legalFormShort, entityType, address, isActive, juridicalSituation, activities[], establishments[], websites[], un bloc vat et un bloc source (cachedAt, stale). Adaptez l’accès aux champs à l’enveloppe décrite dans la référence. Le champ isActive peut valoir true, false ou null : traitez null comme « inconnu », pas comme « inactif ».

Recherche : retrouver un numéro depuis un nom

curl -s "https://api.kvkbase.nl/v1/be/search?q=boulangerie&postalCode=1000&pageSize=10" \
  -H "Authorization: Bearer YOUR_API_KEY"

q demande au moins deux caractères, postalCode quatre chiffres. Chaque résultat donne le numéro, le nom, le type d’entité, la forme juridique, le code postal et la commune. Affichez une liste de choix à l’utilisateur et ne lancez la consultation qu’une fois la sélection faite : une recherche suivie d’une consultation coûte 2 tokens, pas davantage. Pour les cas d’usage manuels, l’outil de recherche gratuit suffit.

Lots : enrichir une liste existante

Pour une base de contacts, envoyez des lots de 25 numéros au plus :

import os
import requests

BASE = "https://api.kvkbase.nl"
HEADERS = {"Authorization": f"Bearer {os.environ['KVKBASE_API_KEY']}"}

def enrich(numbers):
    out = {}
    for i in range(0, len(numbers), 25):
        chunk = numbers[i:i + 25]
        r = requests.post(
            f"{BASE}/v1/be/lookup/batch",
            headers=HEADERS,
            json={"cbeNumbers": chunk, "lang": "fr"},
            timeout=30,
        )
        r.raise_for_status()
        body = r.json()
        results = body.get("results", body)
        for number, item in results.items():
            out[number] = item["data"] if item["success"] else None
    return out

Un lot peut réussir partiellement : testez success pour chaque numéro et consignez les erreurs au lieu d’interrompre le traitement. Dédoublonnez et filtrez les numéros invalides avant d’envoyer, chaque numéro du lot coûte 1 token.

Erreurs et nouvelles tentatives

CodeHTTPQue faire
INVALID_CBE_NUMBER400Corriger la saisie, ne pas réessayer
NOT_FOUND404Afficher « numéro introuvable », ne pas réessayer
QUOTA_EXCEEDED / limite de débit429Patienter ; un quota épuisé ne se règle pas par des essais
UPSTREAM_ERROR502Réessayer avec délai croissant
UPSTREAM_BUDGET503Réessayer plus tard
const BASE = "https://api.kvkbase.nl";
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

export async function kvk(path, options = {}, attempt = 0) {
  const res = await fetch(BASE + path, {
    ...options,
    headers: {
      Authorization: `Bearer ${process.env.KVKBASE_API_KEY}`,
      "Content-Type": "application/json",
      ...options.headers,
    },
  });
  if ([429, 502, 503].includes(res.status) && attempt < 3) {
    await sleep(2 ** attempt * 1000 + Math.random() * 250);
    return kvk(path, options, attempt + 1);
  }
  if (!res.ok) throw Object.assign(new Error("KVKBase " + res.status), { status: res.status });
  return res.json();
}

Limitez toujours le nombre d’essais. Après trois échecs, mettez la tâche en file d’attente plutôt que de bloquer l’utilisateur.

Stocker et mettre en cache

Chaque réponse contient source.cachedAt et source.stale. Conservez ces valeurs : elles indiquent l’âge de l’information, et les données ne sont pas en temps réel. Une stratégie simple et économe :

  • Stockez la fiche reçue avec l’horodatage de votre appel.
  • Réutilisez-la pendant une durée adaptée à votre usage (quelques jours pour un formulaire, un contrôle récent pour une décision de crédit).
  • Rafraîchissez à la demande avant une opération sensible, par exemple avant d’émettre une première facture.
  • Si vous stockez des entreprises individuelles, leur adresse peut être celle d’un domicile : appliquez les règles du RGPD pour la durée de conservation et l’accès.

Faire correspondre les champs avec votre CRM ou votre facture

Champ de l’APIChamp de votre formulaire
nameRaison sociale
legalFormShortForme juridique (SRL, SA…)
vat.numberNuméro de TVA (à confirmer avec VIES)
address.street + houseNumberRue et numéro
address.postalCode, cityCode postal, commune
activities[] où isMainActivité principale

Pour la facturation, le numéro de TVA dérivé reste un candidat tant que vat.valid n’est pas confirmé. La procédure est détaillée dans le guide VIES.

Le parcours de paiement

  1. Le client saisit son numéro d’entreprise, ou tape le début de son nom.
  2. Votre interface valide le format et la paire de contrôle. Rien n’est envoyé si la saisie est fausse.
  3. Votre serveur appelle lookup (ou search puis lookup) avec lang=fr.
  4. Vous préremplissez raison sociale, adresse et TVA, en laissant tous les champs modifiables.
  5. Si isActive vaut false, affichez un avertissement plutôt qu’un blocage automatique.

Gardez l’humain dans la boucle : une donnée préremplie n’est pas une garantie d’exhaustivité. Pour un contrôle plus poussé d’un client ou d’un fournisseur, voyez le guide de vérification.

Surveiller vos tokens

Comptez vos tokens avant de les consommer : validation locale, dédoublonnage, cache. Une consultation, une recherche et une validation VIES coûtent chacune 1 token, donc un parcours « recherche, consultation, validation VIES » en coûte 3. Les tarifs complets sont sur la page prix, et la page Belgique présente le service dans son ensemble.

Questions fréquentes

Quel format de numéro d'entreprise l'API accepte-t-elle ?
Tous les formats courants : 0821.015.819, 0821015819 et BE0821015819. Vous pouvez donc transmettre la saisie de l'utilisateur telle quelle, mais il reste utile de la valider côté client pour éviter un aller-retour inutile.
Un numéro mal formé consomme-t-il des tokens ?
Non. Un numéro malformé est rejeté avant toute recherche et renvoie une erreur INVALID_CBE_NUMBER (400) sans coût. Une consultation, une recherche ou une validation VIES coûte 1 token.
Combien de numéros puis-je envoyer dans un appel par lots ?
25 au maximum par appel. Chaque numéro du lot coûte 1 token et la réponse est indexée par numéro, avec success et data ou error pour chacun.
Faut-il réessayer après une erreur 429, 502 ou 503 ?
Oui, avec un délai croissant et un nombre d'essais limité. Un quota mensuel épuisé ne se résout pas en réessayant : dans ce cas, passez à un plan supérieur ou attendez le mois suivant.