CompanyBelgium

Traitement par lots avec l'API BCE/KBO : guide pratique

Comment traiter des milliers d'entreprises efficacement ? Guide complet sur le batch processing avec l'API BCE/KBO : import, validation et enrichissement en masse.

1 avril 20267 min de lecture

En bref

Le traitement par lots avec l'API BCE/KBO permet de valider, enrichir ou nettoyer des milliers de fiches entreprises en une seule passe. La stratégie repose sur trois briques : la normalisation des numéros BCE, une queue de concurrence limitée à 5-10 appels simultanés pour respecter le rate limiting, et l'export des résultats en CSV. Idéal pour les migrations CRM, la due diligence fournisseurs ou la prospection B2B en Belgique.

Pourquoi le traitement par lots ?

De nombreux cas d'usage nécessitent le traitement de grandes quantités de données entreprises :

  • Migration CRM : importer et enrichir des milliers de fiches clients
  • Nettoyage de base : valider et corriger les données existantes
  • Due diligence : vérifier un portefeuille de fournisseurs
  • Prospection : enrichir une liste de prospects B2B

Architecture recommandée

Code
1
2
3
4
5
6
7
8
9
┌──────────────┐     ┌───────────────┐     ┌──────────────┐
│  Fichier CSV │────▶│  Worker Queue  │────▶│  API BCE/KBO │
│  ou Base DB  │     │  (Bull/Redis)  │     │              │
└──────────────┘     └───────┬───────┘     └──────────────┘

                     ┌───────▼───────┐
                     │  Résultats    │
                     │  enrichis     │
                     └───────────────┘

Étape 1 : Préparer vos données

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { parse } from class="code-string">'csv-parse/sync';
import fs from class="code-string">'fs';

interface CompanyInput {
  name: string;
  bceNumber?: string;
  vatNumber?: string;
}

class="code-comment">// Lire et parser le fichier CSV
const csvContent = fs.readFileSync(class="code-string">'companies.csv', class="code-string">'utf-8');
const companies: CompanyInput[] = parse(csvContent, {
  columns: true,
  skip_empty_lines: true,
});

console.log(class="code-string">`${companies.length} entreprises à traiter`);

Étape 2 : Normaliser les numéros BCE

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function normalizeBceNumber(input: string): string | null {
  class="code-comment">// Supprimer tous les caractères non numériques
  const digits = input.replace(/\D/g, class="code-string">'');

  class="code-comment">// Un numéro BCE a 10 chiffres
  if (digits.length === 10) {
    return class="code-string">`${digits.slice(0, 4)}.${digits.slice(4, 7)}.${digits.slice(7)}`;
  }

  class="code-comment">// Certains omettent le 0 initial
  if (digits.length === 9) {
    return class="code-string">`0${digits.slice(0, 3)}.${digits.slice(3, 6)}.${digits.slice(6)}`;
  }

  return null; class="code-comment">// Format invalide
}

Étape 3 : File d'attente avec contrôle de débit

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
async function processBatch(
  companies: CompanyInput[],
  concurrency = 5,
  delayMs = 200
) {
  const results = [];
  const errors = [];

  for (let i = 0; i < companies.length; i += concurrency) {
    const batch = companies.slice(i, i + concurrency);

    const promises = batch.map(async (company) => {
      try {
        const bceNumber = company.bceNumber
          ? normalizeBceNumber(company.bceNumber)
          : null;

        if (!bceNumber) {
          class="code-comment">// Recherche par nom
          const res = await fetch(
            class="code-string">`https:class="code-comment">//companybelgium.be/api/companies/search?q=${encodeURIComponent(company.name)}&limit=1`,
            { headers: { class="code-string">'X-API-Key': apiKey, class="code-string">'X-API-Secret': apiSecret } }
          );
          return { input: company, result: await res.json(), matched: true };
        }

        class="code-comment">// Recherche par numéro BCE
        const res = await fetch(
          class="code-string">`https:class="code-comment">//companybelgium.be/api/companies/${bceNumber}`,
          { headers: { class="code-string">'X-API-Key': apiKey, class="code-string">'X-API-Secret': apiSecret } }
        );
        return { input: company, result: await res.json(), matched: true };
      } catch (error) {
        return { input: company, error, matched: false };
      }
    });

    const batchResults = await Promise.all(promises);
    results.push(...batchResults.filter(r => r.matched));
    errors.push(...batchResults.filter(r => !r.matched));

    class="code-comment">// Respecter le rate limit
    if (i + concurrency < companies.length) {
      await new Promise(resolve => setTimeout(resolve, delayMs));
    }

    class="code-comment">// Log progression
    console.log(class="code-string">`Progression : ${Math.min(i + concurrency, companies.length)}/${companies.length}`);
  }

  return { results, errors };
}

