Skip to content

API

VIN

VIN(vin: str, decode: bool = True, fix_check_digit: bool = False, decode_model_year: bool = True)

The VIN object is a unique 17-character Vehicle Identification Number.

Manufacturers assign the VIN, which uniquely identifies vehicles manufactured since 1980 for sale or use in the United States.

                                  model year
                                      |
             WMI          check digit | plant
           |-----|                 |  |  |  |--- serial ----|
Position   1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17
                    |-----------|     |---------------------|
                         VDS                    VIS

The World Manufacturer Identifier (WMI) holds the country, region, and name of the vehicle manufacturer. Mass-market manufacturers are assigned a three-character WMI. Specialized manufacturers are assigned a six-character WMI (positions 1-3 and 12-14)

The Vehicle Description Section (VDS) is defined by manufacturers to identify the vehicle make, model, body type, engine type, restraints, and the weight class (for trucks and multi-purpose vehicles).

The Vehicle Identification Section (VIS) identifies the model year, plant where the vehicle was made, and the vehicle's serial number.

Use VIN by calling the default constructor with the 17-character VIN string. To encode the VIN, convert it to a string:

>>> vin = VIN("4T1BE46K19U856421")
>>> str(vin)
'4T1BE46K19U856421'

Authority:

Vehicle Identification Number (VIN) Requirements

Parameters:

Name Type Description Default
vin str

The 17-digit Vehicle Identification Number.

required
decode bool

Decode vehicle details from the NHTSA vPIC database

True
fix_check_digit bool

If True, fix an incorrect check digit instead of raising a ValueError.

False
decode_model_year bool

If True, validate the model year character. If False, ignore the model year character, which can be useful for vehicles manufactured for markets outside North America (though results may be incomplete or inaccurate).

True

Raises:

Type Description
TypeError

vin is not a string.

ValueError

vin is not 17 characters

ValueError

vin has characters that aren't allowed in a Vehicle Identification Number

ValueError

vin check digit isn't correct

Source code in src/vin/__init__.py
def __init__(
    self,
    vin: str,
    decode: bool = True,
    fix_check_digit: bool = False,
    decode_model_year: bool = True,
) -> None:
    """Validates the VIN and decodes vehicle information.

    Args:
        vin: The 17-digit Vehicle Identification Number.
        decode: Decode vehicle details from the NHTSA vPIC database
        fix_check_digit: If True, fix an incorrect check digit instead of raising a ValueError.
        decode_model_year: If True, validate the model year character. If False, ignore the \
            model year character, which can be useful for vehicles manufactured for markets \
            outside North America (though results may be incomplete or inaccurate).

    Raises:
        TypeError: `vin` is not a string.
        ValueError: `vin` is not 17 characters
        ValueError: `vin` has characters that aren't allowed in a Vehicle Identification Number
        ValueError: `vin` check digit isn't correct

    """
    if not isinstance(vin, str):
        raise TypeError("VIN must be a string")
    if len(vin) != VIN_LENGTH:
        raise ValueError(f"VIN must be exactly {VIN_LENGTH} characters long")
    if decode_model_year and vin[9] not in VIN_MODEL_YEAR_CHARACTERS:
        raise ValueError(
            "VIN model year character must be one of these characters "
            f"{VIN_MODEL_YEAR_CHARACTERS}"
        )
    if not all(c in VIN_CHARACTERS for c in vin):
        raise ValueError(f"VIN must have only these characters {VIN_CHARACTERS}")

    check_digit = self.calculate_check_digit(vin)
    if vin[8:9] != check_digit:
        if fix_check_digit:
            vin = f"{vin[:8]}{check_digit}{vin[9:]}"
        else:
            raise ValueError("VIN check digit is incorrect")

    self._vin: str = vin
    if decode:
        self._decode_vin(decode_model_year)
    return

Attributes

body_class property

body_class: str

The body class.

