Car Image API

Trường hợp sử dụng · Cho thuê xe

Hình ảnh xe cho trang đội xe cho thuê

Hiển thị mọi hạng xe cho thuê theo cùng một cách: một mẫu xe đại diện cho mỗi hạng, khung hình giống hệt nhau với trim, padding và fit, một màu sơn có tên cụ thể, và các URL có thể lưu cache.

Hướng dẫn xây dựng được viết dựa trên hành vi đã ghi trong tài liệu của API; không nêu tên khách hàng nào. Đăng ngày .

Vấn đề: khách thuê một hạng xe, không phải một chiếc xe cụ thể

Khách thuê xe đặt một hạng xe, như xe cỡ nhỏ, SUV cỡ trung, xe minivan, rồi lái đi bất kỳ chiếc nào thuộc hạng đó đang có tại bãi. Trang đặt xe vẫn cần một hình ảnh cho mỗi hạng, và thông lệ là dùng một mẫu xe đại diện kèm dòng chữ "hoặc tương tự".

Những bức ảnh đó thường được lấy từ bất cứ nơi nào tìm được: chỗ này một ảnh báo chí, chỗ kia một ảnh của đại lý, góc chụp khác nhau, phông nền khác nhau, những chiếc xe chiếm khung thẻ theo những cách khác nhau. Một lưới ghép lại như vậy trông rõ là chắp vá. Điều một trang đội xe cần thì ngược lại: mọi hạng xe được thể hiện theo cùng một cách, để thứ duy nhất thay đổi từ thẻ này sang thẻ khác là chiếc xe.

Quy trình tích hợp diễn ra như thế nào

  • Một mẫu xe đại diện cho mỗi hạng, lưu dưới dạng vehicle id trong danh mục, với cụm "hoặc tương tự" trên nhãn chứ không bao giờ trong hình.
  • Một cấu trúc yêu cầu cho mọi thẻ: cùng góc nhìn, khung, kiểu vừa khung, cách cắt, lề, màu sơn, phông nền và định dạng.
  • Tối đa hai hình ảnh cho mỗi hạng xe: thẻ trong lưới và ảnh chính trên trang của hạng xe.
  • Lưu vào bộ nhớ đệm, vì lưới ảnh giống nhau với mọi khách truy cập: tệp trên CDN của bạn, hoặc URL ký được tạo một lần rồi dùng lại.

Bước 1: chọn một mẫu xe đại diện cho mỗi hạng xe, theo id

Chọn mẫu xe đại diện cho từng hạng xe và tra cứu năm đời hiện tại của mẫu đó. GET /api/v1/vehicles?make=&model= miễn phí, công khai và liệt kê mọi năm đời của một mẫu xe, mỗi năm kèm vehicle id ổn định mà bạn sẽ lưu trữ; POST /api/v1/images/resolve làm điều tương tự từ một cụm từ như "2026 toyota rav4".

Id của một năm đời xe
# 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"}
fleet.ts
// 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
};

Vì các id không bao giờ thay đổi, bảng ánh xạ này là nơi duy nhất bị ảnh hưởng khi đội xe thay đổi: khi hạng xe cỡ trung chuyển sang mẫu xe khác, hoặc sang đời xe kế tiếp, chỉ cần thay một id và mọi thẻ, ảnh chính và email đọc bảng ánh xạ sẽ cập nhật theo.

Bước 2: một cấu trúc yêu cầu cho mọi hạng xe

9 góc chụp được đóng khung giống hệt nhau cho mọi xe trong danh mục, nhờ đó lưới hình luôn thẳng hàng. Phần còn lại của thẻ chỉ là vài tham số, quyết định một lần:

  • view=side cho các thẻ: mọi xe đều quay cùng một hướng trên cùng một đường nền. Mỗi góc bên trái có bản đối xứng -right (side-right), để các thẻ có thể hướng vào trong bố cục. Trang hạng xe dùng front-3-4, góc chụp chủ đạo.
  • w=640&h=320&fit=contain: đúng 640×320 cho mọi hạng xe, thấy toàn bộ chiếc xe. Các header X-Image-Width và X-Image-Height trong phản hồi xác nhận kích thước khung.
  • trim=1&padding=6: cắt sát chiếc xe trước khi căn vừa khung, chừa lề bằng 6% cạnh dài hơn của xe, để một chiếc Corolla và một chiếc Tahoe lấp đầy thẻ theo cùng một cách thay vì lơ lửng trong khung nguồn hình vuông.
  • background=f4f4f4 làm phẳng thẻ lên màu xám của chính lưới. Bỏ tham số này để giữ nền trong suốt và để màu của thẻ hiện ra.
  • format=webp cho tệp lưu trữ; format=auto trên URL đã ký, tự phục vụ WebP hoặc PNG tùy từng trình duyệt.
