# VIN Decoder: Open Safety Investigations & Recalls (`aiqlabs/vin-decoder-recall-audit`) Actor

Decodes VINs and checks each vehicle against NHTSA's recall campaigns and its open defect investigations - the ones that have not produced a recall yet, and which a recall search therefore reports as nothing at all. Says plainly what is model-level and what is not.

- **URL**: https://apify.com/aiqlabs/vin-decoder-recall-audit.md
- **Developed by:** [Ai-Q Labs](https://apify.com/aiqlabs) (community)
- **Categories:** Automation, Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## VIN Decoder: Open Safety Investigations & Recalls

A recall is the **end** of a process. Before it there is an investigation — NHTSA has opened a file on a suspected defect and has not yet decided.

Every VIN tool answers "any recalls?". None of them answers "is this model under investigation right now?" — and that is the question a recall search silently returns *no* to.

### The problem, with real examples

Run a recall check on a **2013 Honda Odyssey** today and you learn nothing about `DP26005`, *Inadvertent Deployment of Air Bags*, opened **13 July 2026** and still open with **no recall issued**.

A **2018 Tesla Model 3** has several open investigations and no recall for any of them, including *FSD Collisions in Reduced Roadway Visibility Conditions* and *Sudden Unintended Acceleration*.

A **2014 Range Rover** has `EA26003`, *Front Steering Knuckle Fractures*, open since April 2026. A **2022 Rivian R1T** has `PE26004`, *Rear Toe Link May Separate*.

All four report clean on a recall-only check.

### What this Actor does

For each VIN it decodes the vehicle and then reconciles four NHTSA sources:

| Source | What it answers |
|---|---|
| vPIC | What the vehicle is — make, model, year, body, engine, plant, driver-assistance systems |
| Recalls API | Which recall campaigns cover this make, model and year |
| **ODI investigation history** | **Which defect investigations are open, and whether any produced a recall** |
| Complaints & NCAP | Owner complaint volume by component, and crash test ratings |

No API key is needed for any of them, and nothing is scraped.

#### The checks

| Code | Severity | What it means |
|---|---|---|
| `open_investigation_no_recall` | high | NHTSA is investigating a suspected defect on this model year and no recall exists. **A recall search reports nothing here.** |
| `open_investigation_with_recall` | medium | An open investigation that has already produced campaigns. Open means the agency has not finished. |
| `recall_campaigns_for_model_year` | medium | Campaigns cover this model year — see the honesty note below. |
| `check_digit_failed` | medium | The VIN fails its own check digit. Almost always a transcription error. |
| `model_year_mismatch` | medium | Position 10 of the VIN and NHTSA's decode disagree. |
| `open_investigation_related_variant` | low | An open investigation covers a related trim rather than this exact model. |
| `complaint_cluster_without_action` | low | Complaints concentrate on one component with no recall or investigation. **This Actor's inference, not NHTSA's finding.** |

### What it deliberately does *not* claim

**It never says a recall is outstanding on your specific car.** NHTSA's public API answers at make/model/year granularity; the VIN-level lookup on its website is not exposed as an API (`/recalls/vin/<VIN>` returns 403 — the route does not exist). A car may sit outside the affected production range, or have had the work done years ago. So the field is named `recallCampaignsForModelYear`, the output carries `vinLevelRecallStatusAvailable: false`, and the message tells you to confirm with the manufacturer. Tools that print "your VIN has 3 open recalls" from this same data are overstating it.

**An open investigation is NHTSA's record; a complaint cluster is a pattern this Actor read.** They get different severities and different wording.

**A healthy vehicle produces no findings.** If there is nothing open, nothing recalled and no unusual complaint concentration, the row comes back silent. A report where everything is flagged is a report nobody reads.

**The check digit is only checked where the standard requires one.** Vehicles built outside North America are not required to carry a valid one, and many do not — flagging those would put a warning on a large share of ordinary imports.

**If the investigation file could not be read, the status is `unknown`, never clear.** Absence of a finding is not evidence of absence.

### Input

```json
{
  "vins": ["5FNRL5H66DB000001", "5YJ3E1EAXJF006588"],
  "checkInvestigations": true,
  "includeComplaints": true
}
```

### Output

One row per VIN. The fields that carry the verdict:

| Field | Values |
|---|---|
| `safetyStatus` | `open_investigation` · `investigation_in_progress` · `recalls_to_verify` · `nothing_outstanding` · `unknown` |
| `openInvestigationsWithoutRecall` | Count of open investigations that produced no recall |
| `investigations[]` | `{ investigationId, subject, component, opened, closed, isOpen, recallIssued, linkedRecallCampaigns }` |
| `recallCampaignsForModelYear` | Campaign count for the model year, not for this VIN |
| `issues[]` | `{ code, severity, message, evidence }` |
| `highestSeverity` | `high` · `medium` · `low` · `ok` |

Alongside them: the full decode (make, model, year, trim, body, engine, drive, fuel, plant, GVWR, driver-assistance systems), `checkDigitValid`, `complaintCount` with crashes, fires, injuries and deaths reported, `complaintTopComponents`, and `safetyRatings`.

Three key-value records are written as well: `SUMMARY`, `OPEN_INVESTIGATIONS` (the vehicles with something open and no recall) and `NEEDS_ATTENTION`.

### How it stays cheap

Only the decode is per-VIN. Recalls, investigations, complaints and ratings are all model-level, so a fleet of two hundred identical vans is **one** safety lookup, not two hundred. The investigation history is a single 2 MB download for the whole run.

### Limits, stated plainly

- **US market only.** These are NHTSA datasets.
- **Investigations are matched on make, model and model year**, which is the granularity NHTSA publishes. A trim-specific defect on a variant is reported separately rather than merged.
- **The investigation file is point-in-time.** It is refreshed periodically; an investigation opened this week may not be in it yet.
- **Of the 5,338 investigations in the file, 4,060 name a specific vehicle** — the rest are equipment and tyre inquiries with the vehicle columns blank, and cannot be matched to a VIN. Within the 4,060, 118 are open and 94 have produced no recall.
- **No VIN-level recall completion status exists publicly.** See above.

### Sources

- NHTSA vPIC — `https://vpic.nhtsa.dot.gov/api/`
- NHTSA recalls, complaints and safety ratings — `https://api.nhtsa.gov/`
- NHTSA ODI investigation history — `https://static.nhtsa.gov/odi/ffdd/inv/FLAT_INV.zip`

This Actor reports what those sources say. It is not a safety certification, and it does not replace checking a specific VIN at nhtsa.gov/recalls before buying or dispatching a vehicle.

# Actor input Schema

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

Vehicle Identification Numbers to audit. Seventeen characters each; spaces and hyphens are ignored.

## `checkInvestigations` (type: `boolean`):

Download NHTSA's investigation history and report investigations that are still open. This is the part a recall search cannot tell you. Turning it off makes every safety status unknown rather than clear.

## `includeRelatedVariants` (type: `boolean`):

Also list open investigations into related versions of the model (for example a hybrid trim), reported separately and at the lowest severity.

## `includeComplaints` (type: `boolean`):

Summarise consumer complaints for the model year: how many, over what period, and which components attract them.

## `includeRawComplaints` (type: `boolean`):

Attach the complete complaint records rather than the summary. These run to megabytes for a popular model year.

## `includeSafetyRatings` (type: `boolean`):

Add NHTSA's star ratings for the model year, where the vehicle was tested.

## `maxVehicles` (type: `integer`):

Upper bound on how many VINs to audit in one run. Anything beyond it is dropped and the count is reported in SUMMARY.

## `concurrency` (type: `integer`):

How many lookups to run at once. NHTSA is a free public service, so keep this modest.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout. The investigation archive is several megabytes, so this guards the handshake rather than the whole transfer.

## Actor input object example

```json
{
  "vins": [
    "5FNRL5H66DB000001",
    "5YJ3E1EAXJF006588",
    "1HGCM82633A004352"
  ],
  "checkInvestigations": true,
  "includeRelatedVariants": true,
  "includeComplaints": true,
  "includeRawComplaints": false,
  "includeSafetyRatings": true,
  "maxVehicles": 500,
  "concurrency": 4,
  "requestTimeoutSecs": 60
}
```

# Actor output Schema

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

No description

## `csv` (type: `string`):

No description

## `openInvestigations` (type: `string`):

No description

## `needsAttention` (type: `string`):

No description

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

No description

# 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": [
        "5FNRL5H66DB000001",
        "5YJ3E1EAXJF006588",
        "1HGCM82633A004352"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aiqlabs/vin-decoder-recall-audit").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": [
        "5FNRL5H66DB000001",
        "5YJ3E1EAXJF006588",
        "1HGCM82633A004352",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("aiqlabs/vin-decoder-recall-audit").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": [
    "5FNRL5H66DB000001",
    "5YJ3E1EAXJF006588",
    "1HGCM82633A004352"
  ]
}' |
apify call aiqlabs/vin-decoder-recall-audit --silent --output-dataset

```

## MCP server setup

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

```

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/rNkr0dSwuMvi5j79Z/builds/EpUrlPlD8vrdcNKt2/openapi.json
