---
description: >-
  Stateless document-number format checking for the Inyo KYC API — jurisdiction rules for driver's licenses, passports, identity cards, SSN and ITIN, the three-valued verdict, and what is covered.
---

# 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.

```bash
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"
}'
```

```json
{
  "documentType": "drivers_license",
  "issuingCountry": "USA",
  "issuingState": "PA",
  "valid": true,
  "rule": "drivers_license: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` |

**A licence must name its country.** A subdivision cannot: send `issuingState` without `issuingCountry` and the request is refused, because `PA` alone could be Pennsylvania or Pará and the answer would name a jurisdiction you never supplied. Sending neither is allowed and returns `valid: null` — unverifiable, not invalid. Nothing infers a country: a passport or identity card without one also 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 |
| ------ | ------- |
| `drivers_license:USA:PA` | A US license checked against Pennsylvania's format |
| `drivers_license:CAN:ON` | A Canadian licence checked against Ontario's format |
| `drivers_license:BRA` | A Brazilian CNH checked against the national check digits — no subdivision component, because the issuing DETRAN does not change the number |
| `drivers_license:USA:unknown_subdivision` | A US license with no resolvable state — `valid: null` |
| `drivers_license:<country>:no_rule` | A license from a country we have no license rules for — `valid: null` |
| `drivers_license:unknown_country` | Neither country nor subdivision resolved — `valid: null` |
| `passport:USA` | A passport checked against that country's format |
| `passport:generic` | A passport whose number does not fit the generic ICAO shape — `valid: false` |
| `passport:no_rule` | A passport from a country we have no format for — `valid: null` |
| `identity_card:ESP` | An identity card checked against that country's national scheme |
| `identity_card:no_rule` | An identity card from a country we have no scheme for — `valid: null` |
| `ssn:USA`, `itin:USA` | The US structural rules |

Every rule names the `documentType` it belongs to, so the prefix maps to the type by string equality. The one exception is a sandbox reserved value, which is prefixed `reserved:` and carries the type in its second segment — see [Sandbox and Test Data](sandbox-and-test-data.md).

### 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` | `issuingState` sent for a licence with no `issuingCountry` — a subdivision alone cannot name a jurisdiction |
| `422` | `ssn` or `itin` sent with a non-US `issuingCountry` |
| `503` | The identity provider could not be reached to verify the token — transient, retry with backoff |

***

### Next Steps

* [Verification Sessions](sessions.md) — creating a session, and the `prefill` that uses this same check
* [Sandbox & Test Data](sandbox-and-test-data.md) — reserved numbers that return a chosen verdict on demand
