Car Image API
Documentation

Images

GET /api/v1/images/car — parameters, views, sizes, any paint color, vehicle ids, headers, JSON mode.

GET/api/v1/images/car
images:read1 credit

Query parameters

GET /api/v1/images/car parameters
ParameterTypeDescription
makerequired
string
Manufacturer as it appears in the catalog. Case, spaces and punctuation are normalized ("Mercedes-Benz" and "mercedes benz" are the same make), and nicknames, other separators, company words and typos are read ("chevy", "landrover", "kia-motors", "porshe"): how names are matched. Omit when you send vehicle.
modelrequired
string
Model name, normalized the same way ("model-3", "Model 3") and read from the most literal rule to the least: a unique prefix, a family in any market's word ("gla"), another word order, a reviewed same-body name ("camry-hybrid"), engine and trim words ("x3-xdrive30d"), a badge ("c300") or a typo ("elentra"), with X-Vehicle-Match saying which: how names are matched. Body styles and performance derivatives never substitute. Omit when you send vehicle.
yearrequired
integer
Model year between 1990 and next year (2024.0 reads as 2024). Must exist for the make/model in the catalog. Omit when you send vehicle.
vehicle
string
A stable vehicle id such as veh_78qtwrgh37bkr in place of make, model and year. Every GET /api/v1/vehicles response and every VIN decode carries them. Sending an id together with make, model or year is a 400; an id that names no vehicle is a 404.
viewrequired
front | front-3-4 | side | rear-3-4 | rear | rear-3-4-right | side-right | front-3-4-right
One of eight views around the car, with aliases such as left, front-right, hero and back read in any case, and read as angle, camera, perspective or orientation: see Camera views.
color
preset | CSS name | hex
One of 15 preset names, any CSS color name or any paint as bare hex (color=1a2b3c), each the same 1 credit; also spelled colour and read as paint, paint_color, hex or colors: see Colors.Default: silver
size
thumb | small | medium | large
Named square preset (thumb=256, small=512, medium=768, large=1024). Ignored when w or h is given.
w
integer, up to 1024
Width in pixels, also spelled width: alone, the square source scales to w×w; with h the output is exactly w×h and fit places the car. Above 1024 it is clamped, not refused: see Sizes.
h
integer, up to 1024
Height in pixels, also spelled height. Alone, the output is h×h. Clamped above 1024 like w.
fit
contain | cover | inside
How the car is placed when both w and h are given: contain pads, cover crops, inside may return a smaller image — see Fit.Default: contain
background
transparent | CSS name | hex
Solid color the image is flattened onto: any CSS color name (white, black, whitesmoke, grey…), or hex as rrggbb, #rrggbb, rgb or #rgb; write the bare hex in URLs (background=f4f4f4) so nothing needs escaping — responses echo #f4f4f4. A solid background flattens PNG and WebP too. JPG defaults to #ffffff, and background=transparent with format=jpg is a 400. Also read as bg or background_color.Default: transparent (jpg: white)
framing
consistent | tight | balanced
A composition preset for trim and padding: tight is trim=1, balanced is trim=1&padding=6, consistent is neither. Never together with trim or padding — see Framing.Default: consistent
trim
0 | 1
Crop to the car's own bounds before sizing, so the car fills the box instead of floating in the square frame: see Trim to the car.Default: 0
padding
integer 0–50
Margin kept around a trimmed car, in percent of its longer side. Only with trim=1.Default: 0
shadow
0 | 1
A soft ground shadow under the car, drawn from its own cut-out: see Ground shadow. Same 1 credit.Default: 0
format
png | webp | jpg | auto
Output encoding. PNG and WebP keep the transparent background; JPG gets a flat one. auto delivers WebP when the request's Accept header lists image/webp and PNG otherwise, with Vary: Accept.Default: png

Spellings and unknown parameters

Parameters are read the way people write them: names in any case (Width, COLOR), view aliases such as left and front-right, grey and every CSS color name, whole numbers written 2024.0, and these other names:

  • make: brand
  • vehicle: vehicle_id
  • view: angle, camera, perspective, orientation
  • color: colour, paint, paint_color, hex, colors
  • w: width
  • h: height
  • background: bg, background_color

Each spelling is the same image as the canonical one, cached once.

