Car Image API

Клиенты · Инструменты для дилеров, импорта и VIN

Как получить фото каждого автомобиля в дилерском ПО по VIN или складской таблице

Как инструменты для дилеров и импорта получают из VIN или строки складской ведомости студийное изображение для каждой записи: бесплатная расшифровка VIN, resolve, постоянные id и подписанные URL.

Проблема: VIN в записи появляется за несколько месяцев до фотографии

Запись об автомобиле в наличии в CRM, ERP или системе управления дилерским центром (DMS) начинается с VIN, складского номера и цены. Фото появляется, когда приходит фотограф площадки, а для некоторых машин не появляется вовсе: автомобиль в пути, машина, сданная в трейд-ин и ещё проходящая предпродажную подготовку, импортный автомобиль, название модели которого не совпадает ни с чем в фиде изображений DMS, машина 1990-х, на пресс-фото которой никто не покупал лицензию. На каждом экране с этой записью — в списке продавца, в оценке у закупщика, в предложении клиенту — вместо фото серая заглушка.

Инструменты для дилеров и импорта, работающие на API, заполняют эту заглушку тем, что уже есть в записи. Если в ней есть VIN, до изображения — одно бесплатное декодирование. Если есть только строка в складской ведомости, поможет resolve по свободному тексту. В любом случае в записи оказывается постоянный id автомобиля, и на каждом экране один и тот же автомобиль выглядит одинаково.

Как выглядит интеграция для дилера

  • Расшифровка при поступлении. VIN расшифровывается один раз, при создании записи, и id автомобиля из каталога сохраняется рядом с ним. Дальше по цепочке марка и модель нигде не пишутся текстом.
  • Один ракурс для списка, другой для карточки. Прямой side в широкой рамке для списков автомобилей в наличии; front-3-4 для страницы автомобиля и коммерческого предложения.
  • Глубокий охват по годам. Импортные и подержанные автомобили уходят в 1990-е, и они рендерятся так же, как новые поступления: каталог охватывает период с 1990 по текущий модельный год, включая модели для внутреннего японского рынка.
  • Подписанные URL внутри приложения. CRM работает в браузере, поэтому загружает подписанные URL без ключа, выпущенные сервером, — до пятидесяти за вызов — и обновляет их для записей, которые живут дольше недели.

Шаг 1: бесплатно расшифруйте VIN

GET /api/v1/vin/{vin} бесплатен, и для него нужен только API-ключ. Он возвращает расшифрованные год, марку, модель, комплектацию, тип кузова, двигатель и все остальные атрибуты, известные данным vPIC от NHTSA, а если автомобиль есть в каталоге, то и объект vehicle с его постоянным id и готовым image_path. Частичные VIN тоже подходят: не менее пяти символов, * на каждой неизвестной позиции и необязательная подсказка year.

Декодирование
curl -s -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/vin/1HGCM82633A004352"
200 OK (сокращено)
{
  "data": {
    "vin": "1HGCM82633A004352",
    "valid": true,
    "year": 2003,
    "make": "Honda",
    "model": "Accord",
    "trim": "EX-V6",
    "body_class": "Coupe",
    "vehicle": {
      "id": "veh_3qfyk22gfhsx3",
      "make": "Honda",
      "model": "Accord",
      "year": 2003,
      "image_path": "/api/v1/images/car?vehicle=veh_3qfyk22gfhsx3"
    }
  },
  "request_id": "req_01j9x…"
}

Шаг 1b: когда у вас есть только строка в складской ведомости

Импортные автомобили часто поступают в виде таблицы: год, марка, название модели в том написании, которое использовал аукцион, код комплектации или грейда. POST /api/v1/images/resolve бесплатен и детерминирован: он извлекает из фразы слова, обозначающие год, цвет и ракурс, ищет по каталогу по оставшейся части и возвращает точные параметры с уровнем уверенности, на который можно опираться.

Сопоставление строки складского списка
curl -s -X POST https://carimage.dev/api/v1/images/resolve \
  -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "2019 toyota voxy zs side"}'