Étape 4 : Export des résultats

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { stringify } from class="code-string">'csv-stringify/sync';

function exportResults(results: any[]) {
  const rows = results.map(r => ({
    input_name: r.input.name,
    input_bce: r.input.bceNumber || class="code-string">'',
    matched_name: r.result?.name || class="code-string">'',
    matched_bce: r.result?.enterpriseNumber || class="code-string">'',
    status: r.result?.status || class="code-string">'non trouvé',
    legal_form: r.result?.juridicalForm || class="code-string">'',
    address: r.result?.address || class="code-string">'',
  }));

  const csv = stringify(rows, { header: true });
  fs.writeFileSync(class="code-string">'results_enriched.csv', csv);
  console.log(class="code-string">'Résultats exportés dans results_enriched.csv');
}

Bonnes pratiques

PratiquePourquoi
Concurrence limitée (5-10)Respecter le rate limiting
Délai entre lots (200ms)Lisser la charge
Normaliser les entréesMaximiser le taux de correspondance
Gérer les erreursNe pas bloquer tout le lot
Logger la progressionSuivre le traitement
Sauvegarder régulièrementReprendre en cas d'interruption

Conclusion

Le traitement par lots est essentiel pour les projets de grande envergure. Avec une bonne gestion du débit et des erreurs, vous pouvez traiter des dizaines de milliers d'entreprises efficacement. Consultez aussi le guide d'intégration Node.js/TypeScript de l'API BCE, l'article sur l'automatisation de la vérification des fournisseurs, la page sur les rate limits et le caching et le pipeline CRM pour la prospection B2B belge.

Questions fréquentes

Combien d'entreprises belges puis-je traiter en lot avec l'API BCE/KBO par heure ?

Cela dépend de votre plan tarifaire et de votre stratégie de concurrence. Avec une concurrence de 5 appels simultanés et un délai de 200 ms entre chaque lot, vous pouvez traiter environ 1 500 entreprises par minute sur un plan Pro. Pour des volumes plus importants, optimisez le cache (évitez de requêter plusieurs fois le même numéro BCE) et utilisez le traitement par lots avec une file d'attente comme BullMQ.

Comment normaliser les numéros BCE/KBO avant un traitement en lot ?

Un numéro BCE belge contient 10 chiffres au format 0XXX.XXX.XXX. Dans vos données sources, vous trouverez souvent des variantes : sans points, avec espaces, sans le zéro initial. Nettoyez tous les caractères non numériques, vérifiez que vous obtenez 9 ou 10 chiffres, et reformatez au standard 0XXX.XXX.XXX. Cela maximise le taux de correspondance lors de la recherche dans la base BCE.

Comment reprendre un traitement par lots en cas d'interruption avec l'API BCE/KBO ?

Sauvegardez les résultats au fur et à mesure dans un fichier ou une base de données, en marquant chaque entreprise comme traitée. En cas d'interruption, filtrez les entreprises déjà traitées avant de relancer le batch. Utilisez un index de reprise basé sur le numéro BCE pour éviter les doublons et identifier rapidement où vous en êtes.

Quelle est la différence entre le traitement par lots et les webhooks pour surveiller les entreprises belges ?

Le traitement par lots est adapté aux traitements ponctuels sur un grand volume (migration, audit, enrichissement initial). Les webhooks conviennent à la surveillance en temps réel d'un portefeuille précis : Company Belgium vous notifie dès qu'une entreprise change (adresse, statut, dirigeant, NACE). Pour une veille continue, combinez les deux approches : batch initial puis webhooks pour les mises à jour.

Prêt à commencer ?

Créez votre compte gratuitement et obtenez vos clés API en quelques minutes.

Commentaires

Chargement des commentaires…

Laisser un commentaire

Non publié — sert uniquement à vous notifier.

Les commentaires sont modérés avant publication.

Articles similaires