Thẻ và ảnh hero cho một hạng xe
# 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

Bước 3: một màu sơn có tên cho toàn bộ lưới

15 màu cài sẵn là các màu sơn có tên: white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple. Mặc định là silver, và grey được hiểu là gray. Hãy chọn một màu cho mọi hạng xe để các thẻ trông đồng bộ; phía trên đang hiển thị white. Mỗi màu cài sẵn giữ mẫu sơn riêng thay vì màu CSS cùng tên (red là #b3151b), và mọi màu sơn, kể cả mã hex, đều là bản đổi màu từ một góc nhìn đã được chuẩn bị, nên mỗi màu sơn là một ảnh xe.

Bước 4: lưu bộ nhớ đệm các tệp hoặc URL

Lưới hạng xe giống hệt nhau với mọi khách truy cập, nên chi phí cho mỗi lượt truy cập phải gần như bằng không. Có hai cách để đạt được điều đó:

  • Lưu trữ tệp. Tải mỗi ảnh thẻ và ảnh hero một lần bằng GET /api/v1/images/car và phục vụ chúng từ CDN của bạn như mọi tài nguyên khác; gói trả phí cho phép lưu bản sao trên máy chủ của bạn để phục vụ sản phẩm trong thời gian gói còn hiệu lực (xóa chúng trong vòng 30 ngày sau khi gói kết thúc, hoặc mua Image Pack để giữ vĩnh viễn một bộ ảnh). Hãy giữ ETag của từng tệp: lần kiểm tra lại hằng đêm với If-None-Match sẽ trả về 304 và không tốn gì. Với đội xe ở trên, con số đó là 8 hình ảnh xe của tháng, được dùng lại bao nhiêu lần tùy ý.
  • Hoặc tạo URL đã ký một lần và dùng lại. POST /api/v1/image-urls nhận tối đa 50 hình ảnh mỗi lần gọi và trả về các URL không chứa khóa, có hiệu lực tối đa 7 ngày. URL không giới hạn lượt dùng có thể được lưu đệm công khai trong thời gian hiệu lực, nên khi mọi khách truy cập tải cùng một URL, các lượt tải lặp lại được phục vụ miễn phí từ CDN. Thêm renew: true để URL đã lưu tiếp tục hoạt động sau thời hạn; mỗi lần gia hạn chỉ tính hình ảnh một lần trong tháng diễn ra gia hạn, và không tính thêm nếu hình ảnh đã được tính trong tháng đó, nên đội xe ở trên vẫn chỉ tối đa 8 hình ảnh xe mỗi tháng.

Giới hạn khóa dùng để tạo URL chỉ cho tên miền đặt xe của bạn trên bảng điều khiển, khi đó một URL bị sao chép sang trang khác sẽ trả về 403.

Các URL của lưới, tạo một lần, bằng TypeScript SDK
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 }))
);

Bước 5: xác nhận đặt xe

Email xác nhận hiển thị hạng xe đã đặt, và email được mở bất cứ khi nào người thuê có thời gian xem. Hãy tạo hình ảnh của email dưới dạng URL tự gia hạn: ttl_seconds ở mức tối đa 7 ngày, renew: true, và renew_days kéo dài quá ngày trả xe. Những tuần không ai mở email sẽ không tốn phí, và sau khi kết thúc thuê, URL sẽ ngừng gia hạn. Một Idempotency-Key cho mỗi lượt đặt xe giúp lần gửi thử lại trả về URL đầu tiên thay vì tạo URL thứ hai, và việc lưu URL vào lượt đặt cho phép mọi lần gửi lại sau này dùng lại nó. Các email vòng đời của chính chúng tôi hoạt động theo cách này; câu chuyện về email mô tả cơ chế và mã HTML.

