VIN decoding
GET /api/v1/vin/{vin} — full or partial VIN to year, make, model, trim and a catalog vehicle id. Free.
A VIN is the one identifier every real car carries. GET /api/v1/vin/{vin} decodes it with NHTSA's vPIC database, loaded into our own Postgres and refreshed monthly (NHTSA's API is the fallback when a pattern is missing), and names the catalog vehicle it maps to, so the next call is the picture or the 3D model. It costs nothing and needs a key with images:read.
Decode a VIN
/api/v1/vin/{vin}| Parameter | Type | Description |
|---|---|---|
vinrequired | path · 5–17 characters | A full 17-character VIN, or a partial one with * for each unknown position (at least 5 characters). Letters A–Z except I, O and Q, digits 0–9; case, spaces and hyphens do not matter. |
year | integer | The model year, when you know it. The tenth character of a VIN encodes the year in a 30-year cycle, so a hint tells a 1994 from a 2024 and helps a partial VIN decode; it is also what the catalog match uses when the VIN does not say. |
curl --fail-with-body \
-H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
"https://carimage.dev/api/v1/vin/1HGCM82633A004352"{
"data": {
"vin": "1HGCM82633A004352",
"valid": true,
"errors": [],
"suggested_vin": null,
"year": 2003,
"make": "Honda",
"model": "Accord",
"trim": "EX-V6",
"series": null,
"body_class": "Coupe",
"vehicle_type": "Passenger Car",
"doors": 2,
"drive_type": null,
"fuel_type": "Gasoline",
"engine": {
"cylinders": 6,
"displacement_l": 3,
"hp": 240,
"model": null
},
"transmission": {
"style": null,
"speeds": null
},
"manufacturer": "Honda of America Mfg., Inc.",
"plant": {
"city": "Marysville",
"state": "Ohio",
"country": "United States (USA)"
},
"gvwr": "Class 1: 6,000 lb or less (2,722 kg or less)",
"attributes": {
"Make": "HONDA",
"Model": "Accord",
"Model Year": "2003",
"Trim": "EX-V6",
"Body Class": "Coupe",
"Doors": "2",
"Engine Number of Cylinders": "6",
"Displacement (L)": "3.0",
"Engine Brake (hp) From": "240",
"Fuel Type - Primary": "Gasoline",
"Plant City": "MARYSVILLE",
"Plant State": "OHIO",
"Plant Country": "UNITED STATES (USA)",
"Manufacturer Name": "HONDA OF AMERICA MFG., INC.",
"Vehicle Type": "PASSENGER CAR"
},
"vehicle": {
"id": "veh_3qfyk22gfhsx3",
"make": "honda",
"model": "accord",
"year": 2003,
"image_path": "/api/v1/images/car?vehicle=veh_3qfyk22gfhsx3"
},
"source": "vpic-db"
},
"request_id": "req_01j9x…"
}The named fields are the ones most integrations want, normalized for display (title case, numbers as numbers, null when vPIC has nothing). attributes carries every vPIC variable that has a value, keyed by its vPIC name and left as vPIC spells it; the example above is trimmed. source is vpic-db when our copy answered and vpic-api when NHTSA did.
valid, errors and suggested_vin
valid is true when vPIC decoded the VIN without a complaint. Otherwise errors lists vPIC's findings as {code, text} and the decode still goes ahead with what it could read: a VIN whose ninth character does not check out is still a 2003 Accord.
{
"data": {
"vin": "1HGCM82633A004353",
"valid": false,
"errors": [
{
"code": 1,
"text": "Check Digit (9th position) does not calculate properly"
}
],
"suggested_vin": null,
"year": 2003,
"make": "Honda",
"model": "Accord",
"vehicle": {
"id": "veh_3qfyk22gfhsx3",
"make": "honda",
"model": "accord",
"year": 2003,
"image_path": "/api/v1/images/car?vehicle=veh_3qfyk22gfhsx3"
},
"…": "the other fields as above"
},
"request_id": "req_01j9x…"
}suggested_vin is vPIC's corrected spelling when it can tell which character is wrong, with ! marking the position; use it to prompt the person typing. A VIN that decodes to no make and no model at all is a 404.
Partial VINs
The first eleven characters identify the manufacturer, model, body, engine and year; the serial number after them does not change what the car is. So a partial VIN with * in the unknown positions decodes the same way, which is what you want when a form has only the first characters, a photo cut the plate off, or a listing hides the serial:
# the first 11 characters, serial unknown
curl -H "Authorization: Bearer $CAR_IMAGE_API_KEY" "https://carimage.dev/api/v1/vin/1HGCM82633A*"
# wildcards inside, plus a year hint
curl -H "Authorization: Bearer $CAR_IMAGE_API_KEY" "https://carimage.dev/api/v1/vin/1HGCM8*6*3A?year=2003"Fewer known characters mean fewer decoded fields: the check digit and the serial are skipped rather than guessed, and vehicle is null when the make, model and year cannot all be settled.
From a VIN to an image or a model
vehicle is the catalog entry the VIN maps to, with its stable vehicle id and a ready-made image_path. Pass the id as vehicle= to any image endpoint or as "vehicle" to POST /api/v1/3d; no make, model or year spelling to get right. It is null when the decoded make and model are not in the catalog (a trailer, some commercial chassis), in which case the decoded fields are still yours to display.
# the picture (1 credit)
curl --fail-with-body -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
"https://carimage.dev/api/v1/images/car?vehicle=veh_3qfyk22gfhsx3&view=front-3-4&color=1a2b3c" --output accord.png
# the 3D model (1,000 credits)
curl --fail-with-body \
-X POST https://carimage.dev/api/v1/3d \
-H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3d-honda-accord-2003-red" \
-d '{"vehicle":"veh_3qfyk22gfhsx3","color":"red"}'trim and body_class next to the image rather than claiming the render depicts them.CLI, SDK and MCP
- CLI:
car-image vin 1HGCM82633A004352 [--year 2003] [--json]prints the decoded fields and the ready-to-run image command. - SDK:
client.decodeVin("1HGCM82633A004352", { year? })returns the samedata. - MCP: the
decode_vintool (core toolset, free); see MCP & agents.
Errors
400— not a VIN: fewer than 5 or more than 17 characters, an I, O or Q, a character outside A–Z and 0–9 (other than*), or ayearthat is not four digits.401/403— missing key, or a key withoutimages:read.404— VIN not recognized: vPIC has no record of the pattern. Check the characters or send the full VIN.502— neither the vPIC copy nor NHTSA's API answered. Retry later.
Every failure is application/problem+json. See Errors.