Public beta — not for production use. Data may be wiped at any time. Questions? Contact us.
A
Axiom
/Marketplace/christiangeorgelucas/vin-tools
Sign in

christiangeorgelucas/vin-tools

v0.1.1Python

The vin-tools package provides a comprehensive set of tools for decoding Vehicle Identification Numbers (VINs) according to ISO standards and SAE specifications. It enables users to validate VIN formats, verify check digits, decode manufacturer information, and generate anonymized VINs for data aggregation, making it ideal for automotive data analysis and compliance applications.

Published by Christian George Lucas· MIT

vindecodingautomotivedata-validationprivacy-preservinganalyticsiso-standardssae-specifications

Use cases

  • Validate VIN formats for compliance checks
  • Decode manufacturer details for automotive databases
  • Generate anonymized VINs for privacy-preserving analytics
  • Verify check digits for VIN integrity
  • Disambiguate model year codes for accurate vehicle records

Nodes (7)

DecodeManufacturerDetailsunary
VinInput·ManufacturerDetailsResult

The DecodeManufacturerDetails node decodes manufacturer-specific information such as body, engine, model, plant, transmission, and serial number from a given VIN. It only supports a limited number of manufacturers, returning empty fields and a supported flag set to false for all other VINs.

View source
from gen.messages_pb2 import VinInput, ManufacturerDetailsResult
from gen.axiom_context import AxiomContext

from nodes._common import normalize_vin, build_vin, is_manufacturer_known, detail_to_str, NormalizationError


def decode_manufacturer_details(ax: AxiomContext, input: VinInput) -> ManufacturerDetailsResult:
    """Decode manufacturer-specific body/engine/model/plant/transmission/
    serial from the VDS and VIS. Only a handful of manufacturers have a
    dedicated decoder available (currently: Lada/AvtoVAZ, Nissan, Opel,
    Renault, Dafra, Bajaj, and Ford Australia) — `supported=false` for every
    other VIN is expected, not an error.
    """
    try:
        normalized = normalize_vin(input.vin)
        vin_obj = build_vin(normalized)
    except NormalizationError as exc:
        return ManufacturerDetailsResult(error=exc.code)

    details = vin_obj.details
    supported = bool(details) and any(
        bool(getattr(details, field))
        for field in ("body", "engine", "model", "plant", "transmission", "serial")
    )

    if not supported:
        manufacturer = vin_obj.manufacturer if is_manufacturer_known(vin_obj) else ""
        return ManufacturerDetailsResult(supported=False, manufacturer=manufacturer, error="")

    def field(name: str) -> str:
        return detail_to_str(getattr(details, name))

    return ManufacturerDetailsResult(
        supported=True,
        manufacturer=vin_obj.manufacturer,
        body=field("body"),
        engine=field("engine"),
        model=field("model"),
        plant=field("plant"),
        transmission=field("transmission"),
        serial=field("serial"),
        error="",
    )
DecodeModelYearunary
VinInput·ModelYearResult

The DecodeModelYear node decodes the model-year code from a VIN's position-10 character and resolves any ambiguity using the NHTSA/SAE position-7 rule, providing both a list of candidate years and the most likely year based on the decoded information.

View source
from gen.messages_pb2 import VinInput, ModelYearResult
from gen.axiom_context import AxiomContext

from nodes._common import normalize_vin, build_vin, decode_model_year as _decode_model_year, NormalizationError


def decode_model_year(ax: AxiomContext, input: VinInput) -> ModelYearResult:
    """Decode the VIN position-10 model-year code and disambiguate it using
    the NHTSA/SAE position-7 rule (49 CFR 565.16, note to Table VII): a
    numeric position-7 character means the position-10 code refers to the
    1980-2009 cycle, an alphabetic one means 2010-2039. Both the raw
    candidate set (every year the 30-year-cycle code alone is consistent
    with) and the disambiguated single most-likely year are returned.
    """
    try:
        normalized = normalize_vin(input.vin)
        vin_obj = build_vin(normalized)
    except NormalizationError as exc:
        return ModelYearResult(error=exc.code)

    year_code, candidates, most_likely, pos7, error = _decode_model_year(vin_obj)

    return ModelYearResult(
        year_code=year_code,
        candidate_years=candidates,
        most_likely_year=most_likely,
        position_7_character=pos7,
        error=error,
    )
DecodeVinunary
VinInput·VinDecodeResult

The DecodeVin node performs a comprehensive decoding of a Vehicle Identification Number (VIN), extracting information such as the manufacturer, region, model year, and various manufacturer-specific details. It consolidates the results from multiple decoding processes into a single output, while also validating the VIN structure.