URL tự gia hạn cho một xác nhận đặt xe
// 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 it

CLI, SDK và MCP

  • CLI: npx @meterapp/car-image get --vehicle veh_… --view side --width 640 --height 320 --fit contain --trim --padding 6 --out card.webp ghi một thẻ ra file; car-image url --batch classes.json --renew tạo một loạt URL.
  • SDK: client.vehicles({ make, model }) để lấy id, client.getImage(…) để lấy tệp, client.createImageUrls(…) để lấy URL.
  • MCP: resolve_vehicle và create_car_image_urls giúp trợ lý soạn một thẻ hạng xe từ "SUV cỡ trung, RAV4 hoặc tương đương". Hướng dẫn thiết lập có tại trang MCP.

Câu hỏi thường gặp

Thẻ có thể hiển thị đúng chiếc xe mà người thuê sẽ nhận không?
Không, và cũng không nên cố làm vậy. Một hạng xe được cho thuê theo kiểu “hoặc tương đương”, còn một ảnh render thể hiện một hãng, mẫu xe và năm sản xuất trong danh mục, không phải một chiếc xe trong bãi của bạn. Hãy hiển thị một mẫu xe đại diện kèm cụm “hoặc tương đương” trong nhãn. Khi một chiếc xe cụ thể đã được giao tại quầy, VIN của xe được giải mã miễn phí ra xe tương ứng trong danh mục nếu bạn muốn hiển thị mẫu xe đó thay thế.
Tại sao các xe trong lưới không theo đúng tỷ lệ?
Vì trim cắt mỗi ảnh render sát chiếc xe và fit=contain lấp đầy thẻ bằng chiếc xe đó, nên một xe cỡ nhỏ và một chiếc SUV cỡ lớn đều lấp đầy thẻ như nhau. Đó là điều giữ cho lưới gọn gàng. Hãy mô tả kích thước bằng chữ: tên hạng xe, số chỗ ngồi và số hành lý.
Lưới hạng xe tốn bao nhiêu chi phí?
Một đội xe gồm 4 hạng xe, mỗi hạng có một ảnh thẻ và một ảnh chính, tương đương 8 hình ảnh xe mỗi tháng, mỗi hình được phân phối bao nhiêu lần tùy nhu cầu ở mọi kích thước. Lưu tệp trên CDN của bạn khi gói trả phí còn hiệu lực và chúng chỉ được tính trong tháng bạn tải về, kèm kiểm tra lại miễn phí bằng ETag. Nếu thay vào đó bạn dùng URL có chữ ký tự gia hạn, cùng những hình ảnh đó sẽ được tính một lần trong mỗi tháng có người mở trang.
Lưới hạng xe nên dùng màu sơn nào?
Dùng một màu đặt sẵn cho mọi hạng xe để các thẻ trông như một bộ đồng nhất. 15 màu đặt sẵn là white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple, và màu mặc định là silver; mã hex bất kỳ cũng dùng được, với cùng mức giá. Người thuê sẽ nhận chiếc xe có màu đang có trong bãi, điều mà thẻ chưa bao giờ hứa hẹn.
Nếu mẫu xe của một hạng xe không có trong danh mục thì sao?
Xe không có trong danh mục sẽ trả về 404 kèm gợi ý: các xe gần nhất trong danh mục, mỗi xe kèm id. Hãy dùng một trong số đó, hoặc đề nghị bổ sung xe trên bảng yêu cầu công khai. Danh mục là mã nguồn mở.

Đọc tiếp

Câu chuyện khách hàng · Công cụ dành cho nhà phát triểnCách nhúng ảnh xe vào email bằng signed URL không bao giờ bị hỏngCác email vòng đời khách hàng của chính chúng tôi nhúng đúng ảnh render đầu tiên của từng khách hàng dưới dạng signed URL trực tiếp, tự gia hạn trong một năm. Dưới đây là cách hoạt động và cách bạn áp dụng tương tự.