Validation du numéro KVK : règles, format et erreurs courantes
KVKBase Team

Validation du numéro KVK : règles, format et erreurs courantes

Format du numéro KVK : règles de validation, différence avec le numéro d'établissement, expressions régulières et erreurs de programmation fréquentes.

kvkvalidationdéveloppeurs

Le numéro KVK semble simple : huit chiffres. Pourtant, en pratique, beaucoup de choses tournent mal lors de son traitement dans un logiciel. Des zéros initiaux qui disparaissent à la confusion avec les numéros d’établissement, cet article passe en revue tous les détails techniques à connaître.

Le format du numéro KVK

Un numéro KVK (aussi appelé numéro de dossier) présente les caractéristiques suivantes :

  • Exactement 8 chiffres
  • Uniquement des caractères numériques (0-9)
  • Peut commencer par un ou plusieurs zéros
  • Attribué lors de l’immatriculation et ne change jamais
  • Unique par entité juridique

Exemples de numéros KVK valides :

12345678
01234567
00123456
80001234

Exemples de numéros invalides :

1234567    // Trop court (7 chiffres)
123456789  // Trop long (9 chiffres)
1234567A   // Contient une lettre
12 345 678 // Contient des espaces (sauf si vous les supprimez)

Numéro KVK et numéro d’établissement

C’est l’une des sources de confusion les plus fréquentes. Le registre du commerce néerlandais comporte deux types de numéros d’identification :

Numéro KVK (numéro de dossier)

  • 8 chiffres
  • Identifie l’entité juridique
  • Un seul par entreprise
  • Exemple : 12345678

Numéro d’établissement (vestigingsnummer)

  • 12 chiffres
  • Identifie un établissement précis
  • Une entreprise peut avoir plusieurs établissements
  • Exemple : 000012345678

Une entreprise avec trois établissements possède donc :

  • 1 numéro KVK : 12345678
  • 3 numéros d’établissement : 000012345678, 000012345679, 000012345680

Si votre système doit prendre en charge les deux types, validez en fonction de la longueur :

function identifyNumberType(input) {
  const cleaned = input.replace(/\D/g, '');

  if (cleaned.length === 8) {
    return { type: 'kvk', value: cleaned };
  } else if (cleaned.length === 12) {
    return { type: 'branch', value: cleaned };
  } else {
    return { type: 'invalid', value: null };
  }
}

Validation côté client avec une expression régulière

Une bonne expression régulière pour valider un numéro KVK :

// Basique : exactement 8 chiffres
const KVK_REGEX = /^\d{8}$/;

// Avec espaces et points facultatifs (que vous supprimez)
function validateKvkNumber(input) {
  if (!input || typeof input !== 'string') {
    return { valid: false, error: 'Please enter a KVK number' };
  }

  // Supprimer les espaces, points et tirets
  const cleaned = input.replace(/[\s.\-]/g, '');

  if (!KVK_REGEX.test(cleaned)) {
    if (cleaned.length < 8) {
      return { valid: false, error: 'KVK number is too short (8 digits required)' };
    }
    if (cleaned.length > 8) {
      return { valid: false, error: 'KVK number is too long (8 digits required)' };
    }
    return { valid: false, error: 'KVK number may only contain digits' };
  }

  // Vérification supplémentaire : pas uniquement des zéros
  if (cleaned === '00000000') {
    return { valid: false, error: 'Invalid KVK number' };
  }

  return { valid: true, value: cleaned };
}

Exemple en Python

import re

def validate_kvk_number(kvk_number: str) -> tuple[bool, str]:
    """Valide le format d'un numéro KVK."""
    if not kvk_number:
        return False, "Please enter a KVK number"

    cleaned = re.sub(r'[\s.\-]', '', kvk_number)

    if not re.match(r'^\d{8}$', cleaned):
        return False, f"Invalid format: '{kvk_number}' (expected 8 digits)"

    if cleaned == '00000000':
        return False, "Invalid KVK number"

    return True, cleaned

Erreurs courantes

1. Stocker le numéro comme un entier

L’erreur la plus fréquente. Si vous stockez un numéro KVK en INT ou BIGINT dans votre base de données, les zéros initiaux disparaissent :

-- FAUX : les zéros initiaux disparaissent
CREATE TABLE companies (
  kvk_number INT PRIMARY KEY  -- 01234567 devient 1234567
);