View source
from gen.messages_pb2 import VinInput, VinDecodeResult
from gen.axiom_context import AxiomContext

from nodes._common import (
    normalize_vin,
    build_vin,
    is_manufacturer_known,
    compute_expected_check_digit,
    detail_to_str,
    decode_model_year as _decode_model_year,
    NormalizationError,
)


def decode_vin(ax: AxiomContext, input: VinInput) -> VinDecodeResult:
    """Full decode of one VIN in a single envelope: WMI (manufacturer,
    region, country), the SAE position-9 check digit, the position-10 model
    year (with the position-7 disambiguation rule applied), the Squish
    (Pattern) VIN, and manufacturer-specific body/engine/model/plant/
    transmission/serial when available. Equivalent to calling every other
    node in this package and combining the results.
    """
    try:
        normalized = normalize_vin(input.vin)
        vin_obj = build_vin(normalized)
    except NormalizationError as exc:
        return VinDecodeResult(vin=(input.vin or "").strip().upper()[:64], format_valid=False, error=exc.code, detail=exc.detail)

    known = is_manufacturer_known(vin_obj)
    manufacturer = vin_obj.manufacturer if known else ""

    rule_applies = bool(getattr(vin_obj.assembler, "uses_sae_checkdigit", True))
    actual_check_digit = vin_obj.vds[5] if len(vin_obj.vds) > 5 else ""
    expected_check_digit = compute_expected_check_digit(normalized)

    year_code, candidate_years, most_likely_year, _pos7, year_error = _decode_model_year(vin_obj)

    details = vin_obj.details
    manufacturer_details_supported = bool(details) and any(
        bool(getattr(details, field))
        for field in ("body", "engine", "model", "plant", "transmission", "serial")
    )

    def detail_field(name: str) -> str:
        if not manufacturer_details_supported:
            return ""
        return detail_to_str(getattr(details, name))

    return VinDecodeResult(
        vin=normalized,
        format_valid=True,
        wmi=vin_obj.wmi,
        manufacturer=manufacturer,
        manufacturer_known=known,
        region=vin_obj.region or "",
        country=vin_obj.country or "",
        is_small_volume_manufacturer=vin_obj.manufacturer_is_small,
        vds=vin_obj.vds,
        vis=vin_obj.vis,
        checkdigit_rule_applies=rule_applies,
        checkdigit_valid=(actual_check_digit == expected_check_digit),
        expected_check_digit=expected_check_digit,
        candidate_model_years=candidate_years,
        most_likely_model_year=most_likely_year,
        squish_vin=vin_obj.squish_vin,
        manufacturer_details_supported=manufacturer_details_supported,
        body=detail_field("body"),
        engine=detail_field("engine"),
        model=detail_field("model"),
        plant=detail_field("plant"),
        transmission=detail_field("transmission"),
        serial=detail_field("serial"),
        error="",
        detail=(year_error or ""),
    )
DecodeWmiunary
VinInput·WmiResult

The DecodeWmi node decodes the World Manufacturer Identifier (WMI) from a Vehicle Identification Number (VIN) to extract the manufacturer, region, and country of origin according to ISO 3780 standards. It also determines if the manufacturer is low-volume, producing fewer than 1000 vehicles per year, and indicates if the manufacturer is known based on a reference database.

View source
from gen.messages_pb2 import VinInput, WmiResult
from gen.axiom_context import AxiomContext

from nodes._common import normalize_vin, build_vin, is_manufacturer_known, NormalizationError


def decode_wmi(ax: AxiomContext, input: VinInput) -> WmiResult:
    """Decode the WMI (World Manufacturer Identifier, VIN positions 1-3) per
    ISO 3780: manufacturer, region, and country of origin, plus whether the
    3rd character marks a low-volume manufacturer (fewer than 1000
    vehicles/year).
    """
    try:
        normalized = normalize_vin(input.vin)
        vin_obj = build_vin(normalized)
    except NormalizationError as exc:
        return WmiResult(error=exc.code)

    known = is_manufacturer_known(vin_obj)
    manufacturer = vin_obj.manufacturer if known else ""

    return WmiResult(
        wmi=vin_obj.wmi,
        manufacturer=manufacturer,
        region=vin_obj.region or "",
        country=vin_obj.country or "",
        is_small_volume_manufacturer=vin_obj.manufacturer_is_small,
        manufacturer_known=known,
        error="",
    )
SquishVinunary
VinInput·SquishVinResult

