Dev.to WebDev 🛠 Dev 👁 0 📖 3 min read

Mapping NHTSA vPIC Fields: A Developer Guide to the DecodeVinValues Response

If you've called NHTSA's free vPIC API, you've seen a response with 150+ fields, most of them empty. This guide covers which fields matter, what they mean, and the traps to avoid when mapping them into your own data mode

If you've called NHTSA's free vPIC API, you've seen a response with 150+ fields, most of them empty. This guide covers which fields matter, what they mean, and the traps to avoid when mapping them into your own data model.

The endpoint

GET https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVinValues/{VIN}?format=json

DecodeVinValues returns a flat object (one key per variable), which is easier to map than DecodeVin, which returns a list of {Variable, Value, VariableId} rows. There's also DecodeVinValuesBatch (POST, up to 50 VINs) for bulk work.

Optionally pass &modelyear=2020 when you already know the year; it helps for pre-1980 or incomplete VINs.

Always check ErrorCode first

"ErrorCode": "0",
"ErrorText": "0 - VIN decoded clean. Check Digit (9th position) is correct"
  • ErrorCode is a string and can hold several comma-separated codes, e.g. "1,400".
  • 0 means clean.
  • 1 means the check digit is wrong (the rest may still decode).
  • Other codes cover invalid characters, incomplete VINs, or no matching pattern.

Treat anything other than "0" as "decoded with warnings" and show ErrorText to the user instead of silently trusting the fields.

Identity fields

Field Notes
Make, Model, ModelYear Core identity. ModelYear is the product year, not build date.
Manufacturer Legal manufacturer name; differs from Make for many brands.
Trim, Series Often empty; manufacturers don't always encode trim in the VIN.
VehicleType e.g. PASSENGER CAR, MULTIPURPOSE PASSENGER VEHICLE (MPV), TRUCK.
BodyClass e.g. Sedan/Saloon, Sport Utility Vehicle (SUV)/Multi-Purpose Vehicle (MPV).

Trim is the field users want most and get least. Don't make it required in your UI.

Powertrain

Field Notes
EngineCylinders, DisplacementL, DisplacementCC Strings; DisplacementL may have many decimals. Round for display.
FuelTypePrimary, FuelTypeSecondary Secondary is set for flex-fuel or hybrids.
ElectrificationLevel e.g. BEV, HEV, PHEV. Useful for EV filters.
DriveType e.g. 4WD/4-Wheel Drive/4x4, FWD/Front-Wheel Drive.
TransmissionStyle Frequently empty.
EngineModel, EngineHP Inconsistent coverage.

Plant fields

PlantCity, PlantState, PlantCountry, PlantCompanyName. These come from the manufacturer's plant code (VIN position 11). Country of assembly here can differ from the country implied by the WMI.

Safety equipment

Fields like AirBagLocFront, AirBagLocSide, ABS, ESC, TPMS, BlindSpotMon, AdaptiveCruiseControl. Coverage is uneven, especially for advanced driver-assistance features. An empty field means "not reported," not "not equipped." Never render empty as "No."

Mapping tips

  1. Empty strings, not nulls. Most unset fields come back as "". Normalize to null on ingest.
  2. Everything is a string. Parse numbers (ModelYear, EngineCylinders, Doors) yourself and keep the raw value if parsing fails.
  3. "Not Applicable". Some fields return this literal text. Treat it as null for display logic.
  4. Cache by VIN pattern, not just full VIN. The first 11 characters (minus check digit) largely determine the decode; caching on positions 1-8 + 10-11 can save a lot of requests for fleets.
  5. Be polite. It's a free public service. Batch where you can, cache aggressively, and back off on errors.
  6. Keep the source. Store ErrorCode, ErrorText, and a timestamp so you can re-decode when NHTSA updates manufacturer data.

Minimal TypeScript mapper

type Decoded = {
  vin: string; make: string | null; model: string | null;
  modelYear: number | null; bodyClass: string | null;
  fuel: string | null; plantCountry: string | null;
  warnings: string | null;
};
const n = (v?: string) => (!v || v === 'Not Applicable' ? null : v);
export function mapVpic(r: Record<string, string>): Decoded {
  return {
    vin: r.VIN,
    make: n(r.Make), model: n(r.Model),
    modelYear: r.ModelYear ? Number(r.ModelYear) : null,
    bodyClass: n(r.BodyClass), fuel: n(r.FuelTypePrimary),
    plantCountry: n(r.PlantCountry),
    warnings: r.ErrorCode === '0' ? null : r.ErrorText,
  };
}

What vPIC doesn't give you

No title brands, accident history, owner count, mileage, or recall status. Recalls have their own NHTSA API (by make/model/year) and a VIN lookup on nhtsa.gov; title history comes from NMVTIS-approved providers.

Disclosure: I build VIN Lookup, a free decoder that uses this same vPIC data.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.