-- CORRECT : utiliser un champ texte
CREATE TABLE companies (
  kvk_number CHAR(8) PRIMARY KEY  -- 01234567 reste 01234567
);

En JavaScript, le problème est encore plus sournois :

// FAUX : interprété comme de l'octal dans certains contextes
const kvk = 01234567; // Pas ce que vous attendez !

// CORRECT : toujours sous forme de chaîne
const kvk = "01234567";

// FAUX : JSON.parse peut poser problème si la source n'est pas structurée
// CORRECT : veillez à ce que votre API renvoie toujours des chaînes pour les numéros KVK

2. Aucune normalisation de la saisie

Les utilisateurs saisissent les numéros KVK de toutes sortes de façons :

12345678       // Correct
12.34.56.78    // Avec des points
12 345 678     // Avec des espaces
KVK: 12345678  // Avec un préfixe
012-345-678    // Avec des tirets et 9 caractères

Prévoyez toujours une étape de normalisation :

function sanitizeKvkInput(input) {
  // Supprimer tout sauf les chiffres
  return input.replace(/\D/g, '').padStart(8, '0').slice(0, 8);
}

Remarque : le padStart ci-dessus n’est sûr que si vous êtes certain que la saisie est un numéro KVK qui a perdu ses zéros initiaux. Dans la plupart des cas, il vaut mieux afficher un message d’erreur pour un numéro trop court plutôt que de le compléter.

3. Ne pas vérifier côté serveur

La validation côté client ne contrôle que le format. Elle ne dit rien sur l’existence réelle du numéro dans le registre du commerce. Un numéro comme 99999999 passe le contrôle par expression régulière, mais peut n’appartenir à aucune entreprise.

Vérifiez toujours côté serveur via un appel à l’API :

async function verifyKvkNumber(kvkNumber) {
  const formatCheck = validateKvkNumber(kvkNumber);
  if (!formatCheck.valid) {
    return { verified: false, error: formatCheck.error };
  }

  try {
    const response = await fetch(
      `https://api.kvkbase.nl/api/v1/lookup/${formatCheck.value}`,
      { headers: { 'Authorization': `Bearer ${API_KEY}` } }
    );

    if (response.status === 404) {
      return { verified: false, error: 'KVK number not found' };
    }

    const data = await response.json();
    return {
      verified: true,
      company: data.tradeName,
      isActive: data.isActive
    };
  } catch (error) {
    return { verified: false, error: 'Verification failed, please try again later' };
  }
}

4. Ne pas distinguer les entreprises actives et inactives

Un numéro KVK peut appartenir à une entreprise radiée. C’est crucial pour la facturation et les contrats. Vérifiez toujours le statut :

const result = await verifyKvkNumber('12345678');
if (result.verified && !result.isActive) {
  showWarning('This company has been deregistered from the KVK');
}

5. Aucun message d’erreur destiné à l’utilisateur

Lorsque la validation échoue, fournissez un message d’erreur clair et précis. « Numéro invalide » ne suffit pas. Indiquez à l’utilisateur ce qui ne va pas et ce qui est attendu.

Recommandations pour la conception de la base de données

CREATE TABLE companies (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  kvk_number CHAR(8) NOT NULL UNIQUE,
  vestiging_number CHAR(12),
  trade_name VARCHAR(255) NOT NULL,
  is_active BOOLEAN DEFAULT true,
  verified_at TIMESTAMP WITH TIME ZONE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),

  CONSTRAINT valid_kvk_format CHECK (kvk_number ~ '^\d{8}$'),
  CONSTRAINT valid_vestiging_format
    CHECK (vestiging_number IS NULL OR vestiging_number ~ '^\d{12}$')
);

CREATE INDEX idx_companies_kvk ON companies(kvk_number);

Conclusion

La validation du numéro KVK ne représente qu’une petite partie de votre application, mais les erreurs à ce niveau ont des conséquences disproportionnées. En stockant toujours le numéro sous forme de chaîne, en normalisant la saisie, en validant à la fois côté client et côté serveur et en vérifiant le statut de l’entreprise, vous évitez les problèmes les plus courants.

Avec KVKBase, vous pouvez combiner la validation du format et la vérification de l’existence en un seul appel à l’API : vous savez ainsi que le numéro est non seulement valide, mais qu’il appartient bien à une entreprise (active).