200 OK (сокращено)
{
  "data": {
    "params": {
      "vehicle_id": "veh_9w0nvw7jphp6r",
      "make": "toyota",
      "model": "voxy",
      "year": 2019,
      "view": "side",
      "color": "silver"
    },
    "display": {
      "make_name": "TOYOTA",
      "model_name": "VOXY"
    },
    "confidence": "low",
    "image_path": "/api/v1/images/car?make=toyota&model=voxy&year=2019&view=side&color=silver"
  },
  "request_id": "req_01j9x…"
}

Автомобиль определён верно (Toyota Voxy 2019 года), но уверенность — low, потому что «ZS» — это комплектация, которую каталог не знает, и её пришлось обойти при сопоставлении. При пакетном импорте считайте high готовым результатом, а medium и low передавайте человеку вместе со списком candidates. Если в таблице год и марка уже указаны в отдельных столбцах, передавайте их в полях year и make, а в query оставляйте только модель — сопоставление станет намного точнее. Фраза без слов, относящихся к автомобилю, возвращает 400, а марка без подходящей модели — 404 со списком годов этой марки, чтобы вы могли уточнить модель.

Шаг 2: сохраните id автомобиля в записи

Каким бы путём вы к нему ни пришли, сохраните vehicle.id (или params.vehicle_id) в записи складского автомобиля как обычный строковый столбец. Он детерминирован и постоянен: у одного и того же автомобиля один и тот же id при каждом развёртывании и после каждого релиза каталога, поэтому его можно безопасно использовать как внешний ключ. С этого момента каждый запрос изображения — это vehicle=veh_…, где невозможно допустить опечатку, а марка, переименованная производителем или иначе заведённая источником, никогда не сломает сохранённый URL.

Шаг 3: один ракурс для списка, другой для страницы с подробностями

Списки автомобилей в наличии широкие и невысокие, поэтому обычно выбирают прямой вид сбоку в рамке 2:1: каждый автомобиль смотрит в одну сторону и стоит на одной базовой линии. trim=1&padding=6 обрезает изображение по автомобилю перед вписыванием, поэтому Hilux и Yaris заполняют строку одинаково; fit=contain сохраняет холст ровно 640×320 с прозрачными полями. На странице с подробностями используется front-3-4 размером 1024, и у обоих общий кеш: если цвет не указан, он серебристый в обоих случаях.

Изображение для списка по одной записи
curl --fail-with-body -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/images/car?vehicle=veh_3qfyk22gfhsx3&view=side&w=640&h=320&fit=contain&trim=1&padding=6&format=webp" \
  -o stock-4471.webp

Шаг 4: показывайте изображения в CRM через подписанные URL

CRM работает в браузере, а в браузере никогда не должен храниться API-ключ. Когда на экране отображается страница складских позиций, сервер создаёт по одному подписанному URL на запись с помощью POST /api/v1/image-urls (до пятидесяти за вызов; изображение каждого URL засчитывается как изображение автомобиля за месяц), и страница загружает их как обычные изображения. Для записи, которая месяцами остаётся в наличии, важны две настройки:

  • ttl_seconds: 604800 с renew: true: URL продолжает работать после семидневного TTL, а продление засчитывает изображение один раз в месяце, на который оно приходится, и ничего сверх, если оно уже было учтено в этом месяце. Месяцы, когда автомобиль никто не смотрит, не учитываются.
  • Отдельный Idempotency-Key для каждой страницы синхронизации: повторный запрос воспроизводит первый ответ и ничего не выпускает дважды.

Ограничьте ключ, выпускающий URL, источником (origin) CRM в панели управления — и URL, попавший на другой сайт, вернёт 403. Отзыв ключа аннулирует все выпущенные им URL. Если изображения автомобилей по тарифу на месяц израсходованы, продление вернёт 402, а тот же URL снова заработает после сброса лимита или повышения тарифа. Полный жизненный цикл описан в документации по подписанным URL.

Приёмка и складской список с TypeScript SDK
import { CarImageClient } from "@meterapp/car-image-sdk";

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

// On intake: VIN in, vehicle id on the record. Free.
const { data: decoded } = await client.decodeVin(stock.vin);
if (decoded.vehicle) {
  stock.vehicleId = decoded.vehicle.id; // veh_…, permanent; the record never spells a car again
  stock.trim = decoded.trim;            // shown next to the image, never claimed by it
}

