# VIN Decoder API: Bulk NHTSA Lookup, Specs & Recalls (`usefulapi/vin-decoder`) Actor

Decode thousands of VINs with official NHTSA data: make, model, year, trim, engine, plant. Check digit and model year verified, makers' own 2026 VIN codes, optional recalls, complaints and 5-Star crash ratings. Flat CSV. From USD 1.00 per 1,000 VINs.

- **URL**: https://apify.com/usefulapi/vin-decoder.md
- **Developed by:** [Useful API](https://apify.com/usefulapi) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 decoded vins

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## VIN Decoder API: bulk NHTSA lookup, specs and recalls

Decode one VIN or 100,000 in a single run with the US government's official vehicle data (NHTSA vPIC): make, model,
model year, trim, body, engine, drive, transmission, GVWR and assembly plant, one clean row per VIN, ready for Excel,
CSV, JSON or your app. Every VIN is also checked against the federal VIN rule (49 CFR 565): check digit, model year code,
maker code, plant and serial number, with plain-English warnings when something is wrong. Model year 2026 VINs from 19
makers are also read against **the maker's own VIN code tables** filed with NHTSA. Recalls, owner complaints and NHTSA's 5-Star crash test ratings can be
added for each vehicle.

No API key, no sign-up anywhere else, no subscription: USD 1.00 per 1,000 decoded VINs.

### Who it's for

- **Car dealers and auction sites:** check and complete a whole inventory or a lot list from its VINs in seconds.
- **Fleet managers:** one sheet with every vehicle's specs, plant and open recall campaigns for its model year.
- **Insurers, lenders and leasing:** catch mistyped or fake VINs (check digit, model year, test patterns) before they
  reach a quote or a contract.
- **Parts shops and marketplaces:** turn a VIN into make, model, year, engine and drive to match parts.
- **Developers:** a VIN decoder API you call from code, with the same columns on every row.

### What you get for each VIN

| Group | Fields |
|---|---|
| **Vehicle (NHTSA vPIC)** | make, model, modelYear, trim, series, bodyClass, vehicleType, doors, seats, driveType, engine (one line), engineCylinders, displacementL, engineHP, engineModel, fuelTypePrimary, electrificationLevel, batteryKWh, transmissionStyle, transmissionSpeeds, gvwr, curbWeightLB, manufacturer, plantCity, plantState, plantCountry |
| **VIN check (offline, 49 CFR 565)** | valid, checkDigit, checkDigitExpected, checkDigitValid, modelYearCode, modelYearCandidates (both years a code can mean), modelYearOffline, wmi, manufacturerId, vds, plantCode, serialNumber |
| **Flags** | flags (codes) and warnings (plain English): wrong length, illegal characters, I/O/Q typos with a corrected VIN, check digit mismatch, invalid year code, model year after next year, test patterns, NHTSA's own error codes explained |
| **Maker's VIN filing** (model year 2026, Ford 2027) | makerFilingModel, makerFilingDecode (each coded position as the maker wrote it: line, series, body, engine, restraints, GVWR), makerFilingPlant, makerFilingSource (file and date), makerFilingLink (the PDF at NHTSA) |
| **Recalls** (option) | recallCount, recallCampaigns, recallParkIt, recallParkOutside, recallModels (the NHTSA name used) |
| **Complaints** (option) | complaintCount, complaintCrashes, complaintFires, complaintInjuries, complaintDeaths, complaintTopComponents |
| **Crash test ratings** (option) | ratingOverall, ratingFrontCrash, ratingSideCrash, ratingSidePole, ratingRollover (NHTSA 5-Star stars), rolloverRiskPercent, ratingsVehicle (the rated version used) |
| **Nested details** (option) | nhtsaFields (every non-empty NHTSA field for the VIN), makerFiling (position by position), recalls (subject, summary, consequence, remedy, report date, units affected) |

Every row also says where each part came from (`source`) and its `status`:

| status | Meaning | Billed as |
|---|---|---|
| `decoded` | NHTSA decoded the VIN cleanly (make and model) | VIN decoded |
| `decoded_with_warnings` | NHTSA decoded it but reported issues (see flags) | VIN decoded |
| `partial` | NHTSA returned the make but no model (common for VINs of cars not sold in the US) | VIN checked |
| `not_decoded` | NHTSA returned no make (for example an unregistered maker) | VIN checked |
| `invalid` | not a valid 17-character VIN; not sent to NHTSA | VIN checked |
| `nhtsa_unavailable` | NHTSA did not answer after retries; the offline check is still in the row | VIN checked |
| `offline` | you switched NHTSA off: offline check and maker filing only | VIN checked |

### Why this decoder

- **Bulk and fast:** 50 VINs per NHTSA request (the most NHTSA allows), about 1,000 VINs in 30 seconds. Paste a list or
  give the link to a CSV (a Google Sheet published as CSV works); the VIN column is found for you. Duplicates are decoded
  once, and text that is not a VIN (makes, prices, stock numbers) is skipped, not billed.
- **Explains the VIN, not just looks it up.** The check digit with the value it should have, both model years a code can
  mean and which one applies, the I/O/Q typo fixed when the check digit proves it. Works even when NHTSA is down.
- **No false alarms on non-US VINs.** NHTSA marks many European and Asian home-market VINs as "check digit does not
  calculate". The check digit is only required for vehicles made for the US and Canada; the warning says so.
- **The maker's own codes** for model year 2026 (Ford 2027): Ford, GM (Chevrolet, GMC, Buick, Cadillac), Stellantis (Jeep,
  Ram, Dodge, Chrysler), Toyota and Lexus, Honda and Acura, Hyundai and Genesis, Kia, Nissan and Infiniti, Subaru, Mazda,
  Mitsubishi, Tesla, BMW and MINI, Mercedes-Benz, Volkswagen, Audi, Porsche, Volvo and Polestar, Jaguar Land Rover.