Only tracking tags and cache busters are ignored: every utm_* and every _* name, and gclid, gclsrc, gbraid, wbraid, gad_source, gad_campaignid, dclid, fbclid, msclkid, yclid, ttclid, twclid, li_fat_id, igshid, mc_cid, mc_eid, mkt_tok, srsltid, ref, ref_src, v, ver, t, ts, timestamp, cb, cachebuster, cache_buster, cachebust, nocache, bust, rand, random, nonce, dpl. They change the URL, never the image, and X-Ignored-Parameters names them. Any other parameter the endpoint does not read is a 400 that names it in parameter and lists every name the endpoint reads in allowed, and nothing is charged: an image served without it would be another image than the one asked for.

A size above 1024 is clamped and X-Clamped-Parameters gives the values served. A known parameter sent twice, or under two names (w and width, view and angle), is a 400, because one value would be lost. JSON bodies (signed URLs, 3D, the MCP tools) take the documented names and their spellings (width, colour, vehicle_id) but not the other words, and refuse an unknown field: a body is written by its sender alone, to a schema.

Examples

bash
curl --fail-with-body \
  -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red" \
  --output porsche-911.png

For a layout that is not square, ask for the box you have and trim to the car; for a page, let the browser pick the encoding; for a paint the presets do not have, write the hex bare; and when you already hold a vehicle id, send that instead of the three name parameters:

text
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=600&h=400&trim=1&padding=6
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=512&background=f4f4f4&format=auto
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=1a2b3c
https://carimage.dev/api/v1/images/car?vehicle=veh_78qtwrgh37bkr&view=front-3-4&color=1a2b3c

Camera views

Eight fixed camera positions, described by where the camera stands around the vehicle: 0° is straight ahead of the nose, 90° level with the car's left side, 180° behind it and 270° level with its right side. The set is symmetric: front-3-4, side and rear-3-4 show the left side with the nose pointing left, and each has a -right twin that shows the right side with the nose pointing right. The framing is identical for every vehicle in the catalog, which is what makes listings and comparison grids line up.

Aliases are read in any case and with any separators (Front Left, front_left); left and right name the side of the car the camera sees, where the nose also points, so view=left is side and view=front-right is front-3-4-right. Every alias redirects to, and is cached as, the view it names.

view=LabelYawDescriptionAliases
frontFront0°Straight-on front view—
front-3-4Front three-quarter (facing left)35°Front and left side at ~35°, nose to the left; the classic hero anglefront34, hero, front-3-4-left, front-left, left-front
sideSide (facing left)90°Perfect side profile, nose pointing leftside-left, profile, left, left-side
rear-3-4Rear three-quarter (facing left)145°Rear and left side at ~35°, nose to the leftrear34, rear-3-4-left, rear-left, left-rear, back-left
rearRear180°Straight-on rear viewback
rear-3-4-rightRear three-quarter (facing right)215°Rear and right side at ~35°, nose to the right; rear-3-4 mirroredrear34-right, rear-right, right-rear, back-right
side-rightSide (facing right)270°Perfect side profile, nose pointing rightside-r, right, right-side
front-3-4-rightFront three-quarter (facing right)325°Front and right side at ~35°, nose to the right; the hero angle mirroredfront34-right, front-right, right-front

Sizes

Source renders are square 1024×1024 PNGs. Ask for a named preset with size=, or exact pixels with w= and h=: one dimension scales the square (w=600 is 600×600), both deliver exactly w×h, and fit decides how the car is placed in that box. Nothing is ever upscaled: 1024 px is the largest output, and a trimmed car is at most as large as it is in the source.

A size above 1024 is clamped rather than refused, and X-Clamped-Parameters gives the values served: a contain or cover box shrinks whole and keeps its shape (w=1920&h=1080 is delivered as 1024×576); one dimension, or an inside box, is capped on its own.

size=PixelsTypical use
thumb256 × 256Lists, autocomplete rows, chat avatars
small512 × 512Cards and grids
medium768 × 768Detail panes, comparison tables
large1024 × 1024Hero images, print-quality exports
text
# presets are square: 256, 512, 768, 1024
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&size=thumb

# one dimension scales the square: 600×600
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=600

# a box is delivered exactly: 600×400, whole car, transparent sides (fit=contain)
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=600&h=400

