Car Image API

Trường hợp sử dụng · Đấu giá

Ảnh xe cho tin đăng đấu giá

Đăng các lô đấu giá trước khi có ảnh chụp, mỗi lô kèm một ảnh studio theo năm mẫu xe, được ghi rõ là ảnh render từ danh mục, qua các URL đã ký hết hạn cùng phiên đấu giá.

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 đề: phiên đấu giá đã diễn ra trước khi có ảnh

Danh mục đấu giá được đăng ngay khi xe ký gửi về đủ: mỗi xe có một số VIN, một số lô và một ngày bán. Ảnh chụp chỉ có khi xe về đến bãi và thợ ảnh tiếp cận được xe, mà với một phần xe trong phiên thì việc này diễn ra sau khi đã mở đặt giá. Cho đến lúc đó, mỗi lô như vậy chỉ là một ô xám bên cạnh một dòng chữ.

Ảnh render danh mục lấp đầy khung hình với đúng năm đời xe. Nhưng đấu giá cũng chính là nơi một ảnh render tuyệt đối không được bị nhầm là chiếc xe thật: người đặt giá định giá dựa trên tình trạng xe, còn ảnh render không thể hiện điều đó, vì nó không mô tả bất kỳ chiếc xe vật lý cụ thể nào. Mọi điều dưới đây đều xuất phát từ việc đảm bảo đồng thời cả hai điều đó.

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

  • Một ảnh render cho mỗi lô từ số VIN, chỉ hiển thị cho đến khi có ảnh thật của lô.
  • Bộ chọn từ danh mục cho các lô có VIN không giải mã được.
  • Nhãn trên hình ảnh: "Ảnh render từ danh mục, không phải lô này".
  • Mỗi lô một URL, tạo một lần với Idempotency-Key, tồn tại suốt phiên đấu giá.

Bước 1: từ VIN của lô xe đến vehicle id

GET /api/v1/vin/{vin} miễn phí. Khi danh mục có xe đó, phản hồi sẽ chứa data.vehicle.id, id ổn định để lưu cho lô; phiên bản, kiểu thân xe và động cơ đã giải mã được giữ trong phần mô tả của lô. Danh mục trải dài từ 1990 đến 2027, nên xe đời cũ trong phiên đấu giá cũng được render như xe mới nhất. Hướng dẫn cho bảo hiểm trình bày kết quả giải mã theo từng trường, và tài liệu VIN đề cập đến VIN không đầy đủ và các lỗi.

Giải mã VIN khi tiếp nhận xe
# the lot's VIN to the vehicle id the lot stores (free); nothing printed means no catalog match
npx @meterapp/car-image vin "$LOT_VIN" --json | jq -r '.data.vehicle.id // empty'

Bước 2: không có VIN giải mã được? Chọn xe từ danh mục

Một số lô xe đến mà không có VIN giải mã được: xe sản xuất cho thị trường khác, VIN bị nguồn nhập sai, hoặc phiếu ký gửi chỉ có năm, hãng, mẫu xe và không gì khác. Hãy thêm vào biểu mẫu ký gửi ba danh sách thả xuống lấy dữ liệu từ GET /api/v1/vehicles, miễn phí và công khai: ?year= liệt kê các hãng có mẫu xe trong năm đó, còn ?year=&makeId= liệt kê các mẫu xe của hãng đó, mỗi mẫu kèm id xe của năm mẫu đó.

Năm, rồi hãng, rồi mẫu xe
# every make with a 2006 model year (free, public)
curl -s "https://carimage.dev/api/v1/vehicles?year=2006"
# {"data":{"year":2006,"makes":[…,{"id":476,"name":"DODGE","slug":"dodge"},…]},…}

# that make's 2006 models, each with the id of its 2006 model year
curl -s "https://carimage.dev/api/v1/vehicles?year=2006&makeId=476"
200 OK (đã rút gọn)
{
  "data": {
    "year": 2006,
    "make_id": 476,
    "models": [
      {
        "name": "Caliber",
        "slug": "caliber",
        "vehicle_type": "Passenger Car",
        "id": "veh_294vq81yq0d3y"
      },
      {
        "name": "Charger",
        "slug": "charger",
        "vehicle_type": "Passenger Car",
        "id": "veh_96j8z47jqfd4r"
      },
      "…"
    ]
  }
}

Danh mục này cũng chính là gói mã nguồn mở @meterapp/vehicle-db, nên các danh sách thả xuống cũng có thể chạy ngoại tuyến trên cùng một danh sách. Dù cách nào, lô đấu giá cũng lưu cùng loại id như một VIN đã giải mã, và không bước nào phía sau phải ghi tên xe bằng chữ.