- **Recalls you can trust.** NHTSA's safety data names vehicles differently from its VIN decoder (the decoder says
  "Silverado", the recall data "SILVERADO 1500"; 2026 models are listed as "TAHOE ICE", "MODEL Y BEV"). This decoder
  matches the names, including the powertrain, and never borrows another version's recalls (a Q5 SUV does not get the Q5
  Sportback's). When NHTSA does not find the vehicle, the row says **not found**, never "0 recalls".
- **NHTSA trouble never fails your run.** Retries with backoff; a VIN NHTSA cannot answer still gets its row and a clear
  reason; you are billed the lower price for it.

### Input

```json
{
  "vins": ["1HGCM82633A100000", "1GCUYDED0LZ100001, 2020", "1FTMW1KC9VFA00001"],
  "recalls": true,
  "complaints": false
}
```

| Field | Default | Notes |
|---|---|---|
| `vins` | | One VIN per line (the form starts with 4 examples). Spaces, dashes and lower case are fine. Add the model year after a comma if you know it. Up to 100,000 per run |
| `vinListUrl` | | A .txt or .csv file (up to 5 MB). The VIN column is found by its header or content; a Year or Model year column is used. Web pages and Excel files are refused (save as CSV) |
| `nhtsa` | true | Off = offline check only (cheaper) |
| `recalls` | false | Recall campaigns for each vehicle's make, model and model year |
| `complaints` | false | Owner complaint summary for the make, model and model year |
| `ratings` | false | NHTSA 5-Star crash test ratings for the matching rated version |
| `details` | false | Nested blocks: all NHTSA fields, the maker's filing position by position, each recall's text |
| `fixIoq` | true | Read I as 1 and O, Q as 0 when the check digit then holds (the row says so) |
| `dedupe` | true | Same VIN and year given twice = one row |

### Output example (one row, shortened)

```json
{
  "vin": "1GCUYDED0LZ100001",
  "status": "decoded",
  "make": "CHEVROLET",
  "model": "Silverado",
  "modelYear": 2020,
  "trim": "LT",
  "series": "1500",
  "bodyClass": "Pickup",
  "driveType": "4WD/4-Wheel Drive/4x4",
  "engine": "5.3 L, 8 cyl, L84 - DI, DFM, ALUM, GEN 5, VAR 2",
  "transmissionStyle": "Automatic",
  "transmissionSpeeds": 8,
  "plantCity": "FORT WAYNE",
  "plantCountry": "UNITED STATES (USA)",
  "checkDigitValid": true,
  "modelYearCandidates": "2020 or 1990",
  "flags": null,
  "recallsStatus": "ok",
  "recallModels": "SILVERADO 1500",
  "recallCount": 12,
  "source": "49 CFR 565 (offline) + NHTSA vPIC + NHTSA recalls"
}
```

A 2026 vehicle also gets the maker's filing, for example (Ford's model year 2027 filing):