# 600×400, the car filling the box, cropped at the centre
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=600&h=400&fit=cover

# 600×400, cropped to the car first with a 6 % margin, no wasted canvas
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=600&h=400&trim=1&padding=6

# 512×512 on light gray, as WebP
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=512&background=f4f4f4&format=webp

Fit: filling a w×h box

With both w and h the square source has to be placed in a box of another shape, and fit= chooses how (default contain); with one dimension every fit yields the same image. For w=600&h=400:

fit=w=600&h=400 givesDescription
containdefault600×400: the car 400 px tall in the middle, 100 px of transparent canvas (or background color) on each sideExactly w×h; the whole car visible, the rest transparent or the background color (default).
cover600×400: the car scaled to 600 px and cropped 100 px at the top and bottomExactly w×h; scaled to fill the box and cropped at the centre.
inside400×400: the largest square that fits (what w+h returned before 2.6)The car fits within w×h; the output may be smaller than the box.

Trim to the car

The square source leaves empty canvas above and below a car, so a box that is not square shows either padding or a crop. trim=1 crops to the car's own bounds (its alpha channel) before sizing, so the car itself fills the box — the setting to reach for in listing cards, table rows and hero sections — and padding= keeps a margin around it, 0–50 percent of the car's longer side (only with trim).

  • With a box and contain or cover the canvas is still exactly w×h: it is the car, not the square, that gets fitted.
  • With one dimension or fit=inside the output follows the car's aspect ratio (w=600&trim=1 is roughly 600×270 for a side view), and X-Image-Width and X-Image-Height report the exact size.

Framing

framing= names a composition instead of spelling one out. It is a preset, not another transform: the API rewrites it into the trim and padding it stands for before anything else reads the request, so framing=tight is the same image, canonical URL, cache entry, ETag and 1 credit as trim=1&padding=0, and responses echo trim and padding, never framing.

framing values
ParameterTypeDescription
consistent
no trim
The generator's own camera framing (default, no trim): the same apparent camera scale across all eight views of a vehicle, for galleries, 360 spinners and 3D previews.Default: default
tight
trim=1
The whole car fills the box with no margin: trim=1&padding=0.
balanced
trim=1&padding=6
A catalog composition with even margins around the car: trim=1&padding=6.
  • Vehicle catalog grid: balanced, so every card has the same even margin whatever the car's shape.
  • Dealership listing hero: balanced with a background that matches the page.
  • Search-result thumbnails: tight at a small size, so the car uses every pixel of the slot.
  • Multi-angle gallery or 360 spinner: consistent (or no framing at all). Since the coherent-views policy the eight views of one vehicle share one apparent camera scale; trimming each view to its own bounds would zoom the side profile and the front by different amounts.
  • 3D preview poster: consistent, so the still matches the camera the model opens with.
  • Two vehicles side by side: tight makes each car as large as its box allows; consistent keeps each vehicle's own camera scale. Neither shows how big the cars are relative to each other in the real world: each vehicle is framed on its own.

Sending framing with trim or padding (even framing=consistent&trim=0) is a free 400 that names both, and an unknown value is a free 400 that lists the three. Values are read in any case. Make logos do not take it.

bash
# catalog grid card
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=600&h=400&framing=balanced&format=webp
# listing hero on the page's own grey
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=1024&h=576&background=f4f4f4&framing=balanced&format=webp
# search-result thumbnail
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=160&h=100&framing=tight&format=webp
# gallery: every view at one camera scale (framing=consistent is the default)
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=side&color=red&w=800&h=600&framing=consistent

Ground shadow

A cut-out car can look pasted onto a page. shadow=1 grounds it: a soft, neutral shadow under the car, an ambient one along the line its tyres stand on and a darker contact shadow right under them. It is drawn at delivery from the render's own transparent cut-out, so it is the same car, not a new render, and it costs the same 1 credit.

  • On a transparent PNG or WebP the shadow is semi-transparent, so it darkens whatever the image sits on; with a background or as JPG it is flattened into a soft grey.
  • It is never drawn above the car and stays inside the frame; with trim=1 the crop keeps it, so a trimmed car is a little taller with a shadow than without.
  • Off by default: an image without shadow is byte for byte what it was, with the same ETag. Make logos do not take it.
