How to Use the VIN Decoder API

By Vehicle API
How to Use the VIN Decoder API

You have a VIN and need reliable year, make, model, trim, engine and plant data you can ship into dealer tools, marketplaces, fleet or insurance workflows. By the end of this guide you’ll sign up for the 7‑day trial, grab your API key, send a VIN decode request, parse the official JSON envelope, and handle coverage, nulls, errors, rate limits and caching in production.

What you will build and what this API returns

This guide focuses on a single endpoint: POST https://vehicles-api.com/api/v1/vin/decode. It decodes any 17‑character VIN worldwide and returns a normalized JSON envelope with status, source and data. The data includes year, make, model, trim, body, doors, vehicle_type, engine details, transmission, plant and manufacturer. Fields not published by NHTSA are null. VIN decoding is global, but coverage is fullest for US‑market vehicles.

Illustration: How to Use the VIN Decoder API

Safety data like recalls, owner complaints and NCAP crash ratings are US‑market only and matched by make + model + year, not by VIN. Dutch plates are available separately from RDW open data and never include a VIN. This API is not a vehicle history report and does not include title, accident or ownership history.

You can call the HTTP API or connect to the same capabilities via the MCP server for agentic workflows.

Start your 7‑day trial and get your API key

  • Create your account: Register (Starter is $19/mo; every plan includes a 7‑day free trial).
  • Open the dashboard, copy your API key. You’ll use it in the X-API-Key header. Authorization: Bearer YOUR_API_KEY also works if your client prefers a standard Authorization header.
  • Base URL for HTTP is https://vehicles-api.com/api/v1. MCP is at https://vehicles-api.com/mcp.

Send your first VIN decode request

Below are the official samples you can copy and run. They target the VIN decoder endpoint and use the header X-API-Key: YOUR_API_KEY. The control VIN 1HGCM82633A004352 is a 2003 Honda Accord and is provided for documentation and testing; it is not your vehicle. Do not substitute a different VIN until you’ve proven your integration.

curl

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"}'

Python

import json
import os
import requests

API_KEY = os.getenv("VEHICLES_API_KEY", "YOUR_API_KEY")
BASE_URL = "https://vehicles-api.com/api/v1"

def decode_vin(vin: str) -> dict:
url = f"{BASE_URL}/vin/decode"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
}
resp = requests.post(url, headers=headers, json={"vin": vin}, timeout=15)
# Every response is an envelope with status and either data or error
payload = resp.json()
if payload.get("status") != "success":
err = payload.get("error", {})
raise RuntimeError(f"VIN decode failed: {err.get('code')}: {err.get('message')}")
return payload

if __name__ == "__main__":
vin = "1HGCM82633A004352"
envelope = decode_vin(vin)
data = envelope["data"]

# Safe extraction with null-aware defaults
year = data.get("year")
make = data.get("make")
model = data.get("model")
trim = data.get("trim")
engine = data.get("engine") or {}
transmission = data.get("transmission") or {}
plant = data.get("plant") or {}

summary = {
"vin": data.get("vin"),
"valid": data.get("valid"),
"year": year,
"make": make,
"model": model,
"trim": trim,
"engine_cyl": engine.get("cylinders"),
"engine_disp_l": engine.get("displacement_l"),
"engine_config": engine.get("configuration"),
"engine_hp": engine.get("hp"),
"fuel_type": data.get("fuel_type"),
"transmission_style": transmission.get("style"),
"transmission_speeds": transmission.get("speeds"),
"plant_country": plant.get("country"),
"manufacturer": data.get("manufacturer"),
}

print(json.dumps(summary, indent=2))

Read the official JSON response

This is the official JSON envelope and data for the control VIN. Fields that the upstream source does not publish are null. Electrification fields are null here because the control VIN is a gasoline vehicle; do not invent EV values.

