NHTSA VIN Decoder API (vPIC): Tutorial, Gotchas, Real Examples

NHTSA's vPIC API is the free, keyless, official VIN decoder every commercial vehicle API is built on — including ours. This is the tutorial we wish had existed when we built on it: the single and batch endpoints with real responses, the in-band ErrorCode behavior that breaks naive error handling, the blank-field and body-style-split gotchas we hit running it in production, and where recalls actually live (hint: a different API).

By the CarWhere Engineering team · Updated October 2026 · Every example response on this page is real and re-verified

Decode one VIN

DecodeVinValues returns one flat object of ~140 fields — the easiest variant to consume (its sibling DecodeVin returns the same data as a verbose variable/value list):

curl "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVinValues/1GTPHGE80TZ138393?format=json"

# Real response (key fields of ~140):
# "ModelYear": "2026", "Make": "GMC", "Model": "Sierra", "Trim": "Denali",
# "DisplacementL": "3", "EngineCylinders": "6", "FuelTypePrimary": "Diesel",
# "DriveType": "4x2", "BodyClass": "Pickup",
# "PlantCity": "FORT WAYNE", "PlantState": "INDIANA",
# "GVWR": "Class 2E: 6,001 - 7,000 lb (2,722 - 3,175 kg)",
# "ErrorCode": "0"   <-- success signal lives HERE, not in the HTTP status

The three gotchas that break production code

1. Errors are in-band, always HTTP 200

Branch on ErrorCode: 0 = clean, 1 = check-digit failure, 8 = encoded data unresolvable (frequent on European-market VINs, which encode less in positions 4–8), 11 = incorrect model year. Codes comma-combine ("6,14"). A try/catch on the HTTP call catches nothing.

2. Blank means "not filed," not "none"

Manufacturers file to vPIC with varying depth. Our Sierra example returns a full drivetrain but an empty TransmissionStyle. Never render a blank vPIC field as a fact about the car; fall back to spec data keyed by year/make/model/engine instead.

3. Recalls split by body style on the recalls API

The recalls API is keyed by make/model/year strings, and some models are filed per body style or variant — query the plain model name and you can get 0 results for a vehicle that has open campaigns. Production code has to enumerate the model-name variants and union campaigns by NHTSA campaign number. (We learned this the hard way; our complaint/recall aggregation unions variants before counting.)

Batch, recalls, and partial VINs

# Batch: up to 50 VINs per POST, semicolon-separated (model year optional after a comma)
curl -X POST "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/" \
  -d "format=json" \
  --data-urlencode "data=1GTPHGE80TZ138393;5FNYG1H45TB078338,2026"
# Recalls are a SEPARATE NHTSA API, queried by year/make/model (not VIN):
curl "https://api.nhtsa.gov/recalls/recallsByVehicle?make=honda&model=pilot&modelYear=2023"

# Real response: "Count": 5, campaigns include
# "NHTSACampaignNumber": "23V735000", "Component": "STEERING:RACK AND PINION:RACK"
# Partial VINs work — replace unknown characters with *
curl "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVinValues/1GTPHGE8*TZ******?format=json"

Bulk tip: for sustained high-volume decoding, vPIC publishes its entire database as a downloadable standalone file — self-hosting it is both faster and kinder than hammering the public endpoint.

If you'd rather skip the glue code

CarWhere's production API does the vPIC call, the error-code handling, the model-name normalization, and the recalls union in one authenticated request — GET /api/dealer/v1/decode?vin=… returns the decode plus the vehicle's open recall campaigns. The same $49/month key covers original window stickers, sticker parsing, full specs since 1984, recall feeds, and market values. 7-day free trial.

FAQ

Is the NHTSA vPIC API free? Does it have a rate limit?

Free, no API key, no published hard rate limit. It is a government service with no SLA though: latency varies, there are maintenance windows (typically announced on the vPIC site), and heavy bulk use is better served by downloading their standalone database (vPIC offers the full dataset as a downloadable file you can host yourself).

Why does vPIC return HTTP 200 for an invalid VIN?

By design, errors are in-band: every decode returns 200 with an ErrorCode field in the result. "0" is a clean decode; "1" is a check-digit failure; "8" means the model year or other encoded data couldn't be resolved (common on some European-market VINs); several codes can be comma-combined. Production code must branch on ErrorCode, not on HTTP status.

Why are some fields blank in a successful decode?

vPIC only contains what manufacturers file with NHTSA, and filing depth varies. Transmission style, horsepower, and some trim data are frequently blank for brands that don't submit them — a blank field means "not filed," not "doesn't exist." Our 2026 GMC Sierra example decodes cleanly but leaves TransmissionStyle empty.

Does the NHTSA API return recalls for a VIN?

Not from the decode endpoint. Recalls live on a separate API (api.nhtsa.gov/recalls/recallsByVehicle) queried by make, model, and model year — so getting "decode + recalls" takes two calls plus model-name normalization, and the recalls API splits some models by body style, which silently returns 0 results for plain model-name queries unless you aggregate the variants. This two-call + normalization dance is exactly what production VIN APIs collapse into one response.

Can vPIC decode a partial VIN?

Yes — substitute * for unknown positions. Useful for pattern work (all variants of a WMI/VDS) and for damaged-plate lookups. The check digit is skipped for partial decodes.

Does vPIC cover motorcycles, RVs, and trailers?

Yes — every vehicle type sold in the US since the 17-character standard (1981), including motorcycles, RVs, travel trailers, and incomplete vehicles like cutaway chassis. The useful fields differ by type (displacement for motorcycles, body class and chassis maker for RVs).

Related