text
https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red&w=600&h=400&background=ffffff&trim=1&padding=6&shadow=1

Colors

color= takes one of 15 preset names (grey is gray), any other CSS color name, or any paint as hex; the default is silver. Every color is a recolor of one neutral render of the vehicle, not a new generation, so a custom paint costs the same 1 credit as a preset and is cached the same way.

How hex is written

  • In a URL, bare: color=1a2b3c is the canonical spelling, because an unescaped # starts the fragment (color=%231a2b3c works too); in JSON (signed URL items, 3D requests, MCP tools), "#1a2b3c" or "1a2b3c". Three-digit shorthand expands (1ab is 11aabb) and case does not matter.
  • Responses echo hex as "color": "#1a2b3c" and presets by name. A hex that equals a preset's swatch exactly is that preset: color=b3151b is red, one cached image either way.
  • A CSS color name (navy, Light Grey) is read as its CSS hex, in any case and with any separators — color=navy is the image color=000080 and is echoed that way — while the presets keep their own paint swatches, so red is #b3151b, not CSS #ff0000.

The resolve endpoint and the MCP tools' lookup, which pick a vehicle and a paint from a sentence, map free-text phrases ("midnight", "gunmetal") onto the nearest preset and keep a hex as is; the color parameter itself reads a CSS name exactly.

  • white#f4f4f2
  • black#141414
  • gray#7a7d82
  • silver#c3c6cb
    default
  • blue#1f4fa3
  • red#b3151b
  • green#1f6b3a
  • brown#5c3d2e
  • beige#d9c9a8
  • tan#c9a66b
  • orange#e0641b
  • yellow#f2c318
  • gold#b8963e
  • burgundy#6b1a2b
  • purple#5b2a86
  • 1a2b3cany hex

Backgrounds