{
"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

  • Envelope: status indicates success or error. source identifies the upstream dataset (nhtsa for VIN decoding). data holds the decoded vehicle fields.
  • Identity: vin (string), valid (boolean).
  • Core spec: year (number), make (string), model (string), trim (string), body (string), doors (number), vehicle_type (string).
  • Engine: engine.cylinders (number), engine.displacement_l (number, liters), engine.configuration (string), engine.model (string), engine.hp (number), engine.fuel (string). fuel_type mirrors the energy source.
  • Transmission: transmission.style (string), transmission.speeds (number).
  • Driveline and EV: drive and all electrification fields may be null when not published.
  • Plant and OEM: plant.country, plant.city, plant.state; manufacturer.

Production notes: coverage, caching, nulls and safety data

  • Coverage: VIN decoding accepts any 17‑character VIN worldwide. Data depth is fullest for US‑market vehicles. When a field is not published by NHTSA, it returns null. Build your UI and database to accept nulls without failing.
  • Caching: VIN decoding is deterministic for a given VIN. Cache successful decodes keyed by VIN in your database or an edge cache with a long TTL to reduce latency and quota usage. Invalidate only if you detect an upstream change or refresh on a schedule appropriate to your product.
  • US safety programs: Recalls, owner complaints, and NCAP crash ratings are US‑market only and matched by make + model + year. They are not returned by the VIN decoder endpoint and are not VIN‑specific.
  • Dutch plates: RDW open data is available for NL plates and never provides a VIN. Do not attempt to derive a VIN from a Dutch plate.

Error handling, rate limits and quotas

Every response is an envelope. On success, you receive status = success, a source and a data object. On errors, you receive status = error with an error object that includes error.code and error.message. Use error.code for programmatic branching and error.message for operator logs or UI messages. Your HTTP client should still check the HTTP status code; handle non‑2xx as errors.

  • Invalid VINs: Expect status = error with an error object. Do not retry unchanged input.
  • Auth failures: Ensure X-API-Key is present and correct. Authorization: Bearer also works, but do not send both at once.
  • Rate limits: The API enforces rate limits and monthly quotas per plan. If you hit a limit, pause or backoff before retrying. Review the dashboard for your current usage and limits.
  • Retries: Only retry idempotently on transient server/network failures. Do not retry client errors (bad VIN, missing header).

To integrate efficiently at scale, batch your decodes during ingestion, cache results by VIN, and avoid repeated calls for the same VIN within your own workflows. If you anticipate sustained high concurrency, contact support via the Documentation page for guidance.

Field-by-field quick reference

The table below lists the primary fields you’ll map into inventory, quoting and policy systems. Types are inferred from the official example. Any field may be null when not provided by the source.

Field Type Notes
statusstringEnvelope: "success" or "error".
sourcestringUpstream dataset, e.g., "nhtsa".
data.vinstringThe 17‑character VIN you sent.
data.validbooleanChecksum and format validity.
data.yearnumberModel year.
data.makestringOEM brand, uppercased.
data.modelstringModel line.
data.trimstringTrim level.
data.bodystringBody style (e.g., Coupe, Sedan).
data.doorsnumberNumber of doors.
data.vehicle_typestringClassification, e.g., PASSENGER CAR.
data.engine.cylindersnumberCount of cylinders.
data.engine.displacement_lnumberEngine displacement (liters).
data.engine.configurationstringe.g., V-Shaped.
data.engine.modelstringEngine family or code.
data.engine.hpnumberHorsepower.
data.engine.fuelstringPrimary fuel.
data.fuel_typestringFuel type summary.
data.electrification_levelnull|stringEV/Hybrid info when available; null here.
data.ev_drive_unitnull|stringEV drive unit; null here.
data.battery_kwhnull|numberBattery capacity; null for gasoline.
data.charger_levelnull|stringCharging level; null for gasoline.
data.charger_power_kwnull|numberCharger power; null for gasoline.
data.drivenull|stringDriveline (e.g., FWD/AWD) when available.
data.transmission.stylestringe.g., Automatic.
data.transmission.speedsnumberNumber of forward gears.
data.plant.countrystringAssembly country.
data.plant.citystringAssembly city.
data.plant.statestringAssembly state or region.
data.manufacturerstringWMI holder / manufacturer name.
error.codestringPresent only when status = error.
error.messagestringHuman‑readable diagnostic.

Step-by-step: from trial to production

1) Create your account and key

