Car Image API
Documentation

VIN to car image

Decode a VIN free, check the catalog match, then get a car image for 1 credit.

To get a car image from a VIN, decode it with GET /api/v1/vin/{vin}, check that data.vehicle is present, then request an image with that vehicle id. Decoding is free; the image is one vehicle image of your plan's month. Both calls need an API key with images:read. The result is a catalog render of the make, model and year, rather than a photograph of the individual vehicle or a guarantee of its trim.

Decode a VIN

GET/api/v1/vin/{vin}
images:readfree
GET /api/v1/vin/{vin} parameters
ParameterTypeDescription
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.
bash
curl --fail-with-body \
  -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/vin/1HGCM82633A004352"
200 OK
{
  "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.

A VIN with a bad check digit
{
  "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:

bash
# 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

Node.js: decode, check, then save the image
import { writeFile } from "node:fs/promises";
import { CarImageClient } from "@meterapp/car-image-sdk";

const client = new CarImageClient({ apiKey: process.env.CAR_IMAGE_API_KEY });
const { data } = await client.decodeVin(process.env.VIN); // free
if (!data.valid) {
  throw new Error("Ask the person to check the VIN before continuing.");
}
if (!data.vehicle) {
  throw new Error("No catalog match. Ask for make, model and year, then search vehicles.");
}
const image = await client.getImage({
  vehicle: data.vehicle.id, view: "front-3-4", format: "png",
}); // one vehicle image of the month
await writeFile("vehicle.png", image.bytes);

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.

bash
# the picture (one vehicle image of the month)
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 (100 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"}'

Before requesting the image, check GET /api/v1/images/availabilitywith the decoded vehicle id, your view and your color. This free authenticated call reports whether that view is cached, its quality and an estimated wait if it needs rendering. It does not create, count or charge anything. See image availability and quality.

Optional: check readiness without rendering
curl --fail-with-body -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/images/availability?vehicle=veh_3qfyk22gfhsx3&view=front-3-4&color=1a2b3c"

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 same data; client.isImageReady({ vehicle: data.vehicle.id }) then says, free, whether its image can be shown now.
  • MCP: the decode_vin tool (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 a year that is not four digits.
  • 401 / 403 — missing key, or a key without images:read.
  • 404 — VIN not recognized: vPIC has no record of the pattern. Check the characters, above all the first three (the maker code), or send the full VIN, or a partial one with * for each unknown position and a year. vPIC covers vehicles made for the US market, so a correctly typed VIN from another market can be a 404 too: find that car by make and model instead.
  • 502 — neither the vPIC copy nor NHTSA's API answered. Retry later.

Every failure is application/problem+json. See Errors.