Renders are transparent; background= flattens one onto a solid color (a CSS name, or a bare hex such as background=f4f4f4, echoed as #f4f4f4), PNG and WebP included. JPG has no alpha channel: it defaults to #ffffff, and background=transparent with format=jpg is a 400.

Formats

format= accepts png, webp, jpg, auto: PNG (the default) and WebP keep the transparent background, JPG is composited onto it, and WebP is typically 3–5× smaller than PNG at the same size. format=auto lets each client choose (WebP when its Accept header lists image/webp, PNG otherwise, with Vary: Accept), so a signed URL minted with it negotiates on every load: the right choice for an <img> tag.

Response

200 OK with the image bytes and a Content-Type of image/png, image/webp or image/jpeg. Metadata travels in headers:

HeaderExampleMeaning
X-Credits-Charged1Credits debited for this response — always 1 for a delivered image.
X-Credits-Remaining4870Balance after the debit. Plan top-ups before it reaches 0.
X-Image-Sourcecache | generatedCDN hit or cold render. Same price either way.
X-Vehicle-Idveh_395yw8tn73ff8The stable id of the vehicle served, on bytes responses too; send it back as vehicle= next time.
X-Vehicle-Matchexact | alias | trim | fuzzyHow make and model were read: exact for catalog slugs, otherwise the rule that interpreted them, from the most to the least literal (prefix to fuzzy): how names are matched. Also on 304 and URL responses.
X-Ignored-Parametersutm_source, cbOnly when the query held parameters the endpoint does not read: their names (never their values), up to 20. They were ignored, not refused; see Spellings.
X-Clamped-Parametersw=1024, h=576Only when a size above 1024 was asked for: the sizes that were reduced, with the values served. A box keeps its shape.
X-Image-Width600Width of the delivered canvas: exactly w for a contain or cover box, otherwise what the render produced.
X-Image-Height400Height of the delivered canvas. A trimmed car without an exact box follows its own aspect ratio.
ETag"9f2a…c41d-600x400-trim6-png"Stable per source image and transform. Plain square resizes keep the tag they always had; a box, a background, a trim or a shadow adds a segment. Send If-None-Match to receive a free 304.
VaryAcceptOnly with format=auto: the encoding follows the Accept header, so caches keep WebP and PNG apart.
Cache-Controlprivate, no-storeBilled responses bypass HTTP caches: store bytes explicitly and use ETags, or mint a cacheable signed URL for embeds. Keeping renders on your own servers or CDN is allowed on a paid plan, and they keep their license after it ends; see the license.
Server-Timingauth;dur=9.8, plan;dur=12.1, storage;dur=31.4, debit;dur=11.9, total;dur=96.2Where the request spent its time, in milliseconds: each step it waited on (auth, ratelimit, plan, lookup, storage, debit, tint, encode, render…) and the total; generation_wait means this request waited for another render, even if X-Image-Source is cache. Browser network panels show it as a timing breakdown. For diagnosis only: the step names may change.
X-Request-Idreq_01j9x…Include it in bug reports and feedback.

JSON mode: get a signed URL instead of bytes

Send Accept: application/json (or response=url) and the endpoint returns a signed delivery URL instead of the image. This is handy for agents and for servers that pass images to a browser without proxying bytes. Billing is unchanged: one credit.

bash
curl -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  -H "Accept: application/json" \
  "https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red"
200 OK
{
  "data": {
    "url": "https://carimage.dev/api/v1/delivery/eyJhbGciOi…",
    "expires_at": "2026-09-02T18:00:00.000Z",
    "max_uses": 0,
    "vehicle": {
      "vehicle_id": "veh_78qtwrgh37bkr",
      "make": "porsche",
      "model": "911",
      "year": 2024,
      "view": "front-3-4",
      "color": "red",
      "format": "png"
    },
    "width": 1024,
    "height": 1024,
    "format": "png"
  },
  "billing": {
    "credits_charged": 1,
    "credits_remaining": 4870
  },
  "request_id": "req_01j9x…"
}

The echoed vehicle opens with vehicle_id, the stable id of the catalog vehicle that was rendered (however you spelled it), then the delivery options you set: width, height, fit (only with a box), background, trim, padding and shadow. A hex paint is echoed as "color": "#1a2b3c". width and height are null when only the render can tell — a trimmed car without an exact box.

Conditional requests

Store the ETag with the bytes and send it as If-None-Match on the next request: a matching variant returns 304 Not Modified with no body and no charge.

bash
curl -I -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  -H 'If-None-Match: "9f2a…c41d"' \
  "https://carimage.dev/api/v1/images/car?make=porsche&model=911&year=2024&view=front-3-4&color=red"
# HTTP/2 304

Cold renders and refunds

When a make/model/year/color/view combination has never been requested, the API renders it synchronously (about 20 seconds) and saves it in a private origin. Concurrent requests share one generation; each delivered image still costs one credit. If rendering fails the request returns 502 and the credit is refunded.

Show a ready image without waiting (free)

GET /images/car.png?…&mode=cached takes the same parameters, vehicle= included, needs no key and costs nothing. It never renders: it answers 200 with an image that already exists, or a fast 404 with code: "not_cached". Use it to show a picture at once when there is one, and to render the rest in the background.

  1. Decode the VIN (free) or look the vehicle up, and keep its vehicle id.
  2. Put the mode=cached URL in an <img>, or ask client.isImageReady() from the SDK.
  3. On a 404, request the image with your key or POST /api/v1/image-urls (1 credit) without blocking the page, then swap it in.

Coverage is partial and changes as images are rendered, so treat a 404 as "not yet". A paint color can be answered from a neutral base of the view.

html
<img src="https://carimage.dev/images/car.png?vehicle=veh_3qfyk22gfhsx3&view=front-3-4&mode=cached"
     alt="2003 Honda Accord" onerror="this.hidden = true">

Errors

  • 400 — a parameter is missing or invalid; the detail says which (a parameter sent twice or under two spellings, vehicle together with make, model or year, a color that is neither a preset, a CSS color name nor a hex, padding without trim, background=transparent with format=jpg). An unknown parameter is an error. Tracking tags and cache busters are ignored and listed in X-Ignored-Parameters.
  • 401 — missing, revoked or malformed key.
  • 402 — fewer than 1 credit left. Do not retry; top up.
  • 404 — the vehicle is not in the catalog for that year, or no vehicle has that id. Do not retry the same input. For catalog imports, use the years and vehicle ids returned by vehicle search instead of combining every model with every year. Review the response's suggestions or check the catalog's spelling and years before continuing.
  • 429 — rate limited; wait Retry-After seconds.
  • 502 — the render failed; refunded.

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