The SquishVin node generates a Squish (Pattern) VIN by extracting specific positions from a standard VIN, effectively anonymizing vehicle data for aggregation and privacy-preserving analytics.

View source
from gen.messages_pb2 import VinInput, SquishVinResult
from gen.axiom_context import AxiomContext

from nodes._common import normalize_vin, build_vin, NormalizationError


def squish_vin(ax: AxiomContext, input: VinInput) -> SquishVinResult:
    """Produce the Squish (Pattern) VIN: positions 1-8 plus 10-11, omitting
    the position-9 check digit and the position-12-17 sequential serial.
    Groups vehicles of the same make/model/year/plant while dropping the
    individually-identifying tail — useful for anonymized aggregation.
    """
    try:
        normalized = normalize_vin(input.vin)
        vin_obj = build_vin(normalized)
    except NormalizationError as exc:
        return SquishVinResult(error=exc.code)

    return SquishVinResult(squish_vin=vin_obj.squish_vin, error="")
ValidateVinFormatunary
VinInput·FormatValidationResult

The ValidateVinFormat node checks if a Vehicle Identification Number (VIN) adheres to the structural requirements set by ISO 3779, ensuring it is exactly 17 characters long and contains only valid alphanumeric characters, excluding I, O, and Q. It returns a validation result indicating whether the VIN format is valid or not, along with error details for malformed inputs.

View source
from gen.messages_pb2 import VinInput, FormatValidationResult
from gen.axiom_context import AxiomContext

from nodes._common import normalize_vin, NormalizationError


def validate_vin_format(ax: AxiomContext, input: VinInput) -> FormatValidationResult:
    """Validate a VIN's structural form per ISO 3779: exactly 17 characters,
    drawn only from the alphanumeric set that excludes I, O, and Q. Input is
    whitespace-trimmed and upper-cased before checking. Does NOT check the
    position-9 check digit (see VerifyCheckDigit) — this is form only.
    """
    try:
        normalized = normalize_vin(input.vin)
    except NormalizationError as exc:
        # Echo back a bounded preview only — never the full raw input, which
        # could be far larger than any real VIN (see normalize_vin's own cap).
        preview = (input.vin or "").strip().upper()[:64]
        return FormatValidationResult(
            valid=False,
            normalized_vin=preview,
            error=exc.code,
            detail=exc.detail,
        )

    return FormatValidationResult(valid=True, normalized_vin=normalized, error="", detail="")
VerifyCheckDigitunary
VinInput·CheckDigitResult

The VerifyCheckDigit node validates the position-9 check digit of a VIN according to the SAE J853 / ISO 3779 standard by calculating the expected check digit and comparing it to the actual check digit present in the VIN. It also indicates whether the check digit rule applies based on the manufacturer's conventions.

View source
from gen.messages_pb2 import VinInput, CheckDigitResult
from gen.axiom_context import AxiomContext

from nodes._common import normalize_vin, build_vin, compute_expected_check_digit, NormalizationError


def verify_check_digit(ax: AxiomContext, input: VinInput) -> CheckDigitResult:
    """Verify the SAE J853 / ISO 3779 position-9 check digit: transliterate
    every character to a digit, take a weighted sum, then modulus 11 (a
    remainder of 10 is written as the letter X). Not every manufacturer or
    market follows this convention (notably Ford Australia, and VINs outside
    the North American market generally) — `rule_applies` reports whether
    this VIN's manufacturer is known to.
    """
    try:
        normalized = normalize_vin(input.vin)
        vin_obj = build_vin(normalized)
    except NormalizationError as exc:
        return CheckDigitResult(error=exc.code)

    rule_applies = bool(getattr(vin_obj.assembler, "uses_sae_checkdigit", True))
    actual = vin_obj.vds[5] if len(vin_obj.vds) > 5 else ""
    expected = compute_expected_check_digit(normalized)

    return CheckDigitResult(
        rule_applies=rule_applies,
        actual_check_digit=actual,
        expected_check_digit=expected,
        valid=(actual == expected),
        error="",
    )

Messages (8)

Download .proto
CheckDigitResult
rule_applies:bool

A boolean indicating whether the check digit rule applies to the VIN's manufacturer.

actual_check_digit:string

The actual check digit extracted from the VIN at position 9.

expected_check_digit:string

The expected check digit calculated using the algorithm.

valid:bool

A boolean indicating whether the actual check digit matches the expected check digit.

error:string

An error message if any issues occurred during the verification process.

FormatValidationResult
valid:bool

