VIN Decoder: Bulk Vehicle Specs from NHTSA vPIC avatar

VIN Decoder: Bulk Vehicle Specs from NHTSA vPIC

Pricing

$1.00 / 1,000 vin decodeds

Go to Apify Store
VIN Decoder: Bulk Vehicle Specs from NHTSA vPIC

VIN Decoder: Bulk Vehicle Specs from NHTSA vPIC

Decode VINs in bulk with NHTSA vPIC: make, model, year, trim, body, engine, plant and GVWR, plus a check-digit flag. $1 per 1,000 decoded; invalid VINs free.

Pricing

$1.00 / 1,000 vin decodeds

Rating

0.0

(0)

Developer

Kaizoku Data

Kaizoku Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Decode a list of VINs (vehicle identification numbers) into make, model, model year, trim, body class, vehicle type, engine (cylinders, displacement, fuel), drive, transmission, plant (city, state, country), manufacturer and GVWR. You get one row per VIN. The data comes from NHTSA vPIC, the US government's vehicle catalog (free, public, no key). Each VIN is first checked here: it must have the right format, and its North-American check digit is reported.

Price: $1.00 per 1,000 decoded VINs ($0.001 per VIN that vPIC decoded), plus Apify's default Actor-start event. Invalid VINs, VINs vPIC cannot decode, and failed calls are free.

  • Up to 10,000 VINs per run, sent in batches of 50 (vPIC's documented maximum), one call at a time.
  • Format check before any call: exactly 17 characters, no I, O or Q. Spaces are removed and letters upper-cased. Entries that fail become free rows and are never sent.
  • Check digit flag: checkDigitValid says whether position 9 matches the North-American formula. A wrong check digit is reported but not refused: vPIC still decodes the VIN, and VINs built for other markets often skip the check digit.
  • Curated or complete: by default you get about 25 useful fields. With Include all vPIC fields on, each row also gets every non-empty vPIC variable (airbags, safety systems, battery, wheelbase …), at the same price.
  • Quick start: press Start. The prefilled input decodes 3 public sample VINs (two from NHTSA's own API examples, one from Wikipedia's check-digit example). It takes under a minute (about 2 seconds of decoding) and costs $0.003.

Polite by design. The Actor sends an honest User-Agent (vin-decoder-actor/0.1 (https://apify.com/ataism/vin-decoder)), makes one vPIC call at a time with at least 1 second between calls (5 seconds for runs of over 1,000 VINs during NHTSA's business hours), backs off on HTTP 429 and server errors, and stops when vPIC refuses. Your VINs are sent to NHTSA only, and are never written to the log.

What it does

  1. Check. Each entry is cleaned (whitespace removed, upper-cased) and checked: 17 characters from 0–9 and A–Z without I, O and Q. Duplicates are removed (a VIN is decoded and charged once per run). The check digit (position 9) is computed with the North-American formula (49 CFR 565: transliteration, weights 8-7-6-5-4-3-2-10-0-9-8-7-6-5-4-3-2, remainder 11 = X).
  2. Batch. Valid VINs are grouped in input order into batches of up to 50, and each batch is one POST https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ (format JSON). With Model year set, the year is sent with every VIN.
  3. Decode. vPIC's answer is matched to each VIN. The row gets the curated fields, vPIC's own codes (nhtsaErrorCode, nhtsaErrorText) and, if asked, allFields.
  4. Charge. Only VINs that vPIC decoded are charged (rule under Pricing). Rows are saved first, then charged.

Calls start at least 1 second apart. NHTSA asks that large batch jobs run at night (US Eastern time) or at weekends. So when a run has more than 1,000 VINs to send, its calls start at least 5 seconds apart on weekdays from 6 AM to 6 PM US Eastern time (NHTSA's business hours), checked before every call. A full run of 10,000 VINs then takes about 17 minutes instead of about 10. On HTTP 429 the Actor waits as long as Retry-After asks (up to 2 minutes), then doubles its pause between calls for the rest of the run. Server errors (5xx), timeouts and network errors are tried twice more, after 5 s and 10 s. A 401 or 403 is never retried.

Input

FieldWhat it does
VINs (vins)VINs, one per line, up to 10,000 per run. Spaces and lower case are fine. Duplicates are decoded once. Partial VINs (with *) are not accepted.
Model year (optional hint) (modelYear)Optional, 1980–2030. Sent with every VIN of the run. Position 10 of a VIN repeats every 30 years (A = 1980 or 2010), and NHTSA recommends sending the year. If it does not match the VIN, vPIC adds code 12. Use it only when all VINs in the run share a year.
Include all vPIC fields (includeAllFields)Default off. On: each row also gets allFields, every non-empty vPIC variable by its vPIC name (values as text). Same price.

Example inputs

1. A fleet list (curated fields):

{
"vins": ["5XYKT3A12CG000000", "3GNDA13D76S000000", "1M8GDM9AXKP042788"]
}

2. Every vPIC field, for a data warehouse:

{
"vins": ["1M8GDM9AXKP042788", "3D7KU28C54G000000"],
"includeAllFields": true
}

3. VINs of one model year, with the year hint:

{
"vins": ["5XYKT3A12CG000000"],
"modelYear": 2012
}

Output

One item per unique entry. Example (prefill VIN from NHTSA's examples, curated fields, as decoded live on 2026-10-26):

{
"input": "5XYKT3A12CG000000",
"vin": "5XYKT3A12CG000000",
"valid": true,
"checkDigitValid": false,
"status": "decoded",
"billable": true,
"make": "KIA",
"model": "Sorento",
"modelYear": 2012,
"trim": "GL(Middle-low grade)",
"series": null,
"bodyClass": "Sport Utility Vehicle [SUV]/Multipurpose Vehicle [MPV]",
"vehicleType": "MULTIPURPOSE PASSENGER VEHICLE (MPV)",
"doors": 4,
"engineCylinders": null,
"engineDisplacementL": 2.4,
"engineHP": null,
"engineModel": "DOHC MPI THETA-II",
"engineConfiguration": null,
"fuelTypePrimary": "Gasoline",
"fuelTypeSecondary": null,
"electrificationLevel": null,
"driveType": "4x2",
"transmissionStyle": null,
"transmissionSpeeds": null,
"manufacturer": "KIA GEORGIA, INC",
"plantCountry": "UNITED STATES (USA)",
"plantState": "GEORGIA",
"plantCity": null,
"gvwr": "Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg)",
"nhtsaErrorCode": "1",
"nhtsaErrorCodes": [1],
"nhtsaErrorText": "1 - Check Digit (9th position) does not calculate properly",
"additionalErrorText": null,
"suggestedVIN": null,
"errorCode": null,
"message": null,
"modelYearHint": null,
"rowKey": "5XYKT3A12CG000000"
}

Values come from vPIC as published. Empty vPIC values are null: NHTSA notes that a missing value means it has no data on that variable, not that the vehicle lacks the feature. Numbers (modelYear, doors, engineCylinders, engineDisplacementL, engineHP, transmissionSpeeds) are numbers; everything else is text. Every row has the same keys, so CSV and Excel exports line up. input is your entry exactly as given (at most 64 characters).

The dataset has three views: Overview, Engine, drive and plant, and Codes and problems.

Status and error codes

statuserrorCodeMeaningCharged
decoded–vPIC identified the vehicle (rule below)yes
not-decodednot-decodedvPIC answered but did not identify the vehicle, e.g. code 7 (manufacturer not registered with NHTSA) or 8 (no detailed data)no
invalidinvalid-lengthNot 17 characters after removing spaces (partial VINs included)no, never sent
invalidinvalid-charactersContains I, O, Q or a character other than 0–9 / A–Zno, never sent
errorsource-unavailablevPIC answered 5xx three times (maintenance or outage)no
errorrate-limitedvPIC answered 429 three times, or asked to wait more than 2 minutesno
errorrefusedvPIC answered 401/403 or a bot challenge; never worked aroundno
errortimeout, network, dnsNo answer in time, or the connection failed (after 2 retries)no
errorbad-response, too-large, no-result, httpThe answer was not usable, or had no result for this VINno

The run stops early (with a RUN_SUMMARY saying why) when 3 batches in a row fail (source-unavailable), when 2 batches are refused (source-refused), when at least 500 sent VINs are free and outnumber the decoded ones (unpaid-work-cap), when your Max total charge is reached (max-charge), or after 50 minutes (time-limit). If vPIC refused or was down for the whole run and nothing was decoded, the run ends as failed, so you notice.

Pricing

$0.001 per decoded VIN (event vin-decoded), plus Apify's default Actor-start event. No start fee of our own.

A VIN counts as decoded, and is charged, only when vPIC returned a non-empty Make and every code in its ErrorCode list is one of the codes below. When a code says the decode is partial (2, 3, 4, 5, 6 or 14), vPIC must also have returned a Model. A garbled VIN that only yields the make from its first 3 characters is free.

CodevPIC meaning
0VIN decoded clean
1Check digit does not calculate (the rest decoded)
2, 3, 4vPIC found an error in one position and suggests a corrected VIN (suggestedVIN); the decode is partial
5Errors in a few positions (partial decode)
6Incomplete VIN (partial decode)
9, 10Glider or off-road vehicle warning
11, 12Model-year code warning, or the year you sent does not match
14Some characters could not be decoded (partial decode)

Free: code 7 (manufacturer not registered with NHTSA), code 8 (no detailed data), code 400 (a character not allowed in that position; vPIC checks positions more strictly than the Actor's format check), any other code, an empty Make, a partial decode without a model, every invalid entry, and every failed call. Check billable on each row and RUN_SUMMARY.charged for the run.

VINs decodedPrice
3 (prefill)$0.003
100$0.10
1,000$1.00
10,000 (one full run)$10.00

The run never sends more VINs than your Max total charge can pay for, so the limit is respected exactly.

Use it via API, n8n or Make

cURL (synchronous, returns the items):

curl -X POST "https://api.apify.com/v2/acts/ataism~vin-decoder/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"vins":["5XYKT3A12CG000000","1M8GDM9AXKP042788"]}'

JavaScript (npm i apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('ataism/vin-decoder').call({ vins: ['5XYKT3A12CG000000', '1M8GDM9AXKP042788'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((x) => `${x.vin}: ${x.modelYear} ${x.make} ${x.model}`));

Python (pip install apify-client):

from apify_client import ApifyClient
import os
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("ataism/vin-decoder").call(run_input={"vins": ["5XYKT3A12CG000000", "1M8GDM9AXKP042788"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["vin"], item["modelYear"], item["make"], item["model"])

n8n: add the Apify node, choose Run an Actor and get dataset, Actor ataism/vin-decoder, and put {"vins": [...]} in the input JSON.

Make: use the Apify module Run an Actor (Actor ataism/vin-decoder, Run synchronously on), then Get Dataset Items with the run's dataset ID.

Privacy and your responsibilities

In short:

  1. Only your own input is processed: the VINs you supply. The Actor never searches for or collects VINs anywhere else.
  2. Sent to NHTSA only: each valid VIN (and the model year, if you set one) goes to NHTSA's vPIC service, and nowhere else. No other data about you goes with it: no cookie, no key, no account name.
  3. Nothing kept beyond the run: results go to your run's dataset. RUN_SUMMARY and PROGRESS hold counts and a hash of the input, no VINs. VINs are never logged.
  • A VIN identifies a vehicle, not a person. But in the EU and UK, a VIN can be personal data when it is linked to an owner or keeper (for example in a fleet, insurance or dealer system). You supply the VINs and you are the data controller under GDPR / UK GDPR: you need a lawful basis, and you decide what to do with the results. The output holds vehicle facts from NHTSA only; it never contains owner, registration, history or location data.
  • Decoded data is vPIC's, as published by NHTSA from manufacturers' filings. It can be incomplete or wrong; NHTSA asks users to report discrepancies to it. This is not a vehicle history, title, theft or recall check.
  • You control retention of the dataset through your Apify settings.

Limits and honest caveats

  • Up to 10,000 VINs per run (20,000 lines including blanks and duplicates); split bigger lists. A full run of 10,000 takes about 10 minutes (200 vPIC calls of about 2–3 s each), or about 17 minutes during NHTSA's business hours (weekdays 6 AM–6 PM US Eastern), when large runs are paced at 5 s per call.
  • vPIC covers vehicles registered for the US market. NHTSA's FAQ: about 99% decode confidence from model year 1995 for major brands, about 60–65% for 1980–1994, and no data before 1980. European, Japanese or other VINs of vehicles never sold in the US often come back as code 7 (free).
  • One source. If vPIC is down (NHTSA schedules maintenance mostly at weekends), rows are free errors; run again later. NHTSA asks large batch users to run at night (US Eastern time) or at weekends; please schedule big lists that way (they also run faster then).
  • Model year hint applies to the whole run. For mixed years, leave it empty: vPIC reads the year from position 10.
  • No partial VINs. vPIC accepts * wildcards, but this Actor requires full 17-character VINs.
  • Values are text as vPIC publishes them, except the six numeric fields.

Source and terms

Data: NHTSA Product Information Catalog and Vehicle Listing (vPIC), https://vpic.nhtsa.dot.gov/api/, run by the US National Highway Traffic Safety Administration. NHTSA's vPIC FAQ says: "NHTSA is a government agency and the services provided on the API are free for use by the public as an offering as a part of our Open Data initiatives". Works of the US federal government are not under copyright in the US (17 U.S.C. § 105). This Actor is not affiliated with or endorsed by NHTSA.

Open-source components

apify 3.7.2 (Apache-2.0). Everything else is Node.js built-ins.