// When the CRM draws the stock list: one signed URL per record, up to fifty per call.
// The browser loads them; the key never leaves the server.
const { data: urls } = await client.createImageUrls(
  page.map((row) => ({
    vehicle: row.vehicleId, view: "side",
    width: 640, height: 320, fit: "contain", trim: true, padding: 6, format: "auto",
  })),
  { ttlSeconds: 604_800, renew: true, renewDays: 365, idempotencyKey: `stock-list:${syncRunId}:${pageIndex}` }
);

CLI, SDK и MCP

npx @meterapp/car-image
# decode for free; the output names the vehicle id and a ready-to-run image command
npx @meterapp/car-image vin 1HGCM82633A004352
npx @meterapp/car-image vin 1HGCM82633A004352 --json | jq -r .data.vehicle.id

# a partial VIN from a faded door sticker: at least five characters, * for each unknown position
npx @meterapp/car-image vin "1HGCM826*3A" --year 2003

# the list image for one record
npx @meterapp/car-image get --vehicle veh_3qfyk22gfhsx3 --view side --width 640 --height 320 --fit contain --trim --padding 6 --format webp --out stock-4471.webp
  • SDK: client.decodeVin(vin, { year? }), client.resolve(query), client.getImage({ vehicle, … }) и client.createImageUrls(…), как показано выше.
  • MCP: decode_vin, resolve_vehicle, get_car_image и create_car_image_urls входят в базовый набор инструментов, поэтому ассистент, у которого в контексте есть складская система, может ответить на запрос «фото для позиции 4471» по VIN из записи. Настройка описана на странице MCP; поля и ошибки декодера — в документации по VIN.

Часто задаваемые вопросы

Сколько стоит фото для каждого автомобиля в наличии?
Декодирование VIN бесплатно. Каждый автомобиль в каждом цвете окраски и ракурсе — это одно изображение автомобиля, которое учитывается один раз в месяц, как бы часто и в каком бы размере его ни показывали; повторная проверка через If-None-Match бесплатна. Подписанный URL засчитывает своё изображение при создании и, с renew: true, ещё раз в каждом последующем месяце, в котором его открывают. Дилерская группа с несколькими тысячами автомобилей на складе показывает несколько тысяч изображений автомобилей в месяц, поэтому подбирайте тариф под количество выставленных автомобилей.
VIN декодируется, но vehicle равен null. Что делать?
Декодер определил марку, модель и год, но в каталоге нет записи для этого сочетания: прицеп, некоторые коммерческие шасси, модель, которую источники ещё не внесли. Покажите декодированные поля, поищите в каталоге через GET /api/v1/vehicles?q= на случай, если написание отличается, и запросите автомобиль на доске запросов; POST /api/v1/requests добавляет голос к открытому запросу, а не создаёт дубликат.
Охватывает ли декодирование VIN импортные автомобили и машины, никогда не продававшиеся в США?
Декодер использует данные vPIC от NHTSA, поэтому VIN производителя, который подаёт данные в NHTSA, расшифровывается полностью. Автомобиль, никогда не сертифицированный для США, часто расшифровывается лишь до производителя и года без модели, а некоторые не расшифровываются вовсе. Для таких автомобилей определяйте модель по регистрационному документу: сам каталог охватывает весь мир начиная с 1990 года, и в нём есть модели японского внутреннего рынка, например Toyota Voxy.
Показывает ли рендер комплектацию, указанную в записи?
Нет. Каталог ориентируется на марку, модель и год, поэтому купе EX-V6 и седан LX отображаются как один и тот же Accord 2003 года. Храните trim и body_class из расшифровки VIN как текст рядом с изображением и никогда не выдавайте рендер за изображение конкретного экземпляра.
Может ли сайт дилера использовать те же URL, что и CRM?
Создавайте их ключом, в списке разрешённых источников (allowed origins) которого указан сайт, — тогда URL, загруженный браузером с любого другого сайта, вернёт 403 origin_not_allowed. Загрузки без Referer, например из почтового клиента, проходят. CRM и сайт могут использовать один ключ и один набор URL или отдельный ключ каждый, чтобы любой из них можно было отозвать независимо.