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 |
|
ValueError |
|
ValueError |
|
ValueError |
|
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()