This is one of:

  • Ambulance
  • Bus
  • Bus - School Bus
  • Cargo Van
  • Convertible/Cabriolet
  • Coupe
  • Crossover Utility Vehicle (CUV)
  • Fire Apparatus
  • Hatchback/Liftback/Notchback
  • Incomplete
  • Incomplete - Bus Chassis
  • Incomplete - Chassis Cab (Double Cab)
  • Incomplete - Chassis Cab (Number of Cab Unknown)
  • Incomplete - Chassis Cab (Single Cab)
  • Incomplete - Commercial Bus Chassis
  • Incomplete - Commercial Chassis
  • Incomplete - Cutaway
  • Incomplete - Glider
  • Incomplete - Motor Coach Chassis
  • Incomplete - Motor Home Chassis
  • Incomplete - School Bus Chassis
  • Incomplete - Shuttle Bus Chassis
  • Incomplete - Stripped Chassis
  • Incomplete - Trailer Chassis
  • Incomplete - Transit Bus Chassis
  • Limousine
  • Low Speed Vehicle (LSV) / Neighborhood Electric Vehicle (NEV)
  • Minivan
  • Motorcycle - Competition
  • Motorcycle - Cross Country
  • Motorcycle - Cruiser
  • Motorcycle - Custom
  • Motorcycle - Dual Sport / Adventure / Supermoto / On/Off-road
  • Motorcycle - Enclosed Three Wheeled or Enclosed Autocycle [1 Rear Wheel]
  • Motorcycle - Moped
  • Motorcycle - Scooter
  • Motorcycle - Side Car
  • Motorcycle - Small / Minibike
  • Motorcycle - Sport
  • Motorcycle - Standard
  • Motorcycle - Street
  • Motorcycle - Three Wheeled, Unknown Enclosure or Autocycle, Unknown Enclosure
  • Motorcycle - Three-Wheeled Motorcycle (2 Rear Wheels)
  • Motorcycle - Touring / Sport Touring
  • Motorcycle - Underbone
  • Motorcycle - Unenclosed Three Wheeled or Open Autocycle [1 Rear Wheel]
  • Motorcycle - Unknown Body Class
  • Motorhome
  • Off-road Vehicle - All Terrain Vehicle (ATV) (Motorcycle-style)
  • Off-road Vehicle - Construction Equipment
  • Off-road Vehicle - Dirt Bike / Off-Road
  • Off-road Vehicle - Enduro (Off-road long distance racing)
  • Off-road Vehicle - Farm Equipment
  • Off-road Vehicle - Go Kart
  • Off-road Vehicle - Golf Cart
  • Off-road Vehicle - Motocross (Off-road short distance, closed track racing)
  • Off-road Vehicle - Multipurpose Off-Highway Utility Vehicle [MOHUV] or Recreational Off-Highway Vehicle [ROV]
  • Off-road Vehicle - Snowmobile
  • Pickup
  • Roadster
  • Sedan/Saloon
  • Sport Utility Truck (SUT)
  • Sport Utility Vehicle (SUV)/Multi-Purpose Vehicle (MPV)
  • Step Van / Walk-in Van
  • Street Sweeper
  • Streetcar / Trolley
  • Trailer
  • Truck
  • Truck-Tractor
  • Van
  • Wagon

Returns:

Type Description
str

The vehicle type.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("KNDCE3LG2L5073161").body_class
'Sport Utility Vehicle (SUV)/Multi-Purpose Vehicle (MPV)'

description property

description: str

returns a one-line summary of the vehicle

Returns:

Name Type Description
str str

the model year, make, model, and series

Examples:

>>> VIN('KNDCE3LG2L5073161').description
'2020 Kia Niro EX Premium'

descriptor property

descriptor: str

The part of the VIN used to lookup make, model, and other vehicle attributes in NHTSA vPIC.

Returns:

Name Type Description
str str

the 14-character descriptor for this VIN

electrification_level property

electrification_level: str

The electrification level.

This is one of:

  • Mild HEV (Hybrid Electric Vehicle)
  • Strong HEV (Hybrid Electric Vehicle)
  • PHEV (Plug-in Hybrid Electric Vehicle)
  • BEV (Battery Electric Vehicle)
  • FCEV (Fuel Cell Electric Vehicle)
  • HEV (Hybrid Electric Vehicle) - Level Unknown

Returns:

Type Description
str

The electrification level.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("KNDCE3LG2L5073161").electrification_level
'BEV (Battery Electric Vehicle)'

