Seventeen characters, and the whole regulatory file on the car
The Vehicle Data API decodes VINs and returns vehicle specs as clean JSON.
18 active endpoints, on 0, 1 and 2 credit tiers.
- POST/vehicle/v1/vin_decode
- POST/vehicle/v1/vin_decode_batch
- POST/vehicle/v1/vin_decode_flat
- POST/vehicle/v1/fuel_economy
- POST/vehicle/v1/fuel_economy_options
- POST/vehicle/v1/fuel_prices
- POST/vehicle/v1/canadian_specs
- +11 more
What Vehicle Data endpoints does ReefAPI ship?
18 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Vehicle Data API
3 of 18 endpoints, ready to run
Make, model, year, trim, body class, doors and manufacturer, plus the engine, transmission, weight and assembly plant blocks.
{ "ok": true, "meta": { "api": "vehicle", "endpoint": "vin_decode", "mode": "live", "latency_ms": 1009.2, "record_count": 1, "cache_hit": false, "completeness_pct": 83.33 }, "data": { "vin": "1HGCM82633A004352", "vehicle": { "make": "HONDA", "model": "Accord", "modelYear": "2003", "trim": "EX-V6", "bodyClass": "Coupe", "vehicleType": "PASSENGER CAR", "doors": "2", "manufacturer": "AMERICAN HONDA MOTOR CO., INC.", "engine": { "cylinders": "6", "displacementL": "2.998832712", "displacementCc": "2998.832712", "displacementCi": "183", "horsepower": "240", "model": "J30A4", "configuration": "V-Shaped", "fuelPrimary": "Gasoline", "valveTrain": "Single Overhead Cam (SOHC)" }, "transmission": { "style": "Automatic", "speeds": "5" }, "weight": { "gvwr": "Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg)", "gvwrTo": "Class 1: 6,000 lb or less (2,722 kg or less)" }, "plant": { "city": "MARYSVILLE", "state": "OHIO", "country": "UNITED STATES (USA)" }, "ids": { "makeId": "474", "modelId": "1861", "manufacturerId": "988" } }, "decode": { "errorCode": "0", "errorText": "0 - VIN decoded clean. Check Digit (9th position) is correct", "vehicleDescriptor": "1HGCM826*3A" } } }
How the Vehicle Data API works
Vehicle Data is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 184 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Building a listing page from nothing but the VIN
A used-car listing starts with seventeen characters. Everything a buyer wants to know next is published by the regulator and keyed on what those characters decode to.
{"vin": "1HGCM82633A004352"}Returns make, model, year and trim along with engine displacement, cylinders, horsepower, body class and the assembly plant.
{"make": "Honda", "model": "Accord", "modelYear": 2012}Then the same make, model and year into recalls, safety_ratings and complaints — three calls that turn a decode into a history.
Owner complaints came back in the hundreds for a single model year, each with the component, the date and whether a crash, fire or injury was involved. That is the pattern data no listing carries and no seller volunteers.
curl -X POST https://api.reefapi.com/vehicle/v1/vin_decode \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"vin":"1HGCM82633A004352"}'{
"ok": true,
"data": { … },
"meta": {
"api": "vehicle",
"endpoint": "vin_decode",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}Types and units that are not what they look like
This API joins two US federal datasets with different conventions, and the seams show. Every value below is from a measured response — a VIN decode of 1HGCM82633A004352 and an EPA lookup on a 2021 Honda Accord. Read this before you write a schema.
| Field | Measured value | What it actually is |
|---|---|---|
| vehicle.* on a VIN decode | "2003", "6", "240", "2" | strings, all of them — model year, cylinder count, horsepower and door count included. The upstream vPIC catalog is untyped; casting is your job. |
| engine.displacementL | "2.998832712" | unrounded litres. Display it as 3.0 L yourself; do not match on the raw string. |
| weight.gvwr | "Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg)" | a GVWR class label carrying a range, not a weight. There is no single number to parse out. |
| decode.errorCode | "0" | "0" means the VIN decoded clean and the 9th-position check digit is correct; anything else is explained in errorText. |
| decode.vehicleDescriptor | "1HGCM826*3A" | the VIN with the serial positions masked. Safe to log or store when you do not want to keep a full VIN. |
| mpg.city / highway / combined | 30 / 38 / 33 | integers, US miles per gallon. EV and hybrid rows report MPGe on the same keys. |
| co2GramsPerMile | 268.0 | grams of CO2 per mile, float |
| annualFuelCostUsd | 1850 | US dollars per year, integer, on EPA's own driving assumptions |
| fuelEconomyScore / ghgScore | 7 and 7.0 | EPA's 1–10 scales; note one comes back int and the other float |
| fuel_prices.regular | "4.1" | a quoted decimal string, USD per US gallon |
| fuel_prices.electric | "0.15" | USD per kWh — the one entry in that object that is not per gallon |
The two halves of this API type their numbers differently: a VIN decode returns everything as strings, while an EPA fuel-economy row returns real ints and floats. Same request, two conventions, because they are two different government datasets. Normalize at your boundary rather than trusting the shape.
What the regulator publishes, and how to read the joins
Measured on a VIN decode and on the three model-year feeds for the same car. Two of these rows are about not over-reading the data.
A 2003 Accord decoded to its trim, body class, door count, engine model, cylinder count, displacement in three units, horsepower, transmission, weight class and assembly plant. The VIN encodes this; it is not a guess or a lookup against a listings site.
Asking for a 2012 Accord returned campaigns whose summaries describe other model years and other models, because a recall campaign covers whichever vehicles share the defective part — the regulator files it against a component, not a year. The rows are correct; what would be wrong is reading every returned campaign as applying to your exact car. Check the campaign summary, or decode the VIN and match on the component.
One model year returned two rated variants, each with its overall rating and the frontal, side and rollover breakdowns — and with links to the regulator's own crash photographs and test video. Being able to show the source image is what makes a rating persuasive on a listing rather than a number a buyer has to take on trust.
A single model year returned several hundred owner complaints, each with the component, the incident date, the filing date and flags for crash, fire, injuries and deaths. One complaint is an anecdote; the count against a component across a year is the pattern a buyer or a dealer actually needs.
The regulator publishes complaint records with the VIN truncated, so you cannot join a complaint to one specific car. That is a deliberate privacy measure at source, not something we strip. Complaints are usable as a model-year pattern and not as a per-vehicle history.
What people build with Vehicle Data
The jobs this data is most often used for.
endpoints
credits per call
Marketplaces call vin_decode to auto-fill a vehicle listing from a VIN.
Insurance tools use vin_decode for underwriting and quoting.
Apps use fuel_economy and fuel_prices to estimate running costs.
What Vehicle Data data costs
The cheapest call here is 0 credits, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 184 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/vehicle/v1/vin_decode \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"vin":"1HGCM82633A004352"}'import requests
r = requests.post(
"https://api.reefapi.com/vehicle/v1/vin_decode",
headers={"x-api-key": REEF_KEY},
json={
"vin": "1HGCM82633A004352"
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Vehicle Data.
Get a free key →Why does the VIN decoder return numbers as strings?▾
Because the NHTSA vPIC catalog behind it is a flat attribute table with no type information — every cell is text. A measured decode of 1HGCM82633A004352 returned modelYear "2003", cylinders "6", horsepower "240" and doors "2", all quoted. We pass them through rather than guessing at conversions, since a bad cast on an ambiguous field is worse than an honest string. Cast at your own boundary and expect empty strings where the catalog has no value.
Can I decode a partial VIN?▾
Yes — use * for the positions you do not know, and pass modelyear to disambiguate. A VIN is 1–17 characters of A–Z and 0–9 with I, O and Q excluded from the alphabet entirely (they look too much like 1 and 0), so a VIN containing any of those three is malformed rather than unknown. The response's decode.errorText tells you exactly what was and was not resolvable, and decode.suggestedVin appears when NHTSA can propose a correction.
How do I confirm a VIN decoded correctly rather than partially?▾
Read decode.errorCode, not the presence of fields. A measured clean decode returned errorCode "0" with errorText "0 - VIN decoded clean. Check Digit (9th position) is correct" — that is the 9th character validating the other sixteen arithmetically, which catches transcription errors before you store them. meta.completeness_pct on the same call was 83.3, meaning some catalog fields were empty for that vehicle; that is normal for older cars and is not a decode failure.
What is vehicleDescriptor and why would I store it instead of the VIN?▾
It is the VIN with the individual serial masked out — measured: 1HGCM826*3A for 1HGCM82633A004352. It still identifies the make, model, body and engine family, but not the specific car. If you are caching decode results, keying on the descriptor gives you a cache hit across every vehicle of that configuration and keeps a personally-identifying VIN out of your logs.
How do I get fuel economy for a specific trim?▾
Call fuel_economy_options with year, make and model to list the EPA trims and their ids, then call fuel_economy with the id you want. Passing year, make and model straight to fuel_economy auto-resolves and returns one row per trim in vehicles[] — a measured 2021 Honda Accord lookup returned count 1 with id 43361, trim "Automatic (variable gear ratios)", vehicleClass "Large Cars", 30/38/33 MPG and annualFuelCostUsd 1850. EPA coverage starts at 1984.
What unit is the electric price in fuel_prices?▾
USD per kilowatt-hour, while every other key in that object is USD per US gallon. A measured call returned regular 4.1, midgrade 4.68, premium 5.07, diesel 5.31, e85 2.63, cng 2.96, lpg 3.42 and electric 0.15 — and that last figure is only coherent as a per-kWh rate. All eight arrive as quoted strings. These are US national averages at the time you call, not regional prices, so do not use them for a local cost estimate.
How do I decode a lot of VINs at once?▾
vin_decode_batch takes up to 50 per call and is flexible about the input shape: a 'VIN,year;VIN,year' string, an array of bare VIN strings, an array of [VIN, year] pairs, or an array of {vin, modelyear} objects. Each result carries its own vin, vehicle and decode block, so a VIN that fails to decode does not affect the other 49 — check each row's decode.errorCode individually.
What is vin_decode_flat for, and what does raw add?▾
vin_decode_flat returns one row per NHTSA variable — variable name, its label, the value, plus variableId and valueId — instead of the tidied nested vehicle object. Use it when you want a field the curated shape does not surface, or when you need NHTSA's own numeric ids to join against another government dataset. raw: true on vin_decode is the middle ground: you keep the nested object and additionally get the full flat attribute row (around 130 fields) under attributes.
What is the Vehicle Data API?▾
Vehicle Data API is a ReefAPI endpoint group for vehicle data It returns live JSON through POST requests under /vehicle/v1.
Is the Vehicle Data API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Vehicle Data calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Vehicle Data login or account?▾
No login to Vehicle Data is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Vehicle Data data?▾
The page example is captured from a live vin_decode call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Vehicle Data API use?▾
Vehicle Data actions currently cost 1-2 credits per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Vehicle Data from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call vehicle actions with the same key, credit pool and JSON envelope used by normal REST requests.
19 Utilities & AI APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Vehicle Data, you are one call away from the rest of the category — no second contract, no second integration.
Need something this API does not do?
Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 183 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-30.