Khi cả một bảng ký gửi đến cùng lúc, POST /api/v1/vehicles/check đọc tối đa 2.000 mục mỗi lần gọi, mỗi mục được ghi đúng như trong bảng và lấy số lô làm ref, rồi phản hồi cho từng mục: khớp kèm id cần lưu, gợi ý, không tìm thấy hoặc dòng không hợp lệ. Không có gì được render và không tính phí; tài liệu vehicles có thông tin chi tiết.

Bước 3: ghi rõ ảnh render là ảnh render

Hãy đặt nhãn ngay trên hình ảnh, nơi người đặt giá nhìn vào, và trong văn bản alt, chứ không chỉ trong phần mô tả bên dưới. Tình trạng, số km, hư hỏng, tùy chọn và màu sơn thực tế của xe thuộc về phần mô tả lô và, khi đã có, các ảnh chụp. Khi có ảnh chụp, ảnh render sẽ được gỡ bỏ.

Hình ảnh của lô cho đến khi có ảnh chụp thực tế
<figure class="lot-image">
  <img src="https://carimage.dev/api/v1/delivery/eyJhbGciOi…" width="800" height="450"
       alt="Catalog render of a 2006 Dodge Charger, not a photo of lot 117">
  <span class="lot-image__badge">Catalog render, not this lot</span>
</figure>
<p>Photos of this lot are on their way. Condition, mileage and damage are in the report.</p>

Bước 4: mỗi lô một URL, chỉ tạo một lần

Tạo URL cho lô khi tiếp nhận bằng POST /api/v1/image-urls và một Idempotency-Key tạo từ phiên đấu giá và lô, gồm chữ cái, chữ số, ., _, : và -. URL tính hình ảnh của nó là một hình ảnh xe của tháng khi được tạo, vì vậy nếu không có khóa, một lần tiếp nhận được thử lại sẽ tạo thêm URL thứ hai. Khi có khóa:

  • Cùng một khóa với cùng nội dung trong vòng 24 giờ sẽ phát lại phản hồi đầu tiên, kể cả cùng URL, kèm Idempotent-Replayed: true và không bị tính phí lần hai.
  • Cùng một khóa idempotency với body khác sẽ trả về 422, và một lần thử lại vượt lên trước yêu cầu đầu tiên sẽ trả về 409 kèm Retry-After. Vì vậy, hãy cố định mọi thứ trong body, kể cả thời hạn, ngay khi tạo lô đấu giá, và lưu body đó cùng với lô.
  • Hãy lưu cả URL vào lô xe: khóa giúp thử lại an toàn, còn URL đã lưu là thứ các trang đọc trong suốt phần còn lại của phiên đấu giá.

Cả một danh mục được nhập cùng lúc có thể tạo URL cho tối đa 50 lô xe mỗi lần gọi, mỗi đợt dùng một khóa; mỗi URL trong phản hồi đều ghi lại xe và các tùy chọn mà nó được tạo cho.

URL của lô 117
curl --fail-with-body -X POST https://carimage.dev/api/v1/image-urls \
  -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: sale-2026-10-14:lot-117" \
  -d '{"images":[{"vehicle":"veh_96j8z47jqfd4r","view":"side","width":800,"height":450,"fit":"contain","trim":true,"padding":6,"format":"auto"}],"ttl_seconds":259200}'
# run it again: the same URL comes back with Idempotent-Replayed: true, and nothing more is charged

Bước 5: khớp thời hạn của URL với phiên bán

ttl_seconds tối đa là 604800 (7 ngày); giá trị dài hơn sẽ bị giới hạn về mức đó. Với phiên bán kết thúc trong tuần, hãy đặt giá trị này bằng thời gian còn lại đến lúc kết thúc. Khi đó ảnh hiển thị sẽ ngừng hoạt động cùng lúc với việc đặt giá, và sau đó URL trả về 403.

  • Phiên bán có thời hạn dài hơn 7 ngày: tạo URL với renew: true, ttl_seconds ở mức tối đa và renew_days bao trọn phiên bá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, không tính thêm nếu hình ảnh đã được tính trong tháng đó, những tuần không ai mở lô xe thì không bị tính gì, và việc gia hạn dừng lại tại renews_until.
  • Hãy giữ max_uses ở 0, giá trị mặc định: URL không giới hạn có thể được lưu bộ nhớ đệm công khai trong suốt thời hạn hiệu lực, còn URL bị giới hạn sẽ là private, no-store và mọi lượt tải đều được gửi về máy chủ gốc.
  • Giới hạn khóa dùng để tạo URL ký trong các tên miền của sàn đấu giá trên bảng điều khiển: ảnh lô xe bị sao chép sang trang khác sẽ trả về 403.
Tiếp nhận bằng TypeScript SDK
import { CarImageClient, type ImageParams } from "@meterapp/car-image-sdk";

