type enum MRZ document format. td1 = 3 lines of 30, td2 = 2 lines of 36, td3 = 2 lines of 44 (the passport layout), mrva = 2 lines of 44 and mrvb = 2 lines of 36 (machine readable visas).
ICAO 9303 MRZ test fixtures — TD1/TD2/TD3/MRV lines with correct 7-3-1 check digits and exact geometry, issued by the specimen state UTO, plus a validator.
Generated test data for fixtures and development
Each record is one complete machine readable zone plus the fields it encodes. Issuing State and nationality are always UTO and the document number is always SPECIMEN plus a digit.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
type | enum | default: td3 allowed: td1 | td2 | td3 | mrva | mrvb example: td1 | MRZ document format. td1 = 3 lines of 30, td2 = 2 lines of 36, td3 = 2 lines of 44 (the passport layout), mrva = 2 lines of 44 and mrvb = 2 lines of 36 (machine readable visas). |
sex | enum | allowed: M | F | X example: F | Sex written to the MRZ. M and F are written verbatim; X writes the filler '<', which is what Doc 9303 requires in the MRZ when the printed page shows X. Omit for a mix. |
expired | boolean | example: true | true forces an expiry date strictly before the asOf anchor, false forces one strictly after. Omit for a realistic mix of roughly one expired document in sixteen. |
longName | boolean | default: false example: true | true builds a name long enough to overflow the field, forcing the Doc 9303-4 Section 4.2.3 truncation path (the field is filled to the last position and ends with a letter). |
minAge | int | default: 18 allowed: 0 – 120 example: 25 | Youngest holder age in completed years at the asOf anchor. Must be ≤ maxAge. |
maxAge | int | default: 80 allowed: 0 – 120 example: 40 | Oldest holder age in completed years at the asOf anchor. Must be ≥ minAge. |
asOf | date | example: 2026-07-01 | Replayable evaluation anchor (UTC midnight) for ageYears and for expired. Defaults to today; must be between 1970-01-01 and 2099-12-31. The resolved anchor is echoed in meta.params. |
type enum MRZ document format. td1 = 3 lines of 30, td2 = 2 lines of 36, td3 = 2 lines of 44 (the passport layout), mrva = 2 lines of 44 and mrvb = 2 lines of 36 (machine readable visas).
sex enum Sex written to the MRZ. M and F are written verbatim; X writes the filler '<', which is what Doc 9303 requires in the MRZ when the printed page shows X. Omit for a mix.
expired boolean true forces an expiry date strictly before the asOf anchor, false forces one strictly after. Omit for a realistic mix of roughly one expired document in sixteen.
longName boolean true builds a name long enough to overflow the field, forcing the Doc 9303-4 Section 4.2.3 truncation path (the field is filled to the last position and ends with a letter).
minAge int Youngest holder age in completed years at the asOf anchor. Must be ≤ maxAge.
maxAge int Oldest holder age in completed years at the asOf anchor. Must be ≥ minAge.
asOf date Replayable evaluation anchor (UTC midnight) for ageYears and for expired. Defaults to today; must be between 1970-01-01 and 2099-12-31. The resolved anchor is echoed in meta.params.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
count | int | default: 10 allowed: 1 – 100 example: 3 | How many records to generate (1–100). |
seed | int | example: 42 | Deterministic output: the same seed always returns the same records. Omit for random (the used seed is echoed in meta.seed). |
locale | enum | default: en allowed: en | da | de | fr | es | it | pt | ja example: da | Locale for the generated data (names, addresses, …). |
fields | list | example: type,mrz | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: checkDigits | Return all fields except these (comma-separated). |
format | enum | default: json allowed: json | ndjson | csv example: csv | Response format: json envelope, ndjson (one record per line) or csv. |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
count int How many records to generate (1–100).
seed int Deterministic output: the same seed always returns the same records. Omit for random (the used seed is echoed in meta.seed).
locale enum Locale for the generated data (names, addresses, …).
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
format enum Response format: json envelope, ndjson (one record per line) or csv.
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
type | string | MRZ document format of this record: td1, td2, td3, mrva or mrvb. | td3 |
mrz | string | The complete machine readable zone, lines joined with a newline. | PPUTOKLOCKO<<ADALINE<<<<<<<<<<<<<<<<<<<<<<<< SPECIMEN91UTO9607011F2907022<<<<<<<<<<<<<<02 |
lines | string[] | The individual machine readable lines, each exactly lineLength characters. | ["PPUTOKLOCKO<<ADALINE<<<<<<<<<<<<<<<<<<<<<<<<","SPECIMEN91UTO9607011F2907022<<<<<<<<<<<<<<02"] |
lineLength | integer | Exact character count of every line in this format (30, 36 or 44). | 44 |
documentCode | string | Positions 1-2 of the first line: PP for the TD3 passport, I< for TD1/TD2, V< for a visa. | PP |
issuingState | string | Issuing State code — always UTO, the ICAO specimen code for Utopia. | UTO |
nationality | string | Nationality code — always UTO, the ICAO specimen code for Utopia. | UTO |
documentNumber | string | Nine-character synthetic document number: the literal word SPECIMEN plus one digit. | SPECIMEN9 |
primaryIdentifier | string | Full transliterated primary identifier (surname), before any truncation. | KLOCKO |
secondaryIdentifier | string | Full transliterated secondary identifier (given names), before any truncation. Empty for the roughly one record in eight that has no secondary identifier at all. | ADALINE |
nameField | string | The name field exactly as written in the MRZ, padded or truncated to its fixed width. | KLOCKO<<ADALINE<<<<<<<<<<<<<<<<<<<<<<<< |
nameTruncated | boolean | Whether the assembled name did not fit the field and was shortened. | false |
sex | string | MRZ sex character: M, F or < for unspecified (the printed page shows X). | F |
dateOfBirth | string (ISO 8601 date) | Date of birth in full; the MRZ itself carries only the six digits YYMMDD. | 1996-07-01 |
dateOfExpiry | string (ISO 8601 date) | Expiry date in full; the MRZ itself carries only the six digits YYMMDD. | 2029-07-02 |
ageYears | integer | Completed years between dateOfBirth and the resolved asOf anchor. | 30 |
expired | boolean | Whether dateOfExpiry is earlier than the resolved asOf anchor. | false |
optionalData | string[] | Optional-data / personal-number field(s) in MRZ order — always all filler here (TD1 has two, every other format one). | ["<<<<<<<<<<<<<<"] |
checkDigits | object | Every 7-3-1 check digit in the record: documentNumber, dateOfBirth, dateOfExpiry, optionalData (TD3 only) and composite (null for visas). | {"documentNumber":"1","dateOfBirth":"1","dateOfExpiry":"2","optionalData":"0","composite":"2"} |
type string MRZ document format of this record: td1, td2, td3, mrva or mrvb.
example: td3
mrz string The complete machine readable zone, lines joined with a newline.
example: PPUTOKLOCKO<<ADALINE<<<<<<<<<<<<<<<<<<<<<<<< SPECIMEN91UTO9607011F2907022<<<<<<<<<<<<<<02
lines string[] The individual machine readable lines, each exactly lineLength characters.
example: ["PPUTOKLOCKO<<ADALINE<<<<<<<<<<<<<<<<<<<<<<<<","SPECIMEN91UTO9607011F2907022<<<<<<<<<<<<<<02"]
lineLength integer Exact character count of every line in this format (30, 36 or 44).
example: 44
documentCode string Positions 1-2 of the first line: PP for the TD3 passport, I< for TD1/TD2, V< for a visa.
example: PP
issuingState string Issuing State code — always UTO, the ICAO specimen code for Utopia.
example: UTO
nationality string Nationality code — always UTO, the ICAO specimen code for Utopia.
example: UTO
documentNumber string Nine-character synthetic document number: the literal word SPECIMEN plus one digit.
example: SPECIMEN9
primaryIdentifier string Full transliterated primary identifier (surname), before any truncation.
example: KLOCKO
secondaryIdentifier string Full transliterated secondary identifier (given names), before any truncation. Empty for the roughly one record in eight that has no secondary identifier at all.
example: ADALINE
nameField string The name field exactly as written in the MRZ, padded or truncated to its fixed width.
example: KLOCKO<<ADALINE<<<<<<<<<<<<<<<<<<<<<<<<
nameTruncated boolean Whether the assembled name did not fit the field and was shortened.
example: false
sex string MRZ sex character: M, F or < for unspecified (the printed page shows X).
example: F
dateOfBirth string (ISO 8601 date) Date of birth in full; the MRZ itself carries only the six digits YYMMDD.
example: 1996-07-01
dateOfExpiry string (ISO 8601 date) Expiry date in full; the MRZ itself carries only the six digits YYMMDD.
example: 2029-07-02
ageYears integer Completed years between dateOfBirth and the resolved asOf anchor.
example: 30
expired boolean Whether dateOfExpiry is earlier than the resolved asOf anchor.
example: false
optionalData string[] Optional-data / personal-number field(s) in MRZ order — always all filler here (TD1 has two, every other format one).
example: ["<<<<<<<<<<<<<<"]
checkDigits object Every 7-3-1 check digit in the record: documentNumber, dateOfBirth, dateOfExpiry, optionalData (TD3 only) and composite (null for visas).
example: {"documentNumber":"1","dateOfBirth":"1","dateOfExpiry":"2","optionalData":"0","composite":"2"}
/api/mrz {
"data": [
{
"type": "td3",
"mrz": "PPUTOMACGYVER<<DORIAN<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN02UTO7804034M2910079<<<<<<<<<<<<<<08",
"lines": [
"PPUTOMACGYVER<<DORIAN<<<<<<<<<<<<<<<<<<<<<<<",
"SPECIMEN02UTO7804034M2910079<<<<<<<<<<<<<<08"
],
"lineLength": 44,
"documentCode": "PP",
"issuingState": "UTO",
"nationality": "UTO",
"documentNumber": "SPECIMEN0",
"primaryIdentifier": "MACGYVER",
"secondaryIdentifier": "DORIAN",
"nameField": "MACGYVER<<DORIAN<<<<<<<<<<<<<<<<<<<<<<<",
"nameTruncated": false,
"sex": "M",
"dateOfBirth": "1978-04-03",
"dateOfExpiry": "2029-10-07",
"ageYears": 48,
"expired": false,
"optionalData": [
"<<<<<<<<<<<<<<"
],
"checkDigits": {
"documentNumber": "2",
"dateOfBirth": "4",
"dateOfExpiry": "9",
"optionalData": "0",
"composite": "8"
}
},
{
"type": "td3",
"mrz": "PPUTOWISOZK<<LINDSEY<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN13UTO0508012M3111068<<<<<<<<<<<<<<06",
"lines": [
"PPUTOWISOZK<<LINDSEY<<<<<<<<<<<<<<<<<<<<<<<<",
"SPECIMEN13UTO0508012M3111068<<<<<<<<<<<<<<06"
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz?type=td1&count=5&seed=42 {
"data": [
{
"type": "td1",
"mrz": "I<UTOSPECIMEN02<<<<<<<<<<<<<<<\n7804034M2910079UTO<<<<<<<<<<<8\nMACGYVER<<DORIAN<<<<<<<<<<<<<<",
"lines": [
"I<UTOSPECIMEN02<<<<<<<<<<<<<<<",
"7804034M2910079UTO<<<<<<<<<<<8",
"MACGYVER<<DORIAN<<<<<<<<<<<<<<"
],
"lineLength": 30,
"documentCode": "I<",
"issuingState": "UTO",
"nationality": "UTO",
"documentNumber": "SPECIMEN0",
"primaryIdentifier": "MACGYVER",
"secondaryIdentifier": "DORIAN",
"nameField": "MACGYVER<<DORIAN<<<<<<<<<<<<<<",
"nameTruncated": false,
"sex": "M",
"dateOfBirth": "1978-04-03",
"dateOfExpiry": "2029-10-07",
"ageYears": 48,
"expired": false,
"optionalData": [
"<<<<<<<<<<<<<<<",
"<<<<<<<<<<<"
],
"checkDigits": {
"documentNumber": "2",
"dateOfBirth": "4",
"dateOfExpiry": "9",
"optionalData": null,
"composite": "8"
}
},
{
"type": "td1",
"mrz": "I<UTOSPECIMEN13<<<<<<<<<<<<<<<\n0508012M3111068UTO<<<<<<<<<<<6\nWISOZK<<LINDSEY<<<<<<<<<<<<<<<",
"lines": [
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz?type=mrva&expired=true&minAge=25&maxAge=60&count=5 {
"data": [
{
"type": "mrva",
"mrz": "V<UTOMACGYVER<<DORIAN<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN57UTO8404028M2207227<<<<<<<<<<<<<<<<",
"lines": [
"V<UTOMACGYVER<<DORIAN<<<<<<<<<<<<<<<<<<<<<<<",
"SPECIMEN57UTO8404028M2207227<<<<<<<<<<<<<<<<"
],
"lineLength": 44,
"documentCode": "V<",
"issuingState": "UTO",
"nationality": "UTO",
"documentNumber": "SPECIMEN5",
"primaryIdentifier": "MACGYVER",
"secondaryIdentifier": "DORIAN",
"nameField": "MACGYVER<<DORIAN<<<<<<<<<<<<<<<<<<<<<<<",
"nameTruncated": false,
"sex": "M",
"dateOfBirth": "1984-04-02",
"dateOfExpiry": "2022-07-22",
"ageYears": 42,
"expired": true,
"optionalData": [
"<<<<<<<<<<<<<<<<"
],
"checkDigits": {
"documentNumber": "7",
"dateOfBirth": "8",
"dateOfExpiry": "7",
"optionalData": null,
"composite": null
}
},
{
"type": "mrva",
"mrz": "V<UTOWISOZK<<LINDSEY<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN91UTO9908017M2101163<<<<<<<<<<<<<<<<",
"lines": [
"V<UTOWISOZK<<LINDSEY<<<<<<<<<<<<<<<<<<<<<<<<",
"SPECIMEN91UTO9908017M2101163<<<<<<<<<<<<<<<<"
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz?type=td2&longName=true&count=5&seed=7 {
"data": [
{
"type": "td2",
"mrz": "I<UTOBROWN<FAHEY<PRICE<<SKYLA<KRISTO\nSPECIMEN46UTO6606068F2805081<<<<<<<4",
"lines": [
"I<UTOBROWN<FAHEY<PRICE<<SKYLA<KRISTO",
"SPECIMEN46UTO6606068F2805081<<<<<<<4"
],
"lineLength": 36,
"documentCode": "I<",
"issuingState": "UTO",
"nationality": "UTO",
"documentNumber": "SPECIMEN4",
"primaryIdentifier": "BROWN FAHEY PRICE",
"secondaryIdentifier": "SKYLA KRISTOFER",
"nameField": "BROWN<FAHEY<PRICE<<SKYLA<KRISTO",
"nameTruncated": true,
"sex": "F",
"dateOfBirth": "1966-06-06",
"dateOfExpiry": "2028-05-08",
"ageYears": 60,
"expired": false,
"optionalData": [
"<<<<<<<"
],
"checkDigits": {
"documentNumber": "6",
"dateOfBirth": "8",
"dateOfExpiry": "1",
"optionalData": null,
"composite": "4"
}
},
{
"type": "td2",
"mrz": "I<UTOKUNZE<SCHUMM<SCHOEN<FARRELL<SCH\nSPECIMEN91UTO7203040F3406072<<<<<<<8",
"lines": [
"I<UTOKUNZE<SCHUMM<SCHOEN<FARRELL<SCH",
"SPECIMEN91UTO7203040F3406072<<<<<<<8"
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz?locale=de&count=5&seed=2 {
"data": [
{
"type": "td3",
"mrz": "PPUTOSCHNUERER<<ANNEMARIE<<<<<<<<<<<<<<<<<<<\nSPECIMEN02UTO6005225F3210189<<<<<<<<<<<<<<00",
"lines": [
"PPUTOSCHNUERER<<ANNEMARIE<<<<<<<<<<<<<<<<<<<",
"SPECIMEN02UTO6005225F3210189<<<<<<<<<<<<<<00"
],
"lineLength": 44,
"documentCode": "PP",
"issuingState": "UTO",
"nationality": "UTO",
"documentNumber": "SPECIMEN0",
"primaryIdentifier": "SCHNUERER",
"secondaryIdentifier": "ANNEMARIE",
"nameField": "SCHNUERER<<ANNEMARIE<<<<<<<<<<<<<<<<<<<",
"nameTruncated": false,
"sex": "F",
"dateOfBirth": "1960-05-22",
"dateOfExpiry": "2032-10-18",
"ageYears": 66,
"expired": false,
"optionalData": [
"<<<<<<<<<<<<<<"
],
"checkDigits": {
"documentNumber": "2",
"dateOfBirth": "5",
"dateOfExpiry": "9",
"optionalData": "0",
"composite": "0"
}
},
{
"type": "td3",
"mrz": "PPUTOGOTTHARDT<<JESPER<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN35UTO9504305M3305223<<<<<<<<<<<<<<04",
"lines": [
"PPUTOGOTTHARDT<<JESPER<<<<<<<<<<<<<<<<<<<<<<",
"SPECIMEN35UTO9504305M3305223<<<<<<<<<<<<<<04"
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz?fields=mrz&format=ndjson&count=20 {"mrz":"PPUTOMACGYVER<<DORIAN<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN02UTO7804034M2910079<<<<<<<<<<<<<<08"}
{"mrz":"PPUTOWISOZK<<LINDSEY<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN13UTO0508012M3111068<<<<<<<<<<<<<<06"}
{"mrz":"PPUTOJAKUBOWSKI<<SAIGE<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN02UTO5409114F3103304<<<<<<<<<<<<<<00"}
{"mrz":"PPUTORENNER<<HEIDI<<<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN80UTO9902288F1805040<<<<<<<<<<<<<<08"}
{"mrz":"PPUTORAU<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN68UTO5604160F2902049<<<<<<<<<<<<<<08"}
{"mrz":"PPUTOLYNCH<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN46UTO0612276F2905143<<<<<<<<<<<<<<08"}
{"mrz":"PPUTOMILLER<<SANFORD<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN35UTO0212182F3402063<<<<<<<<<<<<<<02"}
{"mrz":"PPUTOLANGWORTH<<AMPARO<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN46UTO5602100F3508172<<<<<<<<<<<<<<02"}
{"mrz":"PPUTOGOODWIN<<DENA<<<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN46UTO7908046M2708159<<<<<<<<<<<<<<08"}
{"mrz":"PPUTOSTIEDEMANN<<SAMANTHA<<<<<<<<<<<<<<<<<<<\nSPECIMEN46UTO4807159M3111219<<<<<<<<<<<<<<02"}
{"mrz":"PPUTOABERNATHY<<MYRL<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN79UTO4508065F3410185<<<<<<<<<<<<<<00"}
{"mrz":"PPUTOJACOBSON<<ROBERT<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN80UTO9706073F3210167<<<<<<<<<<<<<<02"}
{"mrz":"PPUTOFAY<<BILLIE<<<<<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN35UTO0405100F3410174<<<<<<<<<<<<<<06"}
{"mrz":"PPUTOBASHIRIAN<<STEPHEN<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN02UTO7401226M3301029<<<<<<<<<<<<<<08"}
{"mrz":"PPUTOLOCKMAN<<MARCELLE<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN68UTO6107118M3208069<<<<<<<<<<<<<<08"}
{"mrz":"PPUTOSWANIAWSKI<<KAYLI<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN79UTO5611274F2705206<<<<<<<<<<<<<<02"}
{"mrz":"PPUTOPROHASKA<<ANISSA<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN35UTO9301135M3309069<<<<<<<<<<<<<<00"}
{"mrz":"PPUTOMACEJKOVIC<<DINA<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN80UTO7005071M3507175<<<<<<<<<<<<<<06"}
{"mrz":"PPUTOSENGER<<SEAN<<<<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN35UTO7808308F3106143<<<<<<<<<<<<<<08"}
{"mrz":"PPUTOULLRICH<<CONNER<<<<<<<<<<<<<<<<<<<<<<<<\nSPECIMEN35UTO7802100M3501047<<<<<<<<<<<<<<04"}
Structural check only: geometry, MRZ alphabet, sex, date fields and every check digit. It never throws on malformed input and never claims a document is authentic.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
mrz
required
| string | allowed: 1 – 200 example: PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<|L898902C36UTO7408122F1204159ZE184226B<<<<<10 | The MRZ lines, separated by newlines (%0A) or by '|'. One unbroken 90, 88 or 72-character blob is split by the only geometry it can be. ASCII lower-case letters are upper-cased; anything else stays visible and invalid. |
type | enum | allowed: td1 | td2 | td3 | mrva | mrvb example: td3 | MRZ document format. td1 = 3 lines of 30, td2 = 2 lines of 36, td3 = 2 lines of 44 (the passport layout), mrva = 2 lines of 44 and mrvb = 2 lines of 36 (machine readable visas). Omit to detect the format from the line count, the line length and the leading V of a visa. |
mrz string required The MRZ lines, separated by newlines (%0A) or by '|'. One unbroken 90, 88 or 72-character blob is split by the only geometry it can be. ASCII lower-case letters are upper-cased; anything else stays visible and invalid.
type enum MRZ document format. td1 = 3 lines of 30, td2 = 2 lines of 36, td3 = 2 lines of 44 (the passport layout), mrva = 2 lines of 44 and mrvb = 2 lines of 36 (machine readable visas). Omit to detect the format from the line count, the line length and the leading V of a visa.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
locale | enum | default: en allowed: en | da | de | fr | es | it | pt | ja example: da | Locale for the generated data (names, addresses, …). |
fields | list | example: input,normalized | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: reasons | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
locale enum Locale for the generated data (names, addresses, …).
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
input | string | The MRZ exactly as supplied. | ppUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<|L898902C36UTO7408122F1204159ZE184226B<<<<<10 |
normalized | string | Upper-cased input with the supplied separators replaced by newlines and each line trimmed. | PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<< L898902C36UTO7408122F1204159ZE184226B<<<<<10 |
type nullable | string | Resolved MRZ format — the requested type, or the one detected from line count, line length and the leading V of a visa. Null when no format matches. | td3 |
lines | string[] | The normalized machine readable lines. | ["PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<","L898902C36UTO7408122F1204159ZE184226B<<<<<10"] |
lineLengths | integer[] | Character count of each supplied line. | [44,44] |
expectedLineCount nullable | integer | Line count the resolved format requires; null when no format matched. | 2 |
expectedLineLength nullable | integer | Line length the resolved format requires; null when no format matched. | 44 |
geometryValid | boolean | Whether line count and every line length match the resolved format exactly. | true |
characterSetValid | boolean | Whether every character is inside the MRZ alphabet A-Z, 0-9 and <. Vacuously true for empty input, which is reported as EMPTY_INPUT instead. | true |
parsed nullable | object | Decoded MRZ fields (document code, state, number, nationality, raw YYMMDD dates, sex, optional data and the identifiers). Null when the geometry does not match. | {"documentCode":"PP","issuingState":"UTO","documentNumber":"L898902C3","documentNumberCheckDigit":"6","nationality":"UTO","dateOfBirth":"740812","dateOfBirthCheckDigit":"2","sex":"F","dateOfExpiry":"120415","dateOfExpiryCheckDigit":"9","optionalData":["ZE184226B<<<<<"],"optionalDataCheckDigit":"1","compositeCheckDigit":"0","nameField":"ERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<","primaryIdentifier":"ERIKSSON","secondaryIdentifier":"ANNA MARIA"} |
checkDigits | object[] | One ordered entry per 7-3-1 check digit: field, the positions it covers, the recomputed expected digit, the digit found and whether they agree. Empty when the geometry does not match. | [{"field":"documentNumber","covers":"line 2, positions 1-9","expected":"6","found":"6","valid":true}] |
valid | boolean | True only when geometry, alphabet, sex, date fields and every check digit are correct. It is not an authenticity or identity check. | true |
reasons | string[] | Stable ordered reason codes; empty exactly when valid is true. | [] |
input string The MRZ exactly as supplied.
example: ppUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<|L898902C36UTO7408122F1204159ZE184226B<<<<<10
normalized string Upper-cased input with the supplied separators replaced by newlines and each line trimmed.
example: PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<< L898902C36UTO7408122F1204159ZE184226B<<<<<10
type string nullable Resolved MRZ format — the requested type, or the one detected from line count, line length and the leading V of a visa. Null when no format matches.
example: td3
lines string[] The normalized machine readable lines.
example: ["PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<","L898902C36UTO7408122F1204159ZE184226B<<<<<10"]
lineLengths integer[] Character count of each supplied line.
example: [44,44]
expectedLineCount integer nullable Line count the resolved format requires; null when no format matched.
example: 2
expectedLineLength integer nullable Line length the resolved format requires; null when no format matched.
example: 44
geometryValid boolean Whether line count and every line length match the resolved format exactly.
example: true
characterSetValid boolean Whether every character is inside the MRZ alphabet A-Z, 0-9 and <. Vacuously true for empty input, which is reported as EMPTY_INPUT instead.
example: true
parsed object nullable Decoded MRZ fields (document code, state, number, nationality, raw YYMMDD dates, sex, optional data and the identifiers). Null when the geometry does not match.
example: {"documentCode":"PP","issuingState":"UTO","documentNumber":"L898902C3","documentNumberCheckDigit":"6","nationality":"UTO","dateOfBirth":"740812","dateOfBirthCheckDigit":"2","sex":"F","dateOfExpiry":"120415","dateOfExpiryCheckDigit":"9","optionalData":["ZE184226B<<<<<"],"optionalDataCheckDigit":"1","compositeCheckDigit":"0","nameField":"ERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<","primaryIdentifier":"ERIKSSON","secondaryIdentifier":"ANNA MARIA"}
checkDigits object[] One ordered entry per 7-3-1 check digit: field, the positions it covers, the recomputed expected digit, the digit found and whether they agree. Empty when the geometry does not match.
example: [{"field":"documentNumber","covers":"line 2, positions 1-9","expected":"6","found":"6","valid":true}]
valid boolean True only when geometry, alphabet, sex, date fields and every check digit are correct. It is not an authenticity or identity check.
example: true
reasons string[] Stable ordered reason codes; empty exactly when valid is true.
example: []
/api/mrz/validate?mrz=PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<%0AL898902C36UTO7408122F1204159ZE184226B<<<<<10 {
"data": {
"input": "PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<\nL898902C36UTO7408122F1204159ZE184226B<<<<<10",
"normalized": "PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<\nL898902C36UTO7408122F1204159ZE184226B<<<<<10",
"type": "td3",
"lines": [
"PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<",
"L898902C36UTO7408122F1204159ZE184226B<<<<<10"
],
"lineLengths": [
44,
44
],
"expectedLineCount": 2,
"expectedLineLength": 44,
"geometryValid": true,
"characterSetValid": true,
"parsed": {
"documentCode": "PP",
"issuingState": "UTO",
"documentNumber": "L898902C3",
"documentNumberCheckDigit": "6",
"nationality": "UTO",
"dateOfBirth": "740812",
"dateOfBirthCheckDigit": "2",
"sex": "F",
"dateOfExpiry": "120415",
"dateOfExpiryCheckDigit": "9",
"optionalData": [
"ZE184226B<<<<<"
],
"optionalDataCheckDigit": "1",
"compositeCheckDigit": "0",
"nameField": "ERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<",
"primaryIdentifier": "ERIKSSON",
"secondaryIdentifier": "ANNA MARIA"
},
"checkDigits": [
{
"field": "documentNumber",
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz/validate?mrz=PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<%0AL898902C35UTO7408122F1204159ZE184226B<<<<<10 {
"data": {
"input": "PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<\nL898902C35UTO7408122F1204159ZE184226B<<<<<10",
"normalized": "PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<\nL898902C35UTO7408122F1204159ZE184226B<<<<<10",
"type": "td3",
"lines": [
"PPUTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<",
"L898902C35UTO7408122F1204159ZE184226B<<<<<10"
],
"lineLengths": [
44,
44
],
"expectedLineCount": 2,
"expectedLineLength": 44,
"geometryValid": true,
"characterSetValid": true,
"parsed": {
"documentCode": "PP",
"issuingState": "UTO",
"documentNumber": "L898902C3",
"documentNumberCheckDigit": "5",
"nationality": "UTO",
"dateOfBirth": "740812",
"dateOfBirthCheckDigit": "2",
"sex": "F",
"dateOfExpiry": "120415",
"dateOfExpiryCheckDigit": "9",
"optionalData": [
"ZE184226B<<<<<"
],
"optionalDataCheckDigit": "1",
"compositeCheckDigit": "0",
"nameField": "ERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<",
"primaryIdentifier": "ERIKSSON",
"secondaryIdentifier": "ANNA MARIA"
},
"checkDigits": [
{
"field": "documentNumber",
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz/validate?mrz=I<UTOD231458907<<<<<<<<<<<<<<<%0A7408122F1204159UTO<<<<<<<<<<<6%0AERIKSSON<<ANNA<MARIA<<<<<<<<<< {
"data": {
"input": "I<UTOD231458907<<<<<<<<<<<<<<<\n7408122F1204159UTO<<<<<<<<<<<6\nERIKSSON<<ANNA<MARIA<<<<<<<<<<",
"normalized": "I<UTOD231458907<<<<<<<<<<<<<<<\n7408122F1204159UTO<<<<<<<<<<<6\nERIKSSON<<ANNA<MARIA<<<<<<<<<<",
"type": "td1",
"lines": [
"I<UTOD231458907<<<<<<<<<<<<<<<",
"7408122F1204159UTO<<<<<<<<<<<6",
"ERIKSSON<<ANNA<MARIA<<<<<<<<<<"
],
"lineLengths": [
30,
30,
30
],
"expectedLineCount": 3,
"expectedLineLength": 30,
"geometryValid": true,
"characterSetValid": true,
"parsed": {
"documentCode": "I<",
"issuingState": "UTO",
"documentNumber": "D23145890",
"documentNumberCheckDigit": "7",
"nationality": "UTO",
"dateOfBirth": "740812",
"dateOfBirthCheckDigit": "2",
"sex": "F",
"dateOfExpiry": "120415",
"dateOfExpiryCheckDigit": "9",
"optionalData": [
"<<<<<<<<<<<<<<<",
"<<<<<<<<<<<"
],
"optionalDataCheckDigit": null,
"compositeCheckDigit": "6",
"nameField": "ERIKSSON<<ANNA<MARIA<<<<<<<<<<",
"primaryIdentifier": "ERIKSSON",
"secondaryIdentifier": "ANNA MARIA"
},
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz/validate?mrz=V<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<%0AL8988901C4XXX7408122F96121096ZE184226B<<<<<< {
"data": {
"input": "V<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<\nL8988901C4XXX7408122F96121096ZE184226B<<<<<<",
"normalized": "V<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<\nL8988901C4XXX7408122F96121096ZE184226B<<<<<<",
"type": "mrva",
"lines": [
"V<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<",
"L8988901C4XXX7408122F96121096ZE184226B<<<<<<"
],
"lineLengths": [
44,
44
],
"expectedLineCount": 2,
"expectedLineLength": 44,
"geometryValid": true,
"characterSetValid": true,
"parsed": {
"documentCode": "V<",
"issuingState": "UTO",
"documentNumber": "L8988901C",
"documentNumberCheckDigit": "4",
"nationality": "XXX",
"dateOfBirth": "740812",
"dateOfBirthCheckDigit": "2",
"sex": "F",
"dateOfExpiry": "961210",
"dateOfExpiryCheckDigit": "9",
"optionalData": [
"6ZE184226B<<<<<<"
],
"optionalDataCheckDigit": null,
"compositeCheckDigit": null,
"nameField": "ERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<",
"primaryIdentifier": "ERIKSSON",
"secondaryIdentifier": "ANNA MARIA"
},
"checkDigits": [
{
"field": "documentNumber",
…
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} /api/mrz/validate?mrz=PPUTOERIKSSON<<ANNA<MARIA%0AL898902C36UTO7408122F1204159&type=td3 {
"data": {
"input": "PPUTOERIKSSON<<ANNA<MARIA\nL898902C36UTO7408122F1204159",
"normalized": "PPUTOERIKSSON<<ANNA<MARIA\nL898902C36UTO7408122F1204159",
"type": "td3",
"lines": [
"PPUTOERIKSSON<<ANNA<MARIA",
"L898902C36UTO7408122F1204159"
],
"lineLengths": [
25,
28
],
"expectedLineCount": 2,
"expectedLineLength": 44,
"geometryValid": false,
"characterSetValid": true,
"parsed": null,
"checkDigits": [],
"valid": false,
"reasons": [
"WRONG_LINE_LENGTH"
]
},
"meta": {
"endpoint": "mrz",
"route": "/validate",
"locale": "en",
"params": {
"mrz": "PPUTOERIKSSON<<ANNA<MARIA\nL898902C36UTO7408122F1204159",
"type": "td3"
},
"generatedAt": "2026-07-29T08:13:22.000Z"
}
} Machine readable zone test fixtures for passport scanners, MRZ OCR pipelines and KYC ingest parsers — so you can exercise a reader without photographing a real passport. Every line is built from the ICAO Doc 9303 layout tables and the 7-3-1 weighted modulus-10 check digit of Doc 9303-3 Section 4.9.
What this is not. This endpoint implements MRZ layout and check-digit arithmetic only. There is no contactless chip, no BAC, PACE or EAC key derivation, no LDS data groups, no country signing certificate, no digital signature, no authenticity check and no identity claim of any kind. Nothing here asserts that a person, a document or a number exists. A correct check digit only means the surrounding characters are internally consistent.
Every document is a specimen, by construction. The issuing State and the nationality are hard-locked to UTO — "Utopia", the code Doc 9303-3 Section 5 Part G recommends for specimen documents — and the document number is always the literal word SPECIMEN followed by one digit. Utopia is not a real State and issues nothing, so no record here is, or can become, a document of any issuing authority. Names come from generic mock name pools, never from real people.
Geometry is exact. TD1 is 3 lines of 30 characters, TD2 is 2 lines of 36, TD3 (the passport data page) is 2 lines of 44, MRV-A is 2 lines of 44 and MRV-B is 2 lines of 36. Unused positions carry the filler <. Check digits cover the document number, the date of birth, the date of expiry, the TD3 personal-number field, and the composite digit whose covered substrings differ per format — TD1 covers line 1 positions 6-30 plus line 2 positions 1-7, 9-15 and 19-29; TD2 covers line 2 positions 1-10, 14-20 and 22-35; TD3 covers line 2 positions 1-10, 14-20 and 22-43. Machine readable visas have no composite check digit at all, so checkDigits.composite is null for mrva and mrvb.
Names follow Doc 9303-3 Section 4.6. Components are separated by one filler, the primary and secondary identifiers by two. Apostrophes are removed and the parts joined (O'CONNOR → OCONNOR); hyphens become a single filler (SMITH-JONES → SMITH<JONES); digits and all other punctuation are dropped. National characters are transliterated with Doc 9303-3 Section 6.A, the Latin table, always taking the first listed expansion — Ä→AE, Å→AA, Ö→OE, Ø→OE, Ü→UE, Ñ→N, Þ→TH, ẞ→SS — so one input name always produces exactly one MRZ. The Cyrillic and Arabic tables are not implemented, so a name whose identifiers leave no A–Z characters after transliteration is redrawn from the English name pool and reported in meta.warnings — which is exactly what locale=ja does, since Japanese script has no Doc 9303 Latin transliteration.
Roughly one generated record in eight has no secondary identifier at all — the ARKFREITH<<<<<<… shape of Doc 9303-4 Section 4.2.3.1 (f) and Doc 9303-5 Section 4.2.3.5, whose name field contains no << break at all. That is a distinct parse, so the fixtures include it rather than leaving your reader to meet it in production; secondaryIdentifier is an empty string for those records.
Parameters that genuinely constrain the output. type picks the format and therefore the line count and length. sex writes M, F or — for sex=X — the filler < that Doc 9303 requires in the MRZ when the printed page shows X. minAge/maxAge bound ageYears at the asOf anchor, and expired forces the expiry strictly before or strictly after it; omit expired for a realistic mix. longName=true forces the truncation path: the name field is filled to the last position and, as Doc 9303-4 Section 4.2.3 requires, ends with a letter. longName=false is the natural case, but a naturally long name can still overflow a name field — most often the 30 and 31-character TD1, TD2 and MRV-B ones, occasionally even the 39-character TD3 and MRV-A fields — so nameTruncated always reports the truth rather than promising something the data cannot keep.
One truncation strategy, chosen and stated. Doc 9303 lets each issuing State decide how to shorten an over-long name, and its own examples show three different choices. This endpoint always makes the minimal cut: characters are removed from the end of the assembled field, and the primary identifier is shortened only when it leaves no room for << plus the first character of the secondary identifier. Component separators always survive the cut — Doc 9303-3 Section 4.6 requires a single filler between components, and no published example ever merges two of them — so when a cut lands on a separator, the component in front of it gives up its last character and the freed final position carries the following component's initial (…<ANTONI<L, the shape of …<DEJTHAMRONG<K in Doc 9303-4 Section 4.2.3.2 (a)). The field therefore still ends with A–Z, and every component in it is a genuine prefix of the corresponding component of the full name. That rule reproduces the published Doc 9303-4 Section 4.2.3.2 (a) and (b) truncated examples, and the truncated TD1 example in Doc 9303-5 Section 4.2.3.4, character for character; the Doc 9303-4 Section 4.2.3.3 examples use a different, equally valid issuer strategy and are deliberately not imitated.
/validate recomputes every check digit of an MRZ you supply and returns an ordered list of reason codes instead of throwing. It accepts newline-separated or |-separated lines, or one unbroken 72/88/90-character blob, and detects the format from the geometry plus the leading V of a visa. It deliberately does not guess a century for the two-digit years, and it does not convert spaces to < — a space is reported as an invalid character rather than silently repaired. Date fields are checked component by component: each of YY, MM and DD must be two digits or two fillers, every component that is written must be a real calendar component (74<<99 is reported, not waved through as "has a filler"), and the filler form is accepted only for the date of birth — Doc 9303-3 Section 4.8 grants it to the date of birth alone, and the date-of-expiry element carries no filler allowance in the Part 5, 6 and 7 data element directories, so <<<<<< there is INVALID_DATE_OF_EXPIRY. Characters outside the MRZ alphabet are counted as zero while a check digit is recomputed, and flagged separately as INVALID_CHARACTERS, so a garbled scan still produces a full report instead of an exception. On TD3 it honours Doc 9303-4's rule that an unused personal-number field may carry either 0 or < as its check digit.
Deliberate exclusions, so nothing here is a surprise. Optional-data and personal-number fields are always all filler in generated documents. The TD1 long document number variant of Doc 9303-5 Section 4.2.4 — where position 15 holds < and the number continues into the optional-data field — is neither generated nor recognised, so /validate reads position 15 as the document-number check digit and reports INVALID_CHECK_DIGIT_DOCUMENT_NUMBER for such a card. /validate checks structure only: it does not verify that an issuing State or nationality code is a real ICAO code, that a document code is a harmonised one, or that a date is plausible beyond being a real calendar date. The Cyrillic and Arabic transliteration tables and reverse transliteration are out of scope, and the endpoint makes no network calls of any kind.
ICAO Doc 9303-3 Section 4.9 uses modulus 10 with the repeating weighting 7, 3, 1: digits count as themselves, A to Z count as 10 to 35, the filler < counts as zero, and the remainder is the check digit. /api/mrz/validate recomputes every one of them and shows the expected digit next to the digit found.
No. Every document is issued by UTO — the fictional state Doc 9303 uses in its own examples — and every document number is the literal word SPECIMEN plus one digit. These are scanner and parser test fixtures; there is no chip, no signature and no identity behind them.
TD1 (3 lines of 30), TD2 (2 lines of 36), TD3 (2 lines of 44), MRV-A (2 lines of 44) and MRV-B (2 lines of 36). Machine readable visas carry no composite check digit, so checkDigits.composite is null for mrva and mrvb.
Usually because the name was truncated — but not necessarily. Doc 9303-4 Section 4.2.3 requires a shortened name field to be completely filled and to end with A-Z, and a name that happens to fill the field exactly ends with a letter too (PAPANDROPOULOUS<<JONATHON<ALEC), which is why Doc 9303 says such a name must be treated as though it had been truncated. Generated records carry a nameTruncated flag that tells you which case you actually have.
No — the MRZ carries only YYMMDD, and Doc 9303 defines no century rule. Generated records include the full dateOfBirth, but /validate deliberately returns the raw six digits rather than guessing a century.
Not in the MRZ. Doc 9303 allows M, F or the filler <; X is what the printed page shows when the sex is unspecified. sex=X therefore writes <, and /validate reports INVALID_SEX for any other character.
Generate synthetic IBAN-shaped values for 20 countries with matching length, broad BBAN character classes and international MOD-97, or inspect the same checks.
Clearly-fake test credit cards — Luhn-valid numbers with correct Visa, Mastercard, Amex and Discover prefixes, future expiry and matching CVV.
Complete fake people — name, age-consistent birth date, email, phone, job and address — with working filters for gender, age range and email domain.
Random person names — first, last and full — with a strict gender filter, locale-aware name pools in 8 languages and seed-reproducible output.
All 249 ISO 3166-1 countries and territories with codes, regions, capitals, currencies, languages, calling codes, flags and label-safe land points.
Locale-aware fake postal addresses — street, city, state, zip, country and coordinates that all agree, plus a one-line formatted form in the local layout.