Generator · Luxembourg data
Luxembourg matricule
Endpoint GET /v1/lu/matricule
What it covers
Returns a valid Luxembourg matricule (national identification number) with correct check digits. The matricule encodes the full birth date (but no sex); constrain it with age/birth-date filters. Contradictory combinations are rejected with a 400. Set `invalid=true` for deliberately wrong check digits.
How it’s calculated
The Luxembourg matricule carries TWO trailing check digits over the same 11-digit payload: a Luhn (mod-10) digit at position 12, then a Verhoeff (dihedral D5) digit at position 13.
Algorithm
- Build the 11-digit payload: full 4-digit birth year YYYY, then 2-digit month MM, then 2-digit day DD, then a 3-digit serial (000-999), zero-padded. Result is exactly 11 digits, e.g. 19870324042.
- Convert the 11-character string to an array of digit values 0-9 (leading zeros are significant and preserved).
- Compute C1 = the Luhn (mod-10) check digit over those 11 payload digits: walk the digits from RIGHT to LEFT with a doubling flag that STARTS ON (the rightmost payload digit is doubled first). For each digit, if the flag is on multiply it by 2 and, if the product exceeds 9, subtract 9; otherwise take the digit as-is. Add each resulting value to a running sum, and flip the doubling flag after every digit.
- C1 = (10 - (sum mod 10)) mod 10.
- Compute C2 = the Verhoeff (dihedral group D5) check digit over the SAME 11 payload digits (NOT over the first 12 — the Luhn digit is excluded). Use the standard multiplication table D[10][10], permutation table P[8][10], and inverse table INV[10] shown below.
- Reverse the 11 payload digits. Set check = 0. For each pair (index, digit) of the reversed list, where index is 0-based, update check = D[check][ P[(index + 1) mod 8][digit] ].
- After consuming all 11 digits, C2 = INV[check].
- The final 13-digit matricule is the 11 payload digits, followed by C1 (position 12), followed by C2 (position 13).
- Tables — D (rows 0..9): [0,1,2,3,4,5,6,7,8,9],[1,2,3,4,0,6,7,8,9,5],[2,3,4,0,1,7,8,9,5,6],[3,4,0,1,2,8,9,5,6,7],[4,0,1,2,3,9,5,6,7,8],[5,9,8,7,6,0,4,3,2,1],[6,5,9,8,7,1,0,4,3,2],[7,6,5,9,8,2,1,0,4,3],[8,7,6,5,9,3,2,1,0,4],[9,8,7,6,5,4,3,2,1,0]. P (rows 0..7): [0,1,2,3,4,5,6,7,8,9],[1,5,7,6,2,8,3,0,9,4],[5,8,0,3,7,9,6,1,4,2],[8,9,1,6,0,4,3,5,2,7],[9,4,5,3,1,2,6,8,7,0],[4,2,8,6,5,7,3,9,0,1],[2,7,9,3,8,0,6,4,1,5],[7,0,4,6,9,1,3,2,5,8]. INV: [0,4,3,2,1,5,6,7,8,9].
Worked example
Matricule for birth date 1987-03-24, serial 042 → payload 19870324042, check digits ??
Payload digits: 1 9 8 7 0 3 2 4 0 4 2 (YYYY=1987, MM=03, DD=24, serial=042).
LUHN (C1), right-to-left, doubling flag starts ON: digit 2 (double→4), 4 (→4), 0 (double→0), 4 (→4), 2 (double→4), 3 (→3), 0 (double→0), 7 (→7), 8 (double→16→7), 9 (→9), 1 (double→2).
Sum = 4+4+0+4+4+3+0+7+7+9+2 = 44. C1 = (10 - (44 mod 10)) mod 10 = (10 - 4) mod 10 = 6.
VERHOEFF (C2) over same 11 digits. Reversed payload: 2 4 0 4 2 3 0 7 8 9 1. check starts 0, update check = D[check][P[(index+1)%8][digit]].
i=0 d=2: P[1][2]=7, D[0][7]=7. i=1 d=4: P[2][4]=7, D[7][7]=0. i=2 d=0: P[3][0]=8, D[0][8]=8. i=3 d=4: P[4][4]=1, D[8][1]=7. i=4 d=2: P[5][2]=8, D[7][8]=4.
i=5 d=3: P[6][3]=3, D[4][3]=2. i=6 d=0: P[7][0]=7, D[2][7]=9. i=7 d=7: P[0][7]=7, D[9][7]=2. i=8 d=8: P[1][8]=9, D[2][9]=6. i=9 d=9: P[2][9]=2, D[6][2]=9. i=10 d=1: P[3][1]=9, D[9][9]=0.
Final check state = 0, so C2 = INV[0] = 0.
Check digits are C1 C2 = 6 0.C1 = 6 (Luhn), C2 = 0 (Verhoeff); the full 13-digit matricule is 1987032404260.
Edge cases
- The payload always uses a FULL four-digit year (YYYY, e.g. 1987), and the generator clamps encodable birth dates to the 1900-2099 range (MATRICULE_MIN_DATE / MATRICULE_MAX_DATE in build-matricule.ts).
- The serial is a 3-digit field 000-999, zero-padded; the whole payload is always exactly 11 digits and the final matricule is always exactly 13 digits.
Gotchas
- Both check digits are computed over the SAME first 11 digits. The Verhoeff digit (C2, position 13) is NOT computed over the 12 digits including the Luhn digit — it ignores C1 entirely.
- The check-digit Verhoeff uses P[(index + 1) mod 8][digit] with a 0-based index over the reversed payload; the VALIDATION variant (isValidVerhoeff) instead uses P[index mod 8][digit] over all 13 digits and expects a final state of 0. Do not mix the two index offsets.
- Luhn here uses the check-generation convention where the doubling flag starts ON at the rightmost payload digit (because the payload excludes the check digit). The separate isValidLuhn helper starts the doubling flag OFF because it walks a full number whose last digit is already the check digit.
Parameters
| Parameter | Type | Description |
|---|---|---|
| atAge | integer | Exact age in years at request time. |
| bornAfter | stringpattern ^\d{4}(?:-\d{2}(?:-\d{2})?)?$ | Born after this date or fragment (YYYY, YYYY-MM, YYYY-MM-DD). |
| bornBefore | stringpattern ^\d{4}(?:-\d{2}(?:-\d{2})?)?$ | Born before this date or fragment (YYYY, YYYY-MM, YYYY-MM-DD). |
| bornOn | stringpattern ^\d{4}(?:-\d{2}(?:-\d{2})?)?$ | Born on a date or within a fragment: YYYY, YYYY-MM, or YYYY-MM-DD. |
| 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 edge-case values. |
| 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 matricule with deliberately wrong check digits; the birth date stays valid. |
| olderThan | integer | Minimum age in years at request time. |
| seed | integer | Integer seed for reproducible output: the same seed always yields the same record. |
| youngerThan | integer | Maximum age in years at request time. |
Response fields
| Field | Type | Description |
|---|---|---|
| value | string | The 13-digit matricule. |
| digits | string | The canonical 13-digit matricule. |
| birthDate | string | The encoded birth date, ISO `YYYY-MM-DD`. |
Other generators for Luxembourg
Luxembourg companyLuxembourg company nameLuxembourg email addressLuxembourg IBANLuxembourg personLuxembourg person nameLuxembourg product or service offeringLuxembourg TVALuxembourg vehicle registration plate
See all generators for Luxembourg →The same kind of identifier elsewhere
Austrian data · Austrian SVNRBelgian data · Belgian RijksregisternummerBulgarian data · Bulgarian EGNCroatian data · Croatian JMBGCroatian data · Croatian OIBCypriot data · Cyprus TICCzech data · Czech rodné čísloDanish data · Danish CPRDutch data · Dutch BSNEstonian data · Estonian isikukoodFinnish data · Finnish henkilötunnusFinnish data · Finnish Y-tunnusFrench data · French NIRGerman data · German Steuer-IdNrGreek data · Greek AFMGreek data · Greek AMKAHungarian data · Hungarian adóazonosító jelHungarian data · Hungarian személyi azonosítóHungarian data · Hungarian TAJIrish data · Irish PPSNItalian data · Italian Codice FiscaleLatvian data · Latvian personas kodsLithuanian data · Lithuanian asmens kodasPolish data · Polish PESELPortuguese data · Portuguese NIFRomanian data · Romanian CNPSlovak data · Slovak rodné čísloSlovenian data · Slovenian davčna številkaSlovenian data · Slovenian EMŠOSpanish data · Spanish DNISpanish data · Spanish NIESwedish data · Swedish personnummer
Try it