const client = new CarImageClient({ apiKey: process.env.CAR_IMAGE_API_KEY });

const lotImage = (vehicle: string): ImageParams => ({
  vehicle, view: "side", width: 800, height: 450, fit: "contain", trim: true, padding: 6, format: "auto",
});

// How long the lot's URL lives, decided once from the sale's close.
function lifetime(closesAt: Date) {
  const seconds = secondsUntil(closesAt);
  return seconds <= 604800
    ? { ttlSeconds: Math.max(seconds, 60) } // closes within the week
    : { ttlSeconds: 604800, renew: true, renewDays: Math.min(daysUntil(closesAt), 365) }; // a longer timed sale
}

// At intake, once per lot. The lifetime is stored with the lot, so a retry sends
// the same body and replays the first answer instead of minting a second URL.
lot.imageLifetime ??= lifetime(sale.closesAt);
const { data: [placeholder] } = await client.createImageUrls(lotImage(lot.vehicleId), {
  ...lot.imageLifetime,
  idempotencyKey: `${sale.id}:lot-${lot.number}`,
});
lot.placeholderUrl = placeholder.url; // replaced by the lot's own photos when they arrive

Chuẩn bị theo quy mô phiên đấu giá

Mỗi lô là một hình ảnh xe, tức xe của lô đó ở màu sơn và góc nhìn của nó, trừ khi hai lô trùng cả ba yếu tố, và mỗi gói bao gồm một số lượng hình ảnh xe mỗi tháng: Free 100, Pro 2.500 và Business 10.000; Enterprise được thỏa thuận riêng. Hình ảnh đã được tính trong tháng này luôn được phục vụ, và một lô yêu cầu vượt quá hạn mức sẽ bị từ chối toàn bộ trước khi tính bất cứ thứ gì, kèm thông tin gói và hạn mức trong phản hồi. Hãy chọn gói theo số lô bạn đăng trong một tháng. Câu chuyện về sàn giao dịch trình bày cách điều tiết một đợt nhập lớn trong giới hạn tốc độ và giới hạn render.

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

Ảnh render có thể tiếp tục hiển thị sau khi ảnh chụp của lô xe đã có không?
Hãy thay thế nó. Ảnh render chỉ là ảnh tạm cho đời xe, và người đấu giá không bao giờ nên phải băn khoăn bức ảnh nào là chiếc xe đang được bán. Nếu một trang giữ lại ảnh để tham khảo thì nhãn phải đi kèm.
URL sẽ ra sao sau phiên đấu giá?
URL hết hạn khi hết thời hạn hiệu lực, hoặc khi một URL tự gia hạn đạt đến cuối thời gian gia hạn, và khi đó sẽ trả về 403. Đến lúc ấy, lô xe đã có ảnh chụp riêng hoặc kết quả, và kho lưu trữ của phiên đấu giá nên hiển thị các ảnh chụp. Thu hồi khóa đã tạo các URL sẽ vô hiệu hóa tất cả cùng lúc.
Lần thử lại trả về 422. Tại sao?
Cùng một Idempotency-Key được gửi lại với body khác. Nguyên nhân thường gặp là thời hạn hiệu lực được tính lại theo đồng hồ tại thời điểm thử lại. Hãy cố định thời hạn khi tạo lô và lưu lại; khi đó lần thử lại sẽ gửi cùng một body và nhận lại đúng phản hồi đầu tiên.
Ảnh render có thể hiển thị đúng màu sơn của lô đấu giá không?
Có: color nhận bất kỳ tên màu đặt sẵn nào hoặc mã hex, nên hình ảnh có thể khớp với màu sơn trên phiếu ký gửi mà không tốn thêm chi phí. Đó vẫn là mẫu xe trong màu sơn đó, không phải chính lô xe, nên nhãn vẫn được giữ.
Một phiên đấu giá 400 lô xe có chi phí bao nhiêu?
400 hình ảnh xe của tháng: 1 hình ảnh xe cho mỗi lô khi URL của lô được tạo, và lần tạo lại do thử lại không bị tính thêm. Mọi lượt tải trong thời hạn của URL đều miễn phí. Các gói bao gồm Free 100, Pro 2.500 và Business 10.000 hình ảnh xe mỗi tháng, và các lô có cùng xe, màu sơn và góc nhìn chỉ tính một lần.

Đọc tiếp

Câu chuyện khách hàng · Sàn giao dịch ô tôCách đưa ảnh xe chuẩn studio lên mọi tin đăng trên sàn giao dịchMột tin đăng cần có hình ảnh ngay cả trước khi người bán tải ảnh lên. Các sàn giao dịch bổ sung ảnh cho toàn bộ danh mục với một góc chụp và một màu sơn, rồi giữ nguyên cấu trúc yêu cầu cho mọi đời xe mới.