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).