Sign up for the 7‑day trial on the Register page. Copy your API key from the dashboard. Keep it out of client‑side code and public repos.

2) Verify your first decode

Run the curl sample as‑is. Confirm you receive status = success, source = nhtsa and the data object for the control VIN. If your client requires Authorization: Bearer, switch headers accordingly but do not send both headers.

3) Map the fields you need

  • Inventory and listings: year, make, model, trim, body, doors, vehicle_type.
  • Quoting or underwriting: engine.cylinders, engine.displacement_l, engine.hp, fuel_type, transmission.style, transmission.speeds, drive (when available).
  • Manufacturing: plant.country, plant.city, plant.state, manufacturer.

4) Handle nulls and absence gracefully

Some OEMs or model years may not expose drive or certain EV fields through NHTSA. Keep these nullable in your schema. Do not derive values that are not present in the payload.

5) Cache aggressively

VIN decodes do not change frequently. Cache results keyed by VIN and reuse across your systems (dealer feeds, internal UIs, pricing engines). This reduces latency, improves resilience during rate limiting, and saves quota.

6) Instrument and alert

  • Log envelope.status and envelope.source. On errors, capture error.code and error.message with request IDs in your observability stack.
  • Surface null fields in metrics so you can spot OEMs or trims with sparse data and adjust your UX.
  • Track 4xx vs 5xx rates separately. Only backoff and retry on transient failures.

7) Extend to agents and tools via MCP

If you are building AI agents or CLI tools, connect them to the MCP server endpoint at https://vehicles-api.com/mcp to access the same decoding capabilities without reinventing HTTP plumbing.

Testing tips and sample assertions

  • Validate the envelope: assert status == "success" and source == "nhtsa" for decodes.
  • Confirm identity consistency: data.vin should echo your submitted VIN; data.valid should be true for syntactically correct 17‑character VINs.
  • Check canonicalization: make is uppercased (e.g., "HONDA") while model and trim preserve case as published.
  • Units: engine.displacement_l is liters, engine.hp is horsepower (as published by source), charger_power_kw is kilowatts when present.
  • EV fields: for gasoline vehicles, electrification_level, ev_drive_unit, battery_kwh, charger_level, charger_power_kw will be null. Do not coerce nulls to zeros.

Security and compliance notes

  • Store your key server‑side. For browser apps, proxy requests through your backend to attach X-API-Key.
  • Limit logs: Do not write API keys to logs. Redact VINs if your compliance policy requires it.
  • Time bounds: When archiving payloads, keep original envelopes and timestamps so you can reprocess if mappings improve.

Frequently asked questions

Does the VIN decoder cover vehicles outside the US?
Yes. The decoder accepts any 17‑character VIN worldwide. Data is most complete for US‑market vehicles because the source is NHTSA vPIC. Fields not available for a region or OEM will be null.

Is this a vehicle history report?
No. VIN decoding returns specifications like year, make, model, trim, engine, transmission and plant. It does not include title, accident or ownership history.

Do Dutch plates include a VIN?
No. Dutch plate data comes from RDW open data and never includes a VIN. Treat Dutch plates and VIN decoding as separate workflows.

How are recalls, complaints and NCAP ratings matched?
They are US‑market only and matched by make + model + year. They are not VIN‑specific and are not returned by the VIN decoder endpoint.

What happens when I hit my rate limit or monthly quota?
The API will return an error envelope (status = error with error.code and error.message). Implement backoff for transient limits, cache decodes to reduce calls, and monitor your usage in the dashboard.

Ready to ship VIN decoding into your app? Start your 7‑day free trial and get your key on the Register page, then keep building with the Documentation and the MCP server for agents.