依据 API 文档所述行为编写的构建指南,不涉及任何具体客户。 发布于 。
问题:您租的是车型类别,而不是某一辆车
租车客户预订的是一个车型类别,例如紧凑型车、中型 SUV、MPV,然后开走停车场上该类别中的任意一辆车。预订页面仍需为每个类别配图,惯例是使用一款代表车型并注明“或同类车型”。
这些图片往往东拼西凑,哪里能找到就用哪里的:这张是新闻图,那张是经销商照片,角度各异,背景不同,车辆在卡片中的占比也各不相同。这样拼凑出来的网格,一看就是拼凑的。车队页面需要的恰恰相反:每个车型类别都以相同方式呈现,卡片之间唯一变化的就是车本身。
集成方式一览
- 每个类别一款代表车型,以目录车辆 ID 保存,“或同级车型”写在标签里,绝不体现在图片中。
- 每张卡片使用统一的请求结构:相同的视角、尺寸框、适配方式、裁剪、内边距、车漆、背景和格式。
- 每个车型类别最多两张图片:网格中的卡片图和类别页面上的主图。
- 缓存,因为网格对每位访客都相同:文件放在您的 CDN 上,或签名 URL 只生成一次并重复使用。
第 1 步:按 id 为每个车辆级别选定一款代表车型
选择每个车型级别对应的销售车型,并查询其当前年款。GET /api/v1/vehicles?make=&model= 免费且公开,会列出某一车型的所有年款,每个年款都附带您需要存储的稳定车辆 ID;POST /api/v1/images/resolve 则可根据“2026 toyota rav4”这样的短语完成同样的操作。
# one model's years, each with its vehicle id (free, public)
curl -s "https://carimage.dev/api/v1/vehicles?make=toyota&model=rav4" | jq -c '.data.vehicles[] | select(.year == 2026)'
# {"year":2026,"id":"veh_e5w75c93f6cvk"}// One representative model per class: its current model year, by catalog id.
// "or similar" lives in the label; the picture never promises the car on the lot.
export const CLASS_IMAGES = {
compact: { vehicle: "veh_fy7r2yvwt4p1v", label: "Toyota Corolla or similar" }, // 2026 Toyota Corolla
"midsize-suv": { vehicle: "veh_e5w75c93f6cvk", label: "Toyota RAV4 or similar" }, // 2026 Toyota RAV4
"fullsize-suv": { vehicle: "veh_9mzh9ejqjye43", label: "Chevrolet Tahoe or similar" }, // 2026 Chevrolet Tahoe
minivan: { vehicle: "veh_9jck7rrybf35p", label: "Chrysler Pacifica or similar" }, // 2026 Chrysler Pacifica
};这些 id 永不改变,因此车队变动只需修改这一个映射:当中型车级别换成另一款车型或下一个年款时,只需替换一个 id,所有读取该映射的卡片、首屏大图和邮件都会随之更新。
第 2 步:所有级别使用同一种请求格式
9 个机位视角对目录中的每辆车都采用完全相同的构图,这正是网格能够整齐对齐的原因。卡片的其余部分只需几个参数,一次确定即可:
- 卡片使用
view=side:所有车辆朝向一致,位于同一基线上。每个左侧角度都有对应的-right版本(side-right),因此卡片可以朝向版面内侧。类别页面使用主视觉角度front-3-4。 w=640&h=320&fit=contain:每个类别都精确为 640×320,整车完整可见。响应中的X-Image-Width和X-Image-Height会确认画布尺寸。trim=1&padding=6:先裁剪到车辆本身再进行缩放适配,并以车辆较长边的 6% 作为边距,这样 Corolla 和 Tahoe 会以相同方式填满各自的卡片,而不是悬浮在正方形的原始画面中。background=f4f4f4会将卡片平铺到网格自身的灰色背景上。省略该参数即可保留透明背景,让卡片本身的颜色透出来。- 存储的文件使用
format=webp;签名 URL 使用format=auto,会根据每个浏览器提供 WebP 或 PNG。
# the class card: the same box, view, crop, paint and backdrop for every class
curl --fail-with-body -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
"https://carimage.dev/api/v1/images/car?vehicle=veh_e5w75c93f6cvk&view=side&color=white&w=640&h=320&fit=contain&trim=1&padding=6&background=f4f4f4&format=webp" \
-o midsize-suv-card.webp
# the class page's hero: the three-quarter view, the full width the API delivers
curl --fail-with-body -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
"https://carimage.dev/api/v1/images/car?vehicle=veh_e5w75c93f6cvk&view=front-3-4&color=white&w=1024&format=webp" \
-o midsize-suv-hero.webp第 3 步:整个网格使用同一种命名车漆
这 15 种预设是命名车漆:white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple。默认值为 silver,grey 会被视为 gray。请为所有车型类别选用同一种,让卡片看起来成套;上方展示的是 white。每种预设都使用其专属的车漆色样,而非同名的 CSS 颜色(red 为 #b3151b);每种车漆(包括十六进制颜色)都是基于同一个已准备视角的重新着色,因此每种车漆计为一张车辆图片。
第 4 步:缓存文件或 URL
类别网格对每位访客都相同,因此每次访问的成本应几乎为零。有两种实现方式:
- 存储文件。使用
GET /api/v1/images/car将每张卡片图和主图获取一次,然后像其他静态资源一样通过您的 CDN 提供;付费套餐有效期间,允许在您自己的服务器上保存副本,用于为您的产品提供服务(套餐结束后 30 天内删除,或购买图片包以永久保留一组图片)。请保留每个文件的ETag:每晚使用If-None-Match重新检查会返回304,不产生任何费用。对于上述车队,这相当于当月 8 张车辆图片,可按需反复使用。 - 或者一次性生成签名 URL 并重复使用。
POST /api/v1/image-urls每次调用最多可处理 50 张图片,返回无需密钥的 URL,有效期最长 7 天。不限使用次数的 URL 在有效期内可被公开缓存,因此当所有访客加载同一个 URL 时,重复请求将免费由 CDN 提供。添加renew: true后,已存储的 URL 在有效期过后仍可继续使用;续期只在其发生的月份将该图片计一次,若该图片当月已计过则不再重复计数,因此上述车队每月最多为 8 张车辆图片。
在控制台中将生成这些 URL 的密钥限制为仅用于您的预订域名,这样复制到其他网站的 URL 将返回 403。
import { CarImageClient, type ImageParams } from "@meterapp/car-image-sdk";
import { CLASS_IMAGES } from "./fleet";
const client = new CarImageClient({ apiKey: process.env.CAR_IMAGE_API_KEY });
// Framed once, for every class.
const card = (vehicle: string): ImageParams => ({
vehicle, view: "side", color: "white", width: 640, height: 320,
fit: "contain", trim: true, padding: 6, background: "#f4f4f4", format: "auto",
});
const hero = (vehicle: string): ImageParams => ({ vehicle, view: "front-3-4", color: "white", width: 1024, format: "auto" });
// Every visitor sees the same grid: mint the URLs once and serve the stored ones.
// renew keeps each URL working past its 7-day lifetime, one credit per image
// for each further week in which it is loaded.
const classes = Object.entries(CLASS_IMAGES);
const { data } = await client.createImageUrls(
classes.flatMap(([, entry]) => [card(entry.vehicle), hero(entry.vehicle)]),
{ ttlSeconds: 604800, renew: true, idempotencyKey: "class-grid-2026-10" }
);
await saveClassImages(
classes.map(([key], index) => ({ key, card: data[2 * index].url, hero: data[2 * index + 1].url, renewsUntil: data[2 * index].renews_until }))
);第 5 步:预订确认
确认邮件展示所预订的车型类别,而租车人可能在任何时候才打开邮件。请将其图片生成为可续期的 URL:ttl_seconds 设为 7 天的上限,renew: true,并让 renew_days 覆盖到还车日期之后。无人打开邮件的那几周不产生费用,租期结束后 URL 停止续期。每笔预订使用一个 Idempotency-Key,可使重试发送时重放第一个 URL,而不会再生成一个;将 URL 存储在预订记录上,之后每次重发都可复用它。我们自己的生命周期邮件就是这样运作的;邮件案例中介绍了相关机制和 HTML。
// The booking confirmation: opened today, again at the counter, maybe never.
const { data: [classImage] } = await client.createImageUrls(card(booking.classVehicle), {
ttlSeconds: 604800,
renew: true,
// A week past the return date, and no renewals after it (365 days at most).
renewDays: Math.min(daysUntil(booking.returnDate) + 7, 365),
// A retried send replays the first URL instead of minting a second one.
idempotencyKey: `booking:${booking.id}:class`,
});
booking.classImageUrl = classImage.url; // later resends reuse itCLI、SDK 和 MCP
- CLI:
npx @meterapp/car-image get --vehicle veh_… --view side --width 640 --height 320 --fit contain --trim --padding 6 --out card.webp将卡片写入文件;car-image url --batch classes.json --renew批量生成 URL。 - SDK:
client.vehicles({ make, model })用于获取 ID,client.getImage(…)用于获取文件,client.createImageUrls(…)用于获取 URL。 - MCP:
resolve_vehicle和create_car_image_urls可让助手根据“中型 SUV,RAV4 或同级车型”起草车型卡片。设置方法见 MCP 页面。
常见问题
- 卡片能否展示租车人实际会拿到的那辆车?
- 不能,也不应该这样做。租车按“或同级车型”出租,而渲染图呈现的是目录中的品牌、车型和年份,而不是您停车场里的某辆车。请展示一款代表性车型,并在标签中注明“或同级车型”。柜台分配具体车辆后,如果您想改为展示该车型,可以免费将其 VIN 解码为对应的目录车辆。
- 为什么网格中的车辆没有按比例显示?
- 因为 trim 会将每张渲染图裁剪到车身边缘,而 fit=contain 会让车辆填满卡片,所以紧凑型车和全尺寸 SUV 在卡片中的填充方式相同。这正是网格保持整齐的关键。请用文字说明尺寸:级别名称、座位数和可放行李数。
- 级别网格的费用是多少?
- 一个包含 4 个车型类别、每个类别各有一张卡片图和一张主图的车队,每月需要 8 张车辆图片,每张均可按任意尺寸随意多次交付。在付费套餐有效期间将文件存储在您的 CDN 上,它们只在您获取的当月计数,并可通过 ETag 免费重新校验。如果改为提供自动续期的签名 URL,则同样的图片会在每个有页面被打开的月份各计一次。
- 网格应使用哪种车漆颜色?
- 所有车型类别使用同一种预设颜色,让卡片看起来成套统一。共有 15 种预设:white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple,默认为 silver;任意十六进制颜色值也可以使用,价格相同。租客拿到的是停车场里那辆车的颜色,而卡片从未对颜色做出承诺。
- 如果某个车型类别的车型不在目录中怎么办?
- 目录中不存在的车辆会返回 404 并附带建议:最接近的目录车辆,每个都带有其 id。您可以使用其中之一,或在公开的需求看板上申请添加该车辆。该目录是开源的。