Руководство по интеграции, написанное на основе документированного поведения API; конкретные клиенты в нём не упоминаются. Опубликовано .
Проблема: вы арендуете класс, а не автомобиль
Клиент проката бронирует класс — компактный автомобиль, среднеразмерный кроссовер, минивэн — и уезжает на любом автомобиле этого класса, который есть на стоянке. Странице бронирования всё равно нужно изображение для каждого класса, и по сложившейся практике это одна типичная модель с пометкой «или аналогичный».
Такие изображения обычно берутся откуда придётся: здесь пресс-фото, там снимок дилера, разные ракурсы, разные фоны, автомобили по-разному заполняют карточку. Собранная так сетка и выглядит сборной. Странице автопарка нужно обратное: каждый класс показан одинаково, и от карточки к карточке меняется только сам автомобиль.
Как выглядит интеграция
- Одна представительная модель на класс, сохранённая как идентификатор автомобиля из каталога; пометка «или аналогичный» — в подписи, но никогда на изображении.
- Одна структура запроса для всех карточек: одинаковые ракурс, рамка, вписывание, обрезка, отступы, цвет, фон и формат.
- Не более двух изображений на класс: карточка в сетке и главное изображение на странице класса.
- Кешируются, потому что сетка одинакова для всех посетителей: файлы на вашем 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для сохраняемых файлов;format=autoдля подписанных URL — он отдаёт каждому браузеру 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), и любой цвет, включая hex, — это перекраска одного подготовленного ракурса, поэтому каждый цвет — одно изображение автомобиля.
Шаг 4: кэшируйте файлы или URL
Сетка классов одинакова для всех посетителей, поэтому каждое посещение должно обходиться почти бесплатно. Добиться этого можно двумя способами:
- Храните файлы у себя. Загрузите каждую карточку и главное изображение один раз через
GET /api/v1/images/carи отдавайте их со своего CDN, как любой другой ресурс; платный тариф разрешает хранить копии на собственных серверах для работы вашего продукта, пока он активен (удалите их в течение 30 дней после окончания тарифа или купите Image Pack, чтобы сохранить набор навсегда). Сохраняйте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; подойдёт и любой hex-код по той же цене. Арендатор получит автомобиль того цвета, который есть на стоянке, — карточка цвет и не обещала.
- Что делать, если модели класса нет в каталоге?
- Если автомобиля нет в каталоге, API отвечает 404 с подсказками: ближайшими автомобилями из каталога, каждый со своим id. Используйте один из них или запросите автомобиль на публичной доске запросов. Каталог распространяется с открытым исходным кодом.