make property

make: str

The vehicle make name.

Returns:

Type Description
str

The make name.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("5FNYF5H59HB011946").make
'Honda'
>>> VIN("YT9NN1U14KA007175").make
'Koenigsegg'

manufacturer property

manufacturer: str

The vehicle manufacturer name.

Returns:

Type Description
str

The manufacturer name.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("5FNYF5H59HB011946").manufacturer
'American Honda Motor Co., Inc.'
>>> VIN("YT9NN1U14KA007175").manufacturer
'Koenigsegg Automotive Ab'

model property

model: str

The vehicle model name.

Returns:

Type Description
str

The model name.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("5FNYF5H59HB011946").model
'Pilot'
>>> VIN("YT9NN1U14KA007175").model
'Regera'

model_year property

model_year: int

The vehicle model year

Returns:

Type Description
int

The vehicle model year.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("5FNYF5H59HB011946").model_year
2017
>>> VIN("2GCEC19Z0S1245490").model_year
1995

series property

series: str

The vehicle series name.

Returns:

Type Description
str

The series name.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("5FNYF5H59HB011946").series
'EXL'
>>> VIN("YT9NN1U14KA007175").series
''

trim property

trim: str

The vehicle trim name.

Returns:

Type Description
str

The trim name.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("5FNYF5H59HB011946").trim
''

vds property

vds: str

The Vehicle Description Section (VDS) of the VIN.

Returns:

Type Description
str

The Vehicle Description Section (VDS) from the VIN.

Examples:

>>> VIN("5FNYF5H59HB011946").vds
'YF5H5'

vehicle_type property

vehicle_type: str

The vehicle type.

This is one of:

  • Bus
  • Incomplete Vehicle
  • Low Speed Vehicle (LSV)
  • Motorcycle
  • Multipurpose Passenger Vehicle (MPV)
  • Off Road Vehicle
  • Passenger Car
  • Trailer
  • Truck

Returns:

Type Description
str

The vehicle type.

Raises:

Type Description
DecodingRequiredError

This property is only available when you choose to decode the VIN. See VIN.init(..., decode=True).

Examples:

>>> VIN("5FNYF5H59HB011946").vehicle_type
'Multipurpose Passenger Vehicle (MPV)'
>>> VIN("YT9NN1U14KA007175").vehicle_type
'Passenger Car'

vis property

vis: str

The Vehicle Identification Section (VIS) of the VIN

Returns:

Type Description
str

The Vehicle Identification Section (VIS)

Examples:

>>> VIN("5FNYF5H59HB011946").vis
'HB011946'

wmi property

wmi: str

The World Manufacturer Identifier (WMI) of the vehicle manufacturer.

Mass-market manufacturers are assigned a three-character WMI. For example, some Honda cars have WMI 5FN:

5FNYF5H59HB011946
^^^

Specialized manufacturers are assigned six-character WMI. For example, Koenigsegg cars have WMI YT9007:

YT9NN1U14KA007175
^^^        ^^^

Returns:

Type Description
str

The 3-character WMI for a mass-market manufacturer, or 6-character WMI for a specialized manufacturer.

Examples:

>>> VIN("5FNYF5H59HB011946").wmi
'5FN'
>>> VIN("YT9NN1U14KA007175").wmi
'YT9007'

Functions

calculate_check_digit classmethod

calculate_check_digit(vin: str) -> str

Calculate and return the VIN check digit.

Parameters:

Name Type Description Default
vin str

The 17-digit Vehicle Identification Number.

required

Returns:

Type Description
str

The calculated check digit character.

Source code in src/vin/__init__.py
@classmethod
def calculate_check_digit(cls, vin: str) -> str:
    """Calculate and return the VIN check digit.

    Args:
        vin: The 17-digit Vehicle Identification Number.

    Returns:
        The calculated check digit character.

    """
    total = 0
    for position, letter in enumerate(vin):
        if position != VIN_CHECK_DIGIT_POSITION:
            total += VIN_CHARACTER_VALUES[letter] * VIN_POSITION_WEIGHTS[position]
    return VIN_CHECK_DIGIT_CHARACTERS[total % 11]

