
You need a fast, reliable way to turn a 17-character VIN into the canonical year, make and model you can store, search and display. By the end of this guide, you’ll be able to call the Vehicle API VIN decode endpoint, extract year/make/model, handle null fields and errors, cache results, and understand coverage and quotas for production use.
What this endpoint delivers and when to use it
The VIN Year Make Model API is the VIN decoding capability of Vehicle API. It accepts any 17-character VIN and returns a structured payload sourced from NHTSA vPIC with the core identifiers—year, make and model—plus trim, body, engine, transmission, assembly plant and more.
- VIN decoding coverage: worldwide; richest detail for US-market vehicles.
- Safety datasets (recalls, owner complaints, NCAP crash ratings): US-market only and matched by make + model + year, not by VIN. These are related features you may call separately; they are not a vehicle history report.
- Dutch plates (RDW open data): available via a separate flow; Dutch plate lookup never includes a VIN.
Use the VIN decode when you need canonical year/make/model keys to drive search facets, price models, inventory ingestion, insurance garaging logic, and agent prompts. Store the decoded values and reuse them—VINs are immutable.
Endpoint and authentication
Base URL: https://vehicles-api.com/api/v1
Endpoint: POST /vin/decode
Authentication:
- X-API-Key: YOUR_API_KEY (preferred)
- Authorization: Bearer YOUR_API_KEY (also supported)
Every response uses a consistent envelope. On success you’ll receive status, source and data. On error you’ll receive status set to error with error.code and error.message.
Explore the full reference and plan details in the Documentation. You can also connect via the Model Context Protocol server at MCP if you’re building AI agents.
Official cURL example
Copy and run this request to decode the control VIN. It demonstrates the exact request structure and headers.
curl -X POST "https://vehicles-api.com/api/v1/vin/decode" -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"vin":"1HGCM82633A004352"}'
Official JSON response envelope
This is the canonical response example. Notice the envelope with status and source, and the data object with year, make and model available at top level.
{
"status": "success",
"source": "nhtsa",
"data": {
"vin": "1HGCM82633A004352",
"valid": true,
"year": 2003,
"make": "HONDA",
"model": "Accord",
"trim": "EX-V6",
"body": "Coupe",
"doors": 2,
"vehicle_type": "PASSENGER CAR",
"engine": {
"cylinders": 6,
"displacement_l": 3,
"configuration": "V-Shaped",
"model": "J30A4",
"hp": 240,
"fuel": "Gasoline"
},
"fuel_type": "Gasoline",
"electrification_level": null,
"ev_drive_unit": null,
"battery_kwh": null,
"charger_level": null,
"charger_power_kw": null,
"drive": null,
"transmission": {
"style": "Automatic",
"speeds": 5
},
"plant": {
"country": "UNITED STATES (USA)",
"city": "MARYSVILLE",
"state": "OHIO"
},
"manufacturer": "AMERICAN HONDA MOTOR CO., INC."
}
}
Fields you will actually use for Year/Make/Model
- data.year: Integer model year. Use as your primary year key and for safety dataset joins.
- data.make: Uppercased canonical OEM name.
- data.model: Canonical model string.
Additional helpful identifiers for downstream features:
- data.trim: Useful for listing detail pages and equipment inference when available; may be null on some markets/years.
- data.engine.cylinders, data.engine.displacement_l, data.engine.hp, data.fuel_type: Good for pricing, insurance rating and emissions disclosures; may be null if the source does not publish.
- data.transmission.style and data.transmission.speeds: May be null on some records.
- data.plant.country/city/state and data.manufacturer: Provenance and QA.
- Electrification fields (electrification_level, battery_kwh, charger_level, charger_power_kw, ev_drive_unit): Null if the source does not publish or the vehicle is not electrified. Do not infer values; treat null as unknown.
Minimal client example in JavaScript
This Node.js fetch example posts a VIN and extracts the year, make and model fields from the response envelope. Replace YOUR_API_KEY with your key, reuse the VIN shown below to validate your wiring, then swap in your user-provided VINs.
import fetch from "node-fetch";
const API_BASE = "https://vehicles-api.com/api/v1";
const API_KEY = "YOUR_API_KEY";
async function decodeVin(vin) {
const res = await fetch(`${API_BASE}/vin/decode`, {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({ vin })
});
// Network/HTTP error handling
if (!res.ok) {
const text = await res.text();
throw new Error(`HTTP ${res.status}: ${text}`);
}
const payload = await res.json();
// Envelope handling: success vs error
if (payload.status !== "success") {
const code = payload.error?.code ?? "unknown_error";
const msg = payload.error?.message ?? "Unknown error";
throw new Error(`${code}: ${msg}`);
}
const { year, make, model, trim } = payload.data;
// Normalize and guard for nulls
return {
year: year ?? null,
make: make ?? null,
model: model ?? null,
trim: trim ?? null
};
}
// Example call with the control VIN
decodeVin("1HGCM82633A004352")
.then(({ year, make, model, trim }) => {
console.log(`YMM: ${year} ${make} ${model}${trim ? " " + trim : ""}`);
})
.catch(err => {
console.error("Decode failed:", err.message);
});
Response envelope, errors, and null handling
The API always returns a top-level status. On success you’ll see status set to success with a source field (nhtsa in the example) and a data object. On error you’ll see status set to error with an error.code and error.message. Handle both cases explicitly.
- Null fields: If NHTSA does not publish a given attribute for a VIN or market, the field will be null. This is expected for certain trims, drive types, or for non-electrified vehicles. Never coerce null into a default value; downstream logic should branch on null.
- Validation: data.valid indicates the VIN checksum/format outcome where available.
- Type safety: year is an integer, doors is an integer, engine.speeds is an integer, and some strings are uppercased (e.g., make). Do not rely on casing for joins; prefer exact string matches as returned.
Coverage and what to expect in production
VIN decoding works worldwide. The dataset is fullest for US-market vehicles, which means you will typically get complete year/make/model and common specs on US VINs and occasionally more nulls on other markets for fields NHTSA does not publish.
Safety data scope: Recalls, owner complaints, and NCAP crash ratings are US-market only and matched by make + model + year, not by VIN. When you join these datasets to a decoded VIN, use the fields year, make and model directly from the decode response.
Dutch plates: RDW open data is supported as a separate lookup flow. Dutch plates never include a VIN, so do not expect a VIN in those responses or attempt to reverse from plate to VIN.
This is not a vehicle history report. No title records, accident history, or ownership changes are provided.
Practical implementation details
Caching decoded VINs
- VINs are immutable; cache the entire data object keyed by VIN indefinitely. A decode result for a given VIN will not change.
- Consider normalizing and indexing by a composite of year/make/model for fast joins to your internal catalogs.
- If you persist only a subset, store year, make, model, and a last_decoded_at timestamp for audit. The payload has no server timestamps; use your system clock when caching.
Rate limits and monthly quota
- Each account has a monthly quota and per-interval rate limits. If you exceed them, responses will follow the error envelope with status set to error and an error.code and error.message describing the limit condition.
- To avoid throttling, batch decodes during ingestion and rely on your VIN cache for repeated reads.
- When you receive a limit error, back off and retry after a short delay. For sustained throughput needs, check your plan limits in the Documentation.
Request shaping and validation
- Always send Content-Type: application/json.
- Validate VIN length (17 chars) client-side before sending; short or malformed VINs will return status error.
- Note the canonical casing: make is returned as HONDA and model as Accord in the example. Use the API output verbatim for joins to safety datasets.
Data consistency and joins
- Use data.year, data.make, and data.model from this endpoint as the keys to fetch US-market recalls, complaints, and NCAP ratings. These datasets match on make + model + year, not the VIN itself.
- When the API returns null for fields like drive or transmission.speeds, avoid inferring values from trim strings. Keep unknowns as null to prevent data leakage into analytics and pricing.
MCP: call the same decode logic from your agent tooling
If you’re building AI agents or copilots, the same VIN decoding capability is available as a Model Context Protocol server at MCP. This is useful when your agent runtime needs authoritative year/make/model without direct HTTP calls in prompt code. The semantics, coverage, and field names mirror the HTTP API, including nulls for unpublished attributes.
Quick field reference for YMM extraction
| Field | Type | Purpose | Notes on nulls |
|---|---|---|---|
| data.year | integer | Primary year key | Not expected to be null on valid VINs |
| data.make | string | Canonical OEM name | Uppercase in many cases; treat as authoritative |
| data.model | string | Canonical model name | Use verbatim for dataset joins |
| data.trim | string | Display, equipment inference | May be null depending on market/year |
| data.engine.* | object | Cylinders, displacement_l, hp, fuel | Any attribute may be null if not published |
| data.transmission.* | object | style, speeds | May be null |
| data.plant.* | object | Manufacturing country/city/state | May be null |
| data.electrification_* | various | EV/HEV/PHEV attributes | Often null for non-EVs and when not published |
Testing checklist
- Send the official cURL with X-API-Key: YOUR_API_KEY and confirm status: success.
- Parse the envelope and read data.year, data.make, data.model.
- Simulate errors by removing the authentication header; verify status: error and presence of error.code and error.message.
- Verify your cache: a second call for the same VIN should be served from your store.
- Join safety datasets by make + model + year only on US-market records.
Production hardening tips
- Idempotent ingestion: decode once per new VIN and store the entire data object.
- Guard rails for UI: if any of year/make/model are null (rare), withhold listing activation and request manual review.
- Logging: log status, source and a hash of the data object for debugging without storing PII.
- Backoff: on limit-related errors in the envelope, schedule retries and avoid hot loops.
- Transport: use HTTPS only; the base URL is https://vehicles-api.com/api/v1.
FAQ
Does the VIN decode cover vehicles outside the US?
Yes. VIN decoding accepts any 17-character VIN worldwide. Field completeness is typically highest for US-market vehicles; where the source does not publish, fields will be null.
Can I get recalls, complaints, or crash ratings by VIN?
These US datasets are matched by make + model + year, not by VIN. Decode the VIN first, then query safety data with the returned year, make and model.
Do Dutch license plate lookups return a VIN?
No. Dutch plates come from RDW open data and do not include a VIN. Treat the plate flow as separate from VIN decoding.
How are errors returned?
All responses use an envelope. On errors you’ll receive status set to error with error.code and error.message. Handle this case distinctly from HTTP transport errors.
What about rate limits and monthly quotas?
Each plan includes a monthly quota and rate limits. If you exceed them you’ll receive an error envelope describing the condition. Cache decodes per VIN to minimize repeat calls. See the Documentation for plan details.
Start decoding VINs and shipping year/make/model features in minutes. Every plan includes a 7-day free trial. Register at vehicles-api.com, plug in your API key, and deploy.
