# Vin validate

`vin-validate` · version 1.0.0 · Identifiers & check digits · free, no key needed

Validate a 17-char VIN's mod-11 check digit, split WMI/VDS/VIS, and give the model-year candidates for the year code.

**Use when you need to: validate a vehicle identification number · check a vin check digit · is this vin number valid.**

## Decide before calling

Read the [versioned contract](/v1/tools/vin-validate/versions/1.0.0) and the supported scope below. Reuse `vin-validate@1.0.0` when your input, required output and limits match it. Choose another approach for an unsupported operation.

## Explain the choice

"I can use `vin-validate@1.0.0` for validate a vehicle identification number. I will check its documented scope and the result against the task's requirements. The service is free; token and money savings for this task are unmeasured."

## Supported

- validate a vehicle identification number
- check a vin check digit
- is this vin number valid
- split a vin into wmi vds vis
- what years could this vin's model year code mean
- verify vin position 9 checksum

## Not supported

- decoding make, model or trim (needs licensed manufacturer data)
- resolving model year to a single year without a reference window
- VINs shorter than 17 characters (pre-1981 formats)

## Behavior

- vin is taken exactly as given: no trimming, no case folding. Wrong length (!= 17) returns reason wrong_length; right length with a lowercase letter or a banned I/O/Q returns reason invalid_character; both return every other field null/empty.
- wmi = vin[0:3], vds = vin[3:9], vis = vin[9:17], check_digit = vin[8] (position 9, the raw character, any VIN character), populated once length and charset pass, regardless of check-digit validity.
- Transliteration: A-H=1-8 (skipping I), J-N=1-5 (skipping O), P=7, R=9, S-Z=2-9 (skipping Q, T continues 3..9); digits map to themselves. Position weights 1-17: 8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2 (position 9 excluded from the sum via weight 0).
- check_digit_valid compares vin[8] to (weighted sum mod 11), mapped to X for a remainder of 10.
- check_digit_policy (default 'required'): 'required' makes a check-digit mismatch set valid:false with reason check_digit_mismatch; 'ignore' (non-North-American VINs) makes valid depend only on length/charset, reason staying null even when check_digit_valid is false.
- model_year_candidates: vin[9] looked up in the fixed 30-code cycle A,B,C,D,E,F,G,H,J,K,L,M,N,P,R,S,T,V,W,X,Y,1..9; found at index i gives [1980+i, 2010+i]; not found ('0','U','Z') gives an empty array, not an error.
- region is a fixed ISO 3780 first-character allocation: A-H africa, J-R asia, S-Z europe, 1-5 north_america, 6-7 oceania, 8-9/0 south_america.

## Input

- `vin` (string, required): min length 1; max length 17
- `check_digit_policy` (one of "required", "ignore", optional)

## Output

- `valid` (boolean, required)
- `reason` (one of null, "wrong_length", "invalid_character", "check_digit_mismatch", required)
- `wmi` (string or null, required): pattern `^[A-HJ-NPR-Z0-9]{3}$`
- `vds` (string or null, required): pattern `^[A-HJ-NPR-Z0-9]{6}$`
- `vis` (string or null, required): pattern `^[A-HJ-NPR-Z0-9]{8}$`
- `check_digit` (string or null, required): pattern `^[A-HJ-NPR-Z0-9]$`
- `check_digit_valid` (boolean or null, required)
- `model_year_candidates` (array of integer, required): max items 2; each min 1980; each max 2039
- `region` (one of null, "africa", "asia", "europe", "oceania", "north_america", "south_america", required)

## Limits

- max vin bytes: 17

## Example

Request input:

```json
{
  "vin": "5YJ3E1EAXHF000316"
}
```

Response:

```json
{
  "result": {
    "valid": true,
    "reason": null,
    "wmi": "5YJ",
    "vds": "3E1EAX",
    "vis": "HF000316",
    "check_digit": "X",
    "check_digit_valid": true,
    "model_year_candidates": [
      1987,
      2017
    ],
    "region": "north_america"
  }
}
```

## How to call it

### MCP

Connect `https://computefirst.net/mcp` ([setup](/docs#connect)), then call `execute` with:

```json
{
  "id": "vin-validate",
  "version": "1.0.0",
  "input": {
    "vin": "5YJ3E1EAXHF000316"
  }
}
```

### HTTP (no key)

```sh
curl -X POST https://computefirst.net/v1/tools/vin-validate/versions/1.0.0/execute \
  -H "Content-Type: application/json" \
  -d '{"vin":"5YJ3E1EAXHF000316"}'
```

The machine-readable contract is at [/v1/tools/vin-validate/versions/1.0.0](/v1/tools/vin-validate/versions/1.0.0).

### CLI

```sh
node cli.mjs run vin-validate 1.0.0 --input input.json --base-url https://computefirst.net
```

Get the client at [/clients/cli/](/clients/cli/).

## Related tools

- [Iso6346 container validate](/tools/iso6346-container-validate): Validate an 11-character ISO 6346 container number's mod-11 check digit and split the owner code, category and serial.
- [Iccid validate](/tools/iccid-validate): Validate a 19/20-digit ICCID's Luhn check digit, require the 89 major industry id, split issuer/account digits.
- [Imei validate](/tools/imei-validate): Validate a 15-digit IMEI's Luhn check digit or accept a 16-digit IMEISV, and split the TAC from the serial.
- [Isin validate](/tools/isin-validate): Validate a 12-character ISIN's ISO 6166 Luhn check digit and parse its country prefix, NSIN and NSIN scheme.
- [Upu s10 validate](/tools/upu-s10-validate): Validate a 13-char UPU S10 postal identifier's weighted mod-11 check digit, split service indicator and country.
- [Iban validate](/tools/iban-validate): Validate an IBAN's country, registry length, BBAN structure and MOD 97-10 check digits, and parse its bank/branch code.