_decode_model_year

_decode_model_year() -> int

The model year as encoded in the VIN.

Every VIN has a single character that identifies the vehicle model year. That means that the same model year character is used to represent 1995 and 2025. We can't know for sure which is the correct model year simply by looking at the VIN. To know for sure, you can decode the VIN, which uses information from NHTSA vPIC to determine the actual model year.

Returns:

Type Description
int

The vehicle model year. May be negative if the VIN alone isn't sufficient to determine the model year. When this happens, the actual model year is likely the absolute value of this model year, or 30 years earlier. To find the actual model year, look up the VIN VIN details first with the later model year and then the earlier model year -- only one of these is likely to return a result.

Examples:

>>> VIN("5FNYF5H59HB011946")._decode_model_year()
2017
>>> VIN("2GCEC19Z0S1245490")._decode_model_year()
-2025
Source code in src/vin/__init__.py
def _decode_model_year(self) -> int:
    """The model year as encoded in the VIN.

    Every VIN has a single character that identifies the vehicle model year.
    That means that the same model year character is used to represent 1995
    and 2025. We can't know for sure which is the correct model year simply
    by looking at the VIN. To know for sure, you can decode the VIN, which
    uses information from NHTSA vPIC to determine the actual model year.

    Returns:
        The vehicle model year. May be negative if the VIN alone isn't \
        sufficient to determine the model year. When this happens, the \
        actual model year is likely the absolute value of this model year, \
        or 30 years earlier. To find the actual model year, look up the VIN \
        VIN details first with the later model year and then the earlier \
        model year -- only one of these is likely to return a result.

    Examples:

        >>> VIN("5FNYF5H59HB011946")._decode_model_year()
        2017
        >>> VIN("2GCEC19Z0S1245490")._decode_model_year()
        -2025
    """
    year_code = self._vin[9]
    # assert year_code in VIN_MODEL_YEAR_CHARACTERS
    model_year = 0
    conclusive = False

    if year_code in "ABCDEFGH":
        model_year = 2010 + ord(year_code) - ord("A")
    elif year_code in "JKLMN":
        model_year = 2010 + ord(year_code) - ord("A") - 1
    elif year_code == "P":
        model_year = 2023
    elif year_code in "RST":
        model_year = 2010 + ord(year_code) - ord("A") - 3
    elif year_code in "VWXY":
        model_year = 2010 + ord(year_code) - ord("A") - 4
    elif year_code in "123456789":
        model_year = 2031 + ord(year_code) - ord("1")

    assert model_year > 0

    if self.wmi in CARS_AND_LIGHT_TRUCKS:
        if self._vin[6].isdigit():
            # cars and light trucks manufactured on or before April 30, 2009 (1980 to 2009)
            model_year -= 30
        conclusive = True

    if model_year > date.today().year + 1:
        model_year -= 30
        conclusive = True

    return model_year if conclusive else -model_year

vpic_version classmethod

vpic_version() -> dict[str, str]

Return vPIC snapshot version and release date.

NHTSA releases monthly vPIC snapshots as SQL Server backups. A subset of that data is bundled with this package.

Returns:

Name Type Description
dict dict[str, str]

The vPIC version, release date, effective date, and URL

Examples:

>>> VIN.vpic_version()
{'version': '3.44', 'released': '2024-02-17', 'effective': '2024-02-16T19:41:08+00:00',
 'url': 'https://vpic.nhtsa.dot.gov/api/vPICList_lite_2024_02.bak.zip'}
Source code in src/vin/__init__.py
@classmethod
def vpic_version(cls) -> dict[str, str]:
    """Return vPIC snapshot version and release date.

    NHTSA releases monthly vPIC snapshots as SQL Server backups. A subset
    of that data is bundled with this package.

    Returns:
        dict: The vPIC version, release date, effective date, and URL

    Examples:

        >>> VIN.vpic_version()
        {'version': '3.44', 'released': '2024-02-17', 'effective': '2024-02-16T19:41:08+00:00',
         'url': 'https://vpic.nhtsa.dot.gov/api/vPICList_lite_2024_02.bak.zip'}
    """
    return vehicle_db.get_vpic_version()