Document Number Validator
Check whether a document number is well-formed for its jurisdiction, before you create a session or submit a verification. Nothing is stored and no verification is consumed.
Endpoint: POST /v1/validators/document-number
Authentication: Bearer token with the sessions scope
A stateless format check against the same registry the verification pipeline uses. Nothing is stored and no verification is consumed β but it accepts government identifiers, so it is attributed to a tenant like every other endpoint here. Useful for validating input in your own form before creating a session.
curl --request POST \
--url https://{FQDN}/v1/validators/document-number \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"documentType": "drivers_license",
"number": "31612967",
"issuingCountry": "USA",
"issuingState": "PA"
}'
{
"documentType": "drivers_license",
"issuingCountry": "USA",
"issuingState": "PA",
"valid": true,
"rule": "dl:USA:PA",
"detail": "document number matches the PA license format"
}
The number you send is never echoed back. The response reports the jurisdiction that was applied, not the identifier you submitted.
What Is Covered
| Country | drivers_license | passport | identity_card | ssn / itin |
|---|---|---|---|---|
| πΊπΈ United States | β 51 jurisdictions (50 states + DC) | β | β | β structural rules |
| π¨π¦ Canada | β 13 jurisdictions (10 provinces + 3 territories) | β | β | β |
| π§π· Brazil | β CNH β check digits verified | β | β CPF β check digits verified | β |
| π²π½ Mexico | β | β | β CURP β structure | β |
| πͺπΈ Spain | β | β | β DNI/NIE β control letter verified | β |
| π 11 more countries | β | β | β | β |
| π Everywhere else | β | β generic ICAO shape | β | β |
The 11 additional passport countries, as the issuingCountry you send: ARG, AUS, CHN, DEU, FRA, GBR, IND, ITA, JPN, NLD, RUS.
Anything not marked β β inside the table or beyond it β returns valid: null, never false. Treat a null as "we do not know": accept it, and do not read it as either a pass or a fail.
The CNH, CPF and DNI/NIE are checked with real check-digit arithmetic, so a transposed digit is caught β unlike the licence tables, which are shape-only because those jurisdictions publish no check digit.
Naming the Jurisdiction
issuingCountry is the country β an ISO 3166-1 alpha-3 code, a country name, or a common alias. issuingState is a subdivision within that country β a US state or a Canadian province or territory β and only driver's licenses use it.
| Document type | issuingCountry | issuingState | Notes |
|---|---|---|---|
drivers_license (US) | USA | the state, e.g. PA | |
drivers_license (Canada) | CAN | the province or territory, e.g. ON | |
drivers_license (Brazil) | BRA | β | The CNH is national; the issuing DETRAN does not change the number |
passport | the issuing country | β | |
identity_card | the issuing country | β | |
ssn, itin | USA | β | US-only identifiers; any other country is a 422 |
Always send issuingCountry. A licence sent without one falls back to USA so pre-issuingCountry integrations keep working, but relying on that fallback is how a non-US licence gets checked against a US state's format. Nothing else infers a country: a passport or identity card without one returns valid: null.
ssn and itin are validator-only. They are not capturable document types β you cannot create a session for one β but the structural rules are useful when you collect them on your own forms.
Interpreting the Response
valid is deliberately three-valued:
| Value | Meaning | How to treat it |
|---|---|---|
true | Matches the known format for that jurisdiction | Accept |
false | Violates the known format | Reject before creating the session |
null | No rule exists for that jurisdiction | Accept β an unknown jurisdiction is never a failure |
A null is the honest answer for a jurisdiction we have no rule for, and it is the reason coverage gaps below are safe rather than silently wrong.
rule names the rule that was applied, so you can tell which jurisdiction answered:
rule | Meaning |
|---|---|
dl:USA:PA | A US license checked against Pennsylvania's format |
dl:CAN:ON | A Canadian licence checked against Ontario's format |
dl:BRA | A Brazilian CNH checked against the national check digits β no subdivision component, because the issuing DETRAN does not change the number |
dl:USA:unknown_subdivision | A US license with no resolvable state β valid: null |
dl:<country>:none | A license from a country we have no license rules for β valid: null |
dl:unknown_country | Neither country nor subdivision resolved β valid: null |
passport:USA | A passport checked against that country's format |
passport:no_country_rule | A passport from a country we have no format for β valid: null |
id_card:ESP | An identity card checked against that country's national scheme |
ssn:USA, itin:USA | The US structural rules |
Errors
| Status | Cause |
|---|---|
401 | Missing or invalid Bearer token |
403 | Token lacks the sessions scope |
422 | issuingCountry could not be resolved to a country |
422 | issuingState sent for a passport or identity card β pass the country as issuingCountry |
422 | ssn or itin sent with a non-US issuingCountry |
The second one is worth reading twice if you integrated before issuingCountry existed: issuingState used to carry the country for passports and identity cards. Sending it that way now is a hard error rather than a quiet null, because a null read as a pass is the worse failure.
Next Steps
- Verification Sessions β creating a session, and the
prefillthat uses this same check - Sandbox & Test Data β reserved numbers that return a chosen verdict on demand
