Version 0.6.0

eu-validate documentation

Validate EU identifiers locally in Node or the browser. The offline library has zero runtime dependencies; its validators make no network requests. Hosted VIES and KvK registration lookups are planned separately.

Install and validate

npm install @alosha/eu-validate@^0.6.0
import { validateVAT, validateIBAN, validateBSN } from '@alosha/eu-validate'

validateVAT('NL123456782B01').valid       // true
validateIBAN('NL91ABNA0417164300').valid   // true
validateBSN('111222334').errors          // ['CHECKSUM_FAILED']

ESM and CommonJS exports include TypeScript declarations. VAT, IBAN, BSN and KvK inputs are normalized by removing spaces, dots, dashes and slashes and converting letters to uppercase. Postal inputs are trimmed and uppercased.

Offline checks and coverage

validateVAT
EU VAT format and available checksum rules for all 27 country prefixes. Documented FR, CZ and LV sub-cases have no offline-verifiable checksum.
validateIBAN
National character layout, exact length and mod-97 for all 89 countries in SWIFT IBAN registry release 103 (September 2026).
validateBSN
Dutch eight/nine-digit format and 11-proof; all-zero values fail.
validateKvK
Eight-digit Dutch company-number format. It does not establish registration; checksum is null.
validatePostalCode
Format rules for NL, DE, FR, BE, ES and IT, with explicit coverage and an optional strict mode.
validate
Dispatch by type. Postal calls also accept country and strict options.

Passing checks does not establish company registration, bank-account existence, identity or account ownership. IBAN validation does not implement every domestic account checksum.

Read a validation result

{
  valid: true,
  input: 'NL91 ABNA 0417 1643 00',
  normalized: 'NL91ABNA0417164300',
  country: 'NL',
  type: 'iban',
  checks: { format: true, checksum: true },
  errors: []
}

Check valid for the validator's outcome. Require checks.checksum === true when your application needs a confirmed checksum; null means the checksum did not run or cannot be checked for that case. For postal codes, also inspect checks.formatSupported. isValid narrows valid: true, while assertValid throws ValidationError when valid is false.

Postal coverage and strict mode

Default mode preserves historical acceptance for EU countries without a format pattern and reports formatSupported: false. That acceptance does not confirm the format. Choose strict: true to reject an unchecked format with FORMAT_NOT_SUPPORTED. Supported patterns behave the same in both modes.

import { validatePostalCode, validate } from '@alosha/eu-validate'

validatePostalCode('1011 AB', { country: 'NL', strict: true })
// valid: true, checks.formatSupported: true

validatePostalCode('D02 AF30', { country: 'IE', strict: true })
// valid: false, errors: ['FORMAT_NOT_SUPPORTED']

validate('D02 AF30', { type: 'postalCode', country: 'IE' })
// legacy acceptance: valid: true, checks.formatSupported: false

Country codes are trimmed and uppercased. EU_COUNTRIES uses ISO GR for Greece; VAT-specific tables and results use EL. Postal validation accepts GR or the historical EL alias and returns GR.

Inputs, errors and privacy

MAX_INPUT_LENGTH is 256 raw UTF-16 code units. Length is checked before trimming, so an excessive whitespace-only string returns INPUT_TOO_LONG. Validation reports the first applicable failure. Handle type: null from malformed dispatcher options before passing the result to helpers that expect a known identifier type.

INVALID_INPUT
A JavaScript caller supplied a non-string. The result has input: an empty string; no coercion is performed.
INPUT_TOO_LONG
The raw identifier exceeds 256 UTF-16 code units, before trimming or normalization.
EMPTY_INPUT
Empty or whitespace-only input within the raw length limit.
INVALID_OPTIONS
Malformed dispatcher or postal options. An unknown dispatcher type returns type: null.
COUNTRY_REQUIRED
Postal country is missing or blank.
UNKNOWN_COUNTRY
VAT or IBAN country has no supported rule.
UNSUPPORTED_COUNTRY
Postal country is outside the supported EU set.
FORMAT_NOT_SUPPORTED
Postal strict mode found no format rule. This reports missing coverage, not a known bad postal code.
INVALID_FORMAT
The identifier fails a supported character-layout or country-length rule.
CHECKSUM_FAILED
A performed checksum failed.
CHECKSUM_NOT_VERIFIABLE
Informational VAT checksum exception or a legacy postal coverage gap; valid can still be true.

ValidationError messages omit the identifier. Its result property remains accessible but is non-enumerable. Validation results themselves contain the original and normalized values: avoid explicitly logging sensitive result fields.

Upgrade from 0.5.0

Review the new input and option errors, the 256-code-unit limit, Greek country metadata and stricter IBAN acceptance. Costa Rica's IBAN length is corrected to 22. Postal strict mode is opt-in; the default compatibility behavior is retained. The release is verified by 400 tests and installed-package runtime and type checks on Node 22, 24 and 26.