Images
GET /api/v1/images/car — parameters, views, sizes, any paint color, vehicle ids, headers, JSON mode.
/api/v1/images/carQuery parameters
| Parameter | Type | Description |
|---|---|---|
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:brandvehicle:vehicle_idview:angle,camera,perspective,orientationcolor:colour,paint,paint_color,hex,colorsw:widthh:heightbackground: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
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.pngFor 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:
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=1a2b3cCamera 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= | Label | Yaw | Description | Aliases |
|---|---|---|---|---|
front | Front | 0° | Straight-on front view | — |
front-3-4 | Front three-quarter (facing left) | 35° | Front and left side at ~35°, nose to the left; the classic hero angle | front34, hero, front-3-4-left, front-left, left-front |
side | Side (facing left) | 90° | Perfect side profile, nose pointing left | side-left, profile, left, left-side |
rear-3-4 | Rear three-quarter (facing left) | 145° | Rear and left side at ~35°, nose to the left | rear34, rear-3-4-left, rear-left, left-rear, back-left |
rear | Rear | 180° | Straight-on rear view | back |
rear-3-4-right | Rear three-quarter (facing right) | 215° | Rear and right side at ~35°, nose to the right; rear-3-4 mirrored | rear34-right, rear-right, right-rear, back-right |
side-right | Side (facing right) | 270° | Perfect side profile, nose pointing right | side-r, right, right-side |
front-3-4-right | Front three-quarter (facing right) | 325° | Front and right side at ~35°, nose to the right; the hero angle mirrored | front34-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= | Pixels | Typical use |
|---|---|---|
thumb | 256 × 256 | Lists, autocomplete rows, chat avatars |
small | 512 × 512 | Cards and grids |
medium | 768 × 768 | Detail panes, comparison tables |
large | 1024 × 1024 | Hero images, print-quality exports |
# 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=webpFit: 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 gives | Description |
|---|---|---|
containdefault | 600×400: the car 400 px tall in the middle, 100 px of transparent canvas (or background color) on each side | Exactly w×h; the whole car visible, the rest transparent or the background color (default). |
cover | 600×400: the car scaled to 600 px and cropped 100 px at the top and bottom | Exactly w×h; scaled to fill the box and cropped at the centre. |
inside | 400×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. |
w=600&h=400 gave 400×400); that output is now fit=inside, so pass it to keep the old behaviour.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
containorcoverthe canvas is still exactlyw×h: it is the car, not the square, that gets fitted. - With one dimension or
fit=insidethe output follows the car's aspect ratio (w=600&trim=1is roughly 600×270 for a side view), andX-Image-WidthandX-Image-Heightreport 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.
| Parameter | Type | Description |
|---|---|---|
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:
balancedwith abackgroundthat matches the page. - Search-result thumbnails:
tightat a small size, so the car uses every pixel of the slot. - Multi-angle gallery or 360 spinner:
consistent(or noframingat 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:
tightmakes each car as large as its box allows;consistentkeeps 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.
# 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=consistentGround 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
backgroundor as JPG it is flattened into a soft grey. - It is never drawn above the car and stays inside the frame; with
trim=1the crop keeps it, so a trimmed car is a little taller with a shadow than without. - Off by default: an image without
shadowis byte for byte what it was, with the same ETag. Make logos do not take it.
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=1Colors
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=1a2b3cis the canonical spelling, because an unescaped#starts the fragment (color=%231a2b3cworks too); in JSON (signed URL items, 3D requests, MCP tools),"#1a2b3c"or"1a2b3c". Three-digit shorthand expands (1abis11aabb) 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=b3151bisred, 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=navyis the imagecolor=000080and is echoed that way — while the presets keep their own paint swatches, soredis#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#f4f4f2black#141414gray#7a7d82- default
silver#c3c6cb blue#1f4fa3red#b3151bgreen#1f6b3abrown#5c3d2ebeige#d9c9a8tan#c9a66borange#e0641byellow#f2c318gold#b8963eburgundy#6b1a2bpurple#5b2a861a2b3cany 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:
| Header | Example | Meaning |
|---|---|---|
X-Credits-Charged | 1 | Credits debited for this response — always 1 for a delivered image. |
X-Credits-Remaining | 4870 | Balance after the debit. Plan top-ups before it reaches 0. |
X-Image-Source | cache | generated | CDN hit or cold render. Same price either way. |
X-Vehicle-Id | veh_395yw8tn73ff8 | The stable id of the vehicle served, on bytes responses too; send it back as vehicle= next time. |
X-Vehicle-Match | exact | alias | trim | fuzzy | How 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-Parameters | utm_source, cb | Only 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-Parameters | w=1024, h=576 | Only when a size above 1024 was asked for: the sizes that were reduced, with the values served. A box keeps its shape. |
X-Image-Width | 600 | Width of the delivered canvas: exactly w for a contain or cover box, otherwise what the render produced. |
X-Image-Height | 400 | Height 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. |
Vary | Accept | Only with format=auto: the encoding follows the Accept header, so caches keep WebP and PNG apart. |
Cache-Control | private, no-store | Billed 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-Timing | auth;dur=9.8, plan;dur=12.1, storage;dur=31.4, debit;dur=11.9, total;dur=96.2 | Where 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-Id | req_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.
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"{
"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.
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 304Cold 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.
- Decode the VIN (free) or look the vehicle up, and keep its vehicle id.
- Put the
mode=cachedURL in an<img>, or askclient.isImageReady()from the SDK. - 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.
<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; thedetailsays which (a parameter sent twice or under two spellings,vehicletogether with make, model or year, acolorthat is neither a preset, a CSS color name nor a hex,paddingwithouttrim,background=transparentwithformat=jpg). An unknown parameter is an error. Tracking tags and cache busters are ignored and listed inX-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'ssuggestionsor check the catalog's spelling and years before continuing.429— rate limited; waitRetry-Afterseconds.502— the render failed; refunded.
Every failure is application/problem+json. See Errors.