Generator · Dutch data
Dutch btw-id
Endpoint GET /v1/nl/btw-id
What it covers
Returns a valid Dutch btw-id (VAT identification number), e.g. `NL123456789B01`. Use `standard` to pick `modern` (default, MOD 97-10 checked) or `legacy` (elfproef core, `B01` suffix). Set `invalid=true` for a btw-id that fails validation, or `edge=true` for valid edge-case numbers.
This documents the generator's default 'modern' standard (params.standard defaults to 'modern' in create-generator.ts). The generator can also emit 'legacy' ids, which use the elfproef mod-11 core check and a fixed 'B01' suffix instead of the MOD 97-10 pair.
How it’s calculated
The modern (post-2020) Dutch btw-id is protected by an IBAN-style ISO 7064 MOD 97-10 check whose two digits make the alphanumeric-expanded value of 'NL{core}B' plus the check pair ≡ 1 (mod 97).
Algorithm
- Start from a 9-character numeric core (the drawn payload; the default 'modern' standard leaves the core unconstrained — any 9 digits).
- Form the letter-bearing string to be checked: 'NL' + core + 'B' (the country prefix NL, the 9-digit core, then the literal letter B that precedes the check pair).
- Convert every character of that string to its ISO 7064 / ICAO-9303 alphanumeric value: digits 0-9 map to 0-9, and letters map A=10 … Z=35 — so N=23, L=21, B=11. Concatenate each value's decimal representation (multi-digit values contribute both digits) into one long numeric string. For 'NL{9 digits}B' this yields '23' + '21' + the 9 core digits + '11'.
- Compute the two check digits with ISO 7064 MOD 97-10: take the numeric string as a big integer, multiply by 100, take that modulo 97, and subtract from 98: check = 98 - ((numeric × 100) mod 97).
- Left-pad the result to two digits with a leading zero if needed. This two-digit string is the check pair.
- The final btw-id is 'NL' + core + 'B' + checkPair. It satisfies the property that the numeric conversion of the whole letter-bearing string with the check pair appended is ≡ 1 (mod 97).
Worked example
NL123456782B?? (9-digit core 123456782, modern standard)
Core = 123456782. Letter-bearing string to check = 'NL123456782B'.
Convert characters: N=23, L=21, then the digits 1,2,3,4,5,6,7,8,2 as-is, then B=11. Concatenate → '23' '21' '123456782' '11' = 232112345678211.
Multiply by 100: 232112345678211 × 100 = 23211234567821100.
Modulo 97: 23211234567821100 mod 97 = 22.
Check = 98 - 22 = 76.
76 already has two digits, so the check pair is '76'.
Full btw-id = NL123456782B76. Verify: 23211234567821176 mod 97 = 1. Correct.The check pair is 76, giving the full btw-id NL123456782B76.
Edge cases
- The core itself carries no constraint under the modern standard; the entire integrity guarantee lives in the two trailing check digits over 'NL{core}B'.
- The legacy (pre-2020) standard is a different scheme entirely: its 9-digit core is validated by the Dutch 'elfproef' (weighted mod-11, weights 9,8,7,6,5,4,3,2 over the first 8, check digit = weighted sum mod 11 as a remainder), and the suffix is always the literal 'B01' rather than a computed pair. A core whose mod-11 remainder is 10 has no single-digit check and is redrawn.
- Because the letters N, L, B convert to two-digit values (23, 21, 11), the numeric string fed to MOD 97-10 is longer than the visible id and always begins '2321…' and ends '…11'.
Gotchas
- Do NOT run MOD 97-10 over the literal characters of 'NL123456782B'. Each letter must first be expanded to its alphanumeric value (N→23, L→21, B→11) and those decimal digits concatenated. Skipping the expansion gives the wrong modulus.
- The formula is 98 - ((numeric × 100) mod 97), not 97 - (…). Using 97 or forgetting the ×100 both produce a check pair that fails the ≡ 1 (mod 97) validation.
- The check pair must be zero-padded to two characters; a computed value like 7 must render as '07'.
Parameters
| Parameter | Type | Description |
|---|---|---|
| count | integer1–1000 | Number of records to return, 1–1000 (your plan may lower this). Omitted returns a single record; set it for a batch. |
| edge | boolean | Restrict output to valid edge-case btw-ids from the rare corners. |
| extreme | boolean | Return a correct value wrapped in a hostile encoding (untrimmed whitespace, invisible/zero-width characters, BOM, or bidi/combining marks). Homoglyphs are excluded so the value stays machine-parseable; it still validates after normalisation. |
| invalid | boolean | Return a btw-id that deliberately fails validation. |
| seed | integer | Integer seed for reproducible output: the same seed always yields the same record. |
| standard | "legacy" | "modern" | "both" | Numbering standard: `modern` (default), `legacy`, or `both` (random per record). |
Response fields
| Field | Type | Description |
|---|---|---|
| value | string | The full btw-id, e.g. `NL123456789B01`. |
| digits | string | The bare 9-character core between `NL` and `B`. |
| standard | "legacy" | "modern" | Which standard the value was built to. |
Other generators for Netherlands
The same kind of identifier elsewhere
Try it