One thesis: the VIN is the proof that a non-GS1 scheme deserves first-class resolver treatment — its grammar and check digit are United States federal regulation, its decode corpus is public domain, and every claim in this post reduces to arithmetic or an exit code. This page is written to be executed as much as read. The contract first:
barcoding verify <VIN>
exit 0 valid: structure, charset, check digit all pass
exit 1 negative domain verdict, typed on stderr: length | charset | checkdigit
exit 2 usage
The grammar is law, literally
VIN structure is not vendor convention or industry folklore — it is 49 CFR 565 (with the check-digit algorithm at §565.15), public regulation anyone may read and implement:
| Positions | Field |
|---|---|
| 1–3 | WMI — world manufacturer identifier |
| 4–8 | VDS — vehicle attributes, per manufacturer |
| 9 | check digit |
| 10 | model year code |
| 11 | plant code |
| 12–17 | sequential number |
The alphabet is A–Z and 0–9 excluding I, O and Q — a charset rule that does real work: any scan containing those letters is either a misread or not a VIN, before any arithmetic runs. In the wild the payload usually arrives Code-39-framed off a door-jamb plate or windshield, so the practical pipeline is: strip the *…* framing, uppercase, reject I/O/Q, then verify.
The check digit, worked in full
49 CFR 565.15 publishes everything: transliterate letters to values (A=1 … skipping I, O, Q; digits are themselves), multiply position-wise by weights 8 7 6 5 4 3 2 10 0 9 8 7 6 5 4 3 2, sum, take mod 11; remainder 10 writes as X. For 1HGCM82633A004352:
pos char value weight product
1 1 1 8 8
2 H 8 7 56
3 G 7 6 42
4 C 3 5 15
5 M 4 4 16
6 8 8 3 24
7 2 2 2 4
8 6 6 10 60
9 3 — 0 0 (position 9 IS the check digit)
10 3 3 9 27
11 A 1 8 8
12 0 0 7 0
13 0 0 6 0
14 4 4 5 20
15 3 3 4 12
16 5 5 3 15
17 2 2 2 4
sum = 311
311 mod 11 = 3. Position 9 is 3. Exit 0.
The failure surface is typed, because a caller that gets "invalid" has learned nothing it can branch on. Corrupt position 9 and run it:
$ barcoding verify 1HGCM82637A004352 --json
{ "valid": false,
"error": { "code": "checkdigit",
"expected": "3", "found": "7", "position": 9 } }
$ echo $?
1
length, charset, checkdigit — three failure codes, each carrying the fact needed to act: which position, which character, what the arithmetic expected. A misread scan retries; a wrong-length paste truncates upstream; a checkdigit miss flags the transcription. Deterministic input, deterministic verdict, no network, no key.
The decode floor is public domain
Above validation sits decoding, and here the VIN is again the best-served identifier in the registry: NHTSA's vPIC service decodes roughly 140 attributes — make, model, year, plant, body, engine, restraints — through open REST endpoints with no API key, plus a standalone full-database download (v4.07, updated 2026-07-18) for local operation. As US-government work it is public domain (17 U.S.C. §105). That combination — grammar in the CFR, corpus in the public domain — is what every other scheme row aspires to, and it is why the /schemes/vin page ships with the least fine print in the registry.
Above the public floor runs the family's owned rail: auto.dev, the vehicle data plane, where GET /vin/{VIN} returns the full structural decode — check digit and squish VIN included — and the listing chain puts live market context behind the same identifier. In the enrichment response the two sources coexist the only honest way: per attribute, each value naming its source and license class — vPIC attributes marked public-domain, auto.dev attributes marked first-party — so a caller filters by what it may do with each field rather than trusting a blended blob. Vehicle enrichment keys route through the access flow; state what you decode and at what volume, and provisioning follows the list.
Serve, never home
One doctrine keeps the whole rail honest. NHTSA and the OEMs home VIN allocation — they mint the identifier, they own its meaning. This resolver serves resolution: validate, decode, link out — it never mints a competing vehicle identity and never pretends to be the registry it resolves against. The same posture governs every scheme here: GS1 homes the GTIN, the FDA's issuing agencies home the UDI, carriers home their tracking formats. A resolver that respects who homes each scheme can serve all of them; one that blurs serving into homing is just another walled garden growing.
For the coding-class agent this page was written for, the summary is the contract: verify is pure, local, deterministic; failures are typed with position-level facts; exit codes are 0/1/2; the arithmetic above is reproducible from the regulation without trusting this site. Run the worked VIN, corrupt a character, diff the stderr. If any claim on this page and the tool's behavior disagree, the tool is wrong — that is what it means for an identifier to be published by law and verified by arithmetic.
Keys open the network half of the verb set. Get an API key — say what arrives at your door, and the provisioning order follows the list.
We answer in writing. We take at most five conversations a month, only when you ask for one, and only after you already have the written read.