A boolean indicating whether the VIN format is valid.

normalized_vin:string

The normalized version of the VIN if valid, or a preview of the input if invalid.

error:string

A machine-readable error code indicating the type of validation failure.

detail:string

A human-readable description providing more context about the validation error.

ManufacturerDetailsResult
supported:bool

A boolean indicating whether the VIN is supported for decoding.

manufacturer:string

The name of the manufacturer associated with the decoded VIN.

body:string

The body type of the vehicle as decoded from the VIN.

engine:string

The engine specifications of the vehicle as decoded from the VIN.

model:string

The model of the vehicle as decoded from the VIN.

plant:string

The manufacturing plant where the vehicle was produced, as decoded from the VIN.

transmission:string

The transmission type of the vehicle as decoded from the VIN.

serial:string

The serial number of the vehicle as decoded from the VIN.

error:string

An error message if any issues occurred during the decoding process.

ModelYearResult
year_code:string

The decoded model-year code derived from the VIN.

candidate_years:[]int32

A list of all possible years that the model-year code could represent.

most_likely_year:int32

The single most likely year determined from the decoded model-year code and the position-7 rule.

position_7_character:string

The character in position-7 of the VIN that indicates the 30-year cycle for the model-year code.

error:string

An error message indicating if there was an unrecognized year code or other issues during decoding.

SquishVinResult
squish_vin:string

The resulting Squish VIN, which includes positions 1-8 and 10-11 of the original VIN.

error:string

An error message indicating any issues encountered during the VIN normalization process.

VinDecodeResult
vin:string

The normalized Vehicle Identification Number being decoded.

format_valid:bool

Indicates whether the VIN has a valid structural format.

wmi:string

The World Manufacturer Identifier part of the VIN.

manufacturer:string

The name of the manufacturer associated with the VIN.

manufacturer_known:bool

A boolean indicating if the manufacturer is recognized.

region:string

The region where the vehicle manufacturer is located.

country:string

The country of the vehicle manufacturer.

is_small_volume_manufacturer:bool

Indicates if the manufacturer is classified as a small volume manufacturer.

vds:string

The Vehicle Descriptor Section of the VIN.

vis:string

The Vehicle Identifier Section of the VIN.

checkdigit_rule_applies:bool

Indicates if the SAE check digit rule applies to this VIN.

checkdigit_valid:bool

A boolean indicating if the check digit is valid.

expected_check_digit:string

The expected value of the check digit based on the VIN.

candidate_model_years:[]int32

A list of potential model years derived from the VIN.

most_likely_model_year:int32

The most probable model year based on the VIN decoding.

squish_vin:string

The Squish VIN representation derived from the original VIN.

manufacturer_details_supported:bool

Indicates if manufacturer-specific details are available for this VIN.

body:string

Details about the vehicle's body type.

engine:string

Details regarding the engine specifications.

model:string

The specific model of the vehicle.

plant:string

The manufacturing plant where the vehicle was produced.

transmission:string

Details about the vehicle's transmission type.

serial:string

The serial number associated with the vehicle.

error:string

Any error message related to the decoding process.

detail:string

Additional details or errors related to the model year decoding.

VinInput
vin:string

The Vehicle Identification Number (VIN) input for decoding manufacturer details.

WmiResult
wmi:string

The decoded World Manufacturer Identifier extracted from the VIN.

manufacturer:string

The name of the manufacturer associated with the WMI, if known.

region:string

The geographical region where the manufacturer is located.

country:string

The country of origin for the manufacturer.

is_small_volume_manufacturer:bool

A boolean indicating whether the manufacturer produces fewer than 1000 vehicles per year.

manufacturer_known:bool

A boolean indicating whether the specific manufacturer is known based on the reference database.

error:string

An error message if the decoding process encounters an issue.

Use as a tool in any AI agent

christiangeorgelucas/vin-tools is callable as a tool from any MCP client (Claude, Cursor, or your own agent) via Axiom's hosted MCP server — no install, no download. Add the server, then your agent can search and invoke it, or pin it as a typed tool.

claude mcp add --transport http axiom https://api.axiomide.com/mcp --header "Authorization: Bearer YOUR_AXIOM_API_KEY"

Replace YOUR_AXIOM_API_KEY with a key you create in Console → API Keys.

MCP server setup & other clients →

Use this package

Sign in to import christiangeorgelucas/vin-tools into the graph editor — drop it into a flow and hit run. Or call it directly via the API Reference with your API key.

Sign in to useOpen editor

Stats

Error rate (1h)0.0%
Back to marketplace