Руководство по интеграции, написанное на основе документированного поведения API; конкретные клиенты в нём не упоминаются. Опубликовано .
Проблема: торги начинаются раньше, чем появляются фотографии
Каталог аукциона публикуется, как только поступают автомобили на продажу: для каждого — VIN, номер лота и дата торгов. Фотографии появляются, когда автомобиль прибывает на площадку, а фотограф добирается до автомобиля, — и для части лотов это происходит уже после начала торгов. До тех пор каждый такой лот — серый прямоугольник рядом со строкой текста.
Рендер из каталога заполняет место изображением нужного модельного года. Но аукцион — именно то место, где рендер никогда не должен выдаваться за сам автомобиль: участники торгов оценивают состояние, а рендер его не показывает, потому что он не изображает какой-либо конкретный физический автомобиль. Всё описанное ниже вытекает из необходимости учитывать оба этих факта одновременно.
Как выглядит интеграция
- Рендер для каждого лота по его VIN, который показывается только до появления собственных фото лота.
- Выбор из каталога для лотов, VIN которых не декодируется.
- Подпись на изображении: «Рендер из каталога, не этот лот».
- Один URL на лот, созданный один раз с
Idempotency-Keyи действующий до конца торгов.
Шаг 1: от VIN лота к id автомобиля
GET /api/v1/vin/{vin} — бесплатный метод. Если автомобиль есть в каталоге, ответ содержит data.vehicle.id — стабильный идентификатор, который нужно сохранить в лоте; декодированные комплектация, кузов и двигатель остаются в тексте лота. Каталог охватывает годы с 1990 по 2027, поэтому старые автомобили на аукционе получают рендеры так же, как новейшие. В руководстве по страхованию декодирование разобрано поле за полем, а в документации по VIN описаны неполные VIN и ошибки.
# 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'Шаг 2: VIN не декодируется? Выберите автомобиль в каталоге
Некоторые лоты поступают без VIN, который удаётся декодировать: автомобиль, выпущенный для другого рынка, VIN с опечаткой в источнике, акт приёмки с годом, маркой и моделью — и больше ничего. Добавьте в форму приёмки три выпадающих списка на основе GET /api/v1/vehicles — это бесплатный и публичный эндпоинт: ?year= возвращает марки, у которых есть модель этого года, а ?year=&makeId= — модели этой марки, каждую с id автомобиля для этого модельного года.
# 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"{
"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"
},
"…"
]
}
}Этот же каталог доступен как открытый пакет @meterapp/vehicle-db, поэтому выпадающие списки могут работать и офлайн с тем же самым списком. В любом случае у лота оказывается такой же id, как у декодированного VIN, и дальше по цепочке никто не вписывает название автомобиля вручную.
Когда весь список лотов от комитента приходит разом, POST /api/v1/vehicles/check принимает до 2 000 записей за вызов — каждую в том написании, что в списке, с номером лота в качестве ref — и отвечает по каждой: совпадение с id для сохранения, варианты, промах или некорректная строка. Ничего не рендерится и ничего не списывается; подробности — в документации по vehicles.
Шаг 3: подпишите рендер как рендер
Разместите пометку на самом изображении, куда падает взгляд участника торгов, и в alt-тексте, а не только в описании под ним. Состояние, пробег, повреждения, опции и фактический цвет автомобиля указываются в тексте лота, а когда появятся фотографии — на них. Когда приходят фотографии, рендер убирается.
<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>Шаг 4: один URL на лот, созданный один раз
Создавайте URL лота при приёмке через POST /api/v1/image-urls с Idempotency-Key, составленным из аукциона и лота, из букв, цифр, ., _, : и -. URL засчитывает своё изображение как изображение автомобиля за месяц в момент создания, поэтому без ключа повторная приёмка создала бы второй URL. С ключом:
- Запрос с тем же ключом и тем же телом в течение 24 ч возвращает первый ответ повторно, включая тот же URL, с заголовком
Idempotent-Replayed: trueи без повторного списания. - Тот же ключ с другим телом запроса вернёт
422, а повторный запрос, опередивший первый, —409сRetry-After. Поэтому при создании лота зафиксируйте всё в теле запроса, включая срок действия, и храните его вместе с лотом. - Также сохраните URL в данных лота: ключ защищает повторные запросы, а сохранённый URL страницы используют до конца торгов.
При импорте всего каталога разом можно выпустить URL не более чем для 50 лотов за вызов, с отдельным ключом на каждый пакет; каждый URL в ответе повторяет автомобиль и параметры, для которых он был выпущен.
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Шаг 5: согласуйте срок действия URL со сроком торгов
ttl_seconds может составлять до 604800 (7 дн.); большее значение сокращается до этого предела. Если торги закрываются в течение недели, укажите время, оставшееся до закрытия. Тогда изображение-заглушка перестанет работать одновременно с окончанием торгов, а после этого URL будет возвращать 403.
- Торги дольше 7 дн.: создавайте URL с
renew: true, максимальнымttl_secondsиrenew_days, покрывающим весь срок торгов. Продление засчитывает изображение один раз в том месяце, на который оно приходится, и ничего сверх того, если оно уже было учтено в этом месяце; недели, когда лот никто не открывает, ничего не стоят, а продление прекращается наrenews_until. - Оставляйте
max_usesравным 0 (значение по умолчанию): URL без ограничений публично кэшируется на весь срок действия, а URL с лимитом получаетprivate, no-storeи отправляет каждую загрузку на исходный сервер. - Ограничьте ключ, создающий URL, доменами вашего аукциона на панели управления: изображение лота, скопированное на другой сайт, вернёт
403.
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Подберите тариф под объём торгов
Каждый лот — это одно изображение автомобиля: его автомобиль в его цвете и ракурсе, если только два лота не совпадают по всем трём параметрам, и каждый тариф включает определённое число изображений автомобилей в месяц: Free — 100, Pro — 2 500 и Business — 10 000; для Enterprise — по договорённости. Изображение, уже учтённое в этом месяце, отдаётся всегда, а пакетный запрос, который превысил бы лимит, отклоняется целиком ещё до какого-либо учёта, и в ответе указываются тариф и лимит. Подбирайте тариф под количество лотов, которые вы выставляете за месяц. В истории маркетплейса рассказано, как распределить крупный импорт с учётом лимитов на запросы и рендеринг.
Часто задаваемые вопросы
- Может ли рендер остаться после того, как появятся фотографии лота?
- Замените его. Рендер — это заглушка для модельного года, и участник торгов никогда не должен гадать, на каком изображении продаваемый автомобиль. Если страница сохраняет рендер для справки, подпись остаётся вместе с ним.
- Что происходит с URL после продажи?
- URL перестаёт действовать, когда истекает его срок действия или когда продлеваемый URL достигает конца периода продления, после чего он возвращает 403. К этому времени у лота уже есть собственные фотографии или результат, и в архиве торгов должны отображаться фотографии. Отзыв ключа, которым были созданы URL, сразу аннулирует их все.
- Повторный запрос вернул 422. Почему?
- Тот же Idempotency-Key пришёл с другим телом запроса. Обычная причина — срок действия, заново вычисленный по часам в момент повторной попытки. Зафиксируйте срок действия при создании лота и сохраните его — тогда повторный запрос отправит то же тело и вернёт первый ответ.
- Может ли рендер показать цвет кузова лота?
- Да: параметр color принимает любое из предустановленных названий или hex-код, поэтому изображение может совпадать с цветом, указанным в документах на лот, без доплаты. Но это всё равно модель в этом цвете, а не сам лот, поэтому пометка остаётся.
- Сколько стоят торги с количеством лотов 400?
- 400 изображений автомобиля за месяц: 1 изображение автомобиля на лот в момент создания его URL, а повторное создание ничего не добавляет. Каждая загрузка в течение срока действия URL бесплатна. Планы включают Free 100, Pro 2 500 и Business 10 000 изображений автомобилей в месяц, а лоты с одинаковыми автомобилем, цветом и ракурсом учитываются один раз.