```json
{
  "makerFilingModel": "Ford F-150",
  "makerFilingDecode": "4 (M): Hydraulic brakes; GVWR E (6001 - 7000 lb); restraints: Manual Belts, Driver Frontal, Pass. Frontal, Side inflatable 1st Row; 5-7 (W1K): F-Series, F150 XL, 4x2, SuperCrew; 8 (C): 3.0L GTDI, V-6, Gasoline, Ford",
  "makerFilingPlant": "Dearborn: Dearborn, Michigan",
  "makerFilingSource": "Ford Motor Company, model year 2027 VIN filing to NHTSA (49 CFR 565.16): 2027 MY VIN Attachment -Rev 3.pdf, August 6, 2026"
}
```

The example VINs in this page and in the input are made up on real VIN patterns, with a correct check digit.

The dataset has five views: Overview, Specs, VIN checks, Maker's VIN filing, Recalls and complaints. The run summary
(record `OUTPUT`) counts rows per status, duplicates dropped and NHTSA requests, and says why a run stopped early if it did.

### Pricing

Pay per event, no subscription:

| Event | Price |
|---|---|
| VIN decoded (NHTSA returned the vehicle) | USD 1.00 per 1,000 |
| VIN checked (invalid, offline mode, or NHTSA could not answer) | USD 0.30 per 1,000 |
| Recalls added to a VIN | USD 1.00 per 1,000 |
| Complaints added to a VIN | USD 1.50 per 1,000 |
| Crash ratings added to a VIN | USD 1.00 per 1,000 |
| Run start | USD 0.002 |

Recalls, complaints and crash ratings are billed only on rows where NHTSA answered (status `ok`). Set a maximum cost per run and the
decoder stops cleanly before it, keeping every row decoded so far.

### Good to know

- **Recalls and complaints take longer:** NHTSA's safety service is asked politely (about 3 requests a second), so a list
  of all-different vehicles runs at roughly 1 to 2 seconds per vehicle; a fleet of the same models is much faster (each
  make, model and year is looked up once per run).
- **Recalls are per model year, not per VIN.** NHTSA's public data lists the recalls for a make, model and model year;
  it does not say whether this exact vehicle is included or already repaired. Check a single VIN at nhtsa.gov/recalls or
  with the maker.
- **Before 1981** VINs were not standardized (often fewer than 17 characters). No government source decodes them; such
  VINs are flagged, not guessed.
- **NHTSA covers vehicles sold in the US.** VINs of vehicles never sold there often decode only partly (make, plant
  country); missing fields stay empty. Nothing is filled in by guesswork.
- **Model year 2026 maker filings** come from NHTSA's Manufacturer Information Database (the makers' own 49 CFR 565.16
  submissions). Other years use NHTSA's decode only.
- Data sources: NHTSA vPIC (vpic.nhtsa.dot.gov/api), NHTSA recalls and complaints (api.nhtsa.gov), NHTSA Manufacturer
  Information Database. This is not a vehicle history report: no owners, titles, accidents or mileage.

### FAQ

**Is this a free VIN decoder?** The data is NHTSA's free public data; the tool is pay per use (USD 1.00 per 1,000 decoded
VINs, nothing per month). Apify's free plan credit covers thousands of VINs.

**How many VINs can I decode at once?** Up to 100,000 per run, 50 per NHTSA request; 1,000 VINs take about 25 seconds.

**Can I upload a spreadsheet?** Yes: paste the VIN column, or give the link to a CSV file (a Google Sheet published as
CSV works). The VIN column and a Year column are found for you; other columns are ignored.

**Does it give vehicle history (accidents, owners, mileage, title)?** No. That data is not public. This is a VIN
decoder: what the vehicle is, as its maker reported it to NHTSA, plus NHTSA's recalls and complaints for its model.

**Which crash test rating does a VIN get?** NHTSA rates versions of a model (for example a 2020 Silverado 1500 crew cab
4WD, extended cab 2WD...). The decoder picks the version that matches the VIN's drive, cab and doors. When several fit and
their stars differ, all are listed in `ratingsCandidates` and the row is not billed for ratings. Models NHTSA has not
tested say `not_rated`, never zero stars.

**Does it tell me if a recall was repaired on this car?** No: NHTSA's public data lists recalls by make, model and model
year. Check one VIN at nhtsa.gov/recalls or with the maker.

**Does it work for cars outside the US?** The offline check works on any 17-character VIN. NHTSA's decode covers vehicles
sold in the US; others usually decode only partly (make, plant country) and are billed at
the lower check price.

