KVK Nummer Validatie: Regels, Format en Veelgemaakte Fouten
Technische deep-dive in het KVK-nummer format: validatieregels, verschil met vestigingsnummer, regex patronen en veelgemaakte programmeerfouten.
KVK Nummer Validatie: Regels, Format en Veelgemaakte Fouten
Het KVK-nummer lijkt simpel: acht cijfers. Maar in de praktijk gaat er verrassend veel mis bij het verwerken van KVK-nummers in software. Van voorloopnullen die verdwijnen tot verwarring met vestigingsnummers — in dit artikel behandelen we alle technische details die je moet weten.
Het KVK-nummer format
Een KVK-nummer (ook wel dossiernummer genoemd) heeft de volgende eigenschappen:
- Exact 8 cijfers lang
- Alleen numerieke tekens (0-9)
- Kan beginnen met een of meer nullen
- Wordt toegekend bij inschrijving en verandert nooit
- Is uniek per rechtspersoon
Voorbeelden van geldige KVK-nummers:
12345678
01234567
00123456
80001234
Voorbeelden van ongeldige nummers:
1234567 // Te kort (7 cijfers)
123456789 // Te lang (9 cijfers)
1234567A // Bevat een letter
12 345 678 // Bevat spaties (tenzij je die eruit filtert)
KVK-nummer vs. vestigingsnummer
Dit is een van de meest voorkomende bronnen van verwarring. Nederland kent twee soorten identificatienummers in het handelsregister:
KVK-nummer (dossiernummer)
- 8 cijfers
- Identificeert de rechtspersoon
- Eén per bedrijf
- Voorbeeld:
12345678
Vestigingsnummer
- 12 cijfers
- Identificeert een specifieke vestiging (locatie)
- Een bedrijf kan meerdere vestigingen hebben
- Voorbeeld:
000012345678
Een bedrijf met drie filialen heeft dus:
- 1 KVK-nummer:
12345678 - 3 vestigingsnummers:
000012345678,000012345679,000012345680
Als je systeem beide typen moet ondersteunen, valideer dan op basis van de lengte:
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: 'vestiging', value: cleaned };
} else {
return { type: 'invalid', value: null };
}
}
Client-side validatie met regex
Een goede regex voor KVK-nummervalidatie:
// Basis: exact 8 cijfers
const KVK_REGEX = /^\d{8}$/;
// Met optionele spaties en puntjes (die je eruit filtert)
function validateKvkNumber(input) {
if (!input || typeof input !== 'string') {
return { valid: false, error: 'Voer een KVK-nummer in' };
}
// Verwijder spaties, puntjes en streepjes
const cleaned = input.replace(/[\s.\-]/g, '');
if (!KVK_REGEX.test(cleaned)) {
if (cleaned.length < 8) {
return { valid: false, error: 'KVK-nummer is te kort (8 cijfers nodig)' };
}
if (cleaned.length > 8) {
return { valid: false, error: 'KVK-nummer is te lang (8 cijfers nodig)' };
}
return { valid: false, error: 'KVK-nummer mag alleen cijfers bevatten' };
}
// Aanvullende controle: niet alleen nullen
if (cleaned === '00000000') {
return { valid: false, error: 'Ongeldig KVK-nummer' };
}
return { valid: true, value: cleaned };
}
Python-voorbeeld
import re
def validate_kvk_number(kvk_number: str) -> tuple[bool, str]:
"""Valideer een KVK-nummer op format."""
if not kvk_number:
return False, "Voer een KVK-nummer in"
cleaned = re.sub(r'[\s.\-]', '', kvk_number)
if not re.match(r'^\d{8}$', cleaned):
return False, f"Ongeldig format: '{kvk_number}' (verwacht 8 cijfers)"
if cleaned == '00000000':
return False, "Ongeldig KVK-nummer"
return True, cleaned
Veelgemaakte fouten
1. Opslaan als integer
De meest voorkomende fout. Als je een KVK-nummer opslaat als INT of BIGINT in je database, verdwijnen de voorloopnullen:
-- FOUT: voorloopnullen verdwijnen
CREATE TABLE companies (
kvk_number INT PRIMARY KEY -- 01234567 wordt 1234567
);
-- GOED: gebruik een tekstveld
CREATE TABLE companies (
kvk_number CHAR(8) PRIMARY KEY -- 01234567 blijft 01234567
);
In JavaScript is dit probleem nog subtieler:
// FOUT: wordt als octaal getal geinterpreteerd in sommige contexten
const kvk = 01234567; // Niet wat je verwacht!
// GOED: altijd als string
const kvk = "01234567";
// FOUT: JSON.parse kan problemen geven als de bron ongestructureerd is
// GOED: zorg dat je API altijd strings retourneert voor KVK-nummers
2. Geen input-sanitatie
Gebruikers voeren KVK-nummers in op allerlei manieren:
12345678 // Correct
12.34.56.78 // Met puntjes
12 345 678 // Met spaties
KVK: 12345678 // Met prefix
012-345-678 // Met streepjes en 9 tekens
Bouw altijd een sanitatiestap in:
function sanitizeKvkInput(input) {
// Verwijder alles behalve cijfers
return input.replace(/\D/g, '').padStart(8, '0').slice(0, 8);
}
Let op: de padStart hierboven is alleen veilig als je zeker weet dat het om een KVK-nummer gaat waarvan de nullen zijn verdwenen. In de meeste gevallen wil je bij een te kort nummer liever een foutmelding geven dan aanvullen.
3. Niet server-side verifieren
Client-side validatie controleert alleen het format. Het zegt niets over of het nummer daadwerkelijk bestaat in het handelsregister. Een nummer als 99999999 passeert de regex-check, maar hoort mogelijk bij geen enkel bedrijf.
Verifieer daarom altijd server-side via een API-aanroep:
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-nummer niet gevonden' };
}
const data = await response.json();
return {
verified: true,
company: data.tradeName,
isActive: data.isActive
};
} catch (error) {
return { verified: false, error: 'Verificatie mislukt, probeer later opnieuw' };
}
}
4. Actieve en inactieve bedrijven niet onderscheiden
Een KVK-nummer kan toebehoren aan een bedrijf dat is uitgeschreven. Dit is cruciaal voor facturatie en contracten. Controleer altijd de status:
const result = await verifyKvkNumber('12345678');
if (result.verified && !result.isActive) {
showWarning('Dit bedrijf is uitgeschreven bij de KVK');
}
5. Geen foutmeldingen voor de gebruiker
Als validatie faalt, geef dan een duidelijke, specifieke foutmelding. “Ongeldig nummer” is niet genoeg. Vertel de gebruiker wat er mis is en wat er verwacht wordt.
Database-design aanbevelingen
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);
Conclusie
KVK-nummervalidatie is een klein onderdeel van je applicatie, maar fouten hierin hebben grote gevolgen. Door het nummer altijd als string op te slaan, input te sanitiseren, client-side en server-side te valideren en de bedrijfsstatus te controleren, voorkom je de meest voorkomende problemen.
Met KVKBase combineer je formatvalidatie en bestaanscontrole in een enkele API-aanroep, zodat je zeker weet dat het nummer niet alleen geldig is, maar ook daadwerkelijk bij een (actief) bedrijf hoort.