**What happens to VINs from before 1981?** They were not standardized (often fewer than 17 characters) and no government
source decodes them, so they are flagged invalid, never guessed.

**What if NHTSA is down?** The tool retries, then saves each VIN with its offline check and a clear reason, billed at the
lower check price. Run those VINs again later.

### Use it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/usefulapi~vin-decoder/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"vins": ["1HGCM82633A100000", "1GCUYDED0LZ100001"], "recalls": true}'
```

Questions or a VIN that decodes wrong? Open an issue on the Issues tab with the VIN and what you expected.

# Actor input Schema

## `vins` (type: `array`):

One VIN per line (17 characters; spaces, dashes and lower case are fine). Paste thousands at once with Bulk edit. Add a model year after the VIN if you know it (1HGCM82633A100000, 2003). Text that is not a VIN (a make, a price, a stock number) is skipped and not billed. Duplicates are decoded once.

## `vinListUrl` (type: `string`):

Link to a .txt or .csv file (up to 5 MB), for example a Google Sheet published as CSV (File > Share > Publish to web > CSV). The VIN column is found by its header (VIN, Vehicle Identification Number...) or by its content; a Year or Model year column is used when present. Web pages and Excel files are refused (save as CSV). Can be used together with the list above.

## `nhtsa` (type: `boolean`):

Look each VIN up in NHTSA's official vPIC database (make, model, trim, engine, plant and about 140 more fields), 50 VINs per request. Off = offline check only: format, check digit, model year code, sections and the maker's filing, billed at the lower check price.

## `recalls` (type: `boolean`):

Add the recall campaigns NHTSA lists for each vehicle's make, model and model year (count, campaign numbers, park-it and park-outside warnings). NHTSA's public data works by model year, not by VIN: it does not say whether this exact car is affected or already repaired. Billed per row that gets an answer.

## `complaints` (type: `boolean`):

Add a summary of the complaints owners filed with NHTSA for the make, model and model year: count, crashes, fires, injuries, deaths and the 5 most named components. Billed per row that gets an answer.

## `ratings` (type: `boolean`):

Add NHTSA's 5-Star Safety Ratings for the vehicle's model year and version: overall, front crash, side crash, side pole and rollover stars, and the rollover risk. The rated version is matched on drive, doors and cab; when several versions fit with different stars, they are all listed and the row is not billed. Billed per row that gets one rating.

## `details` (type: `boolean`):

Also add every non-empty NHTSA field (nhtsaFields), the maker's filing position by position (makerFiling) and each recall's text, remedy and date (recalls). Bigger rows; best for JSON. Same price.

## `fixIoq` (type: `boolean`):

VINs never use I, O or Q. When a VIN has them and reading I as 1 and O or Q as 0 gives a correct check digit, decode the corrected VIN (the row says so). Off = report such VINs as invalid with the suggestion.

## `dedupe` (type: `boolean`):

The same VIN (and model year) given twice gets one row. Off = one row (and one charge) per line.

## Actor input object example

```json
{
  "vins": [
    "1HGCM82633A100000",
    "1GCUYDED0LZ100001",
    "1FTMW1KC9VFA00001",
    "1HGCM82623A100001"
  ],
  "nhtsa": true,
  "recalls": false,
  "complaints": false,
  "ratings": false,
  "details": false,
  "fixIoq": true,
  "dedupe": true
}
```

# Actor output Schema

## `results` (type: `string`):

One row per VIN, same columns on every row. Download as CSV, Excel or JSON.

## `summary` (type: `string`):

VINs read, duplicates dropped, rows per status, billed events, NHTSA requests and why the run stopped early (if it did).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "vins": [
        "1HGCM82633A100000",
        "1GCUYDED0LZ100001",
        "1FTMW1KC9VFA00001",
        "1HGCM82623A100001"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("usefulapi/vin-decoder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "vins": [
        "1HGCM82633A100000",
        "1GCUYDED0LZ100001",
        "1FTMW1KC9VFA00001",
        "1HGCM82623A100001",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("usefulapi/vin-decoder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "vins": [
    "1HGCM82633A100000",
    "1GCUYDED0LZ100001",
    "1FTMW1KC9VFA00001",
    "1HGCM82623A100001"
  ]
}' |
apify call usefulapi/vin-decoder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,usefulapi/vin-decoder"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/uoxWtMUbltM5Ocxzd/builds/7aZkvPqfdnNeH7T09/openapi.json
