Car Image API

Clientes · Herramientas para concesionarios, importación y VIN

Cómo convertir un VIN o una hoja de inventario en una foto para cada vehículo en el software de concesionarios

Cómo las herramientas para concesionarios e importadores pasan de un VIN o una línea de la hoja de inventario a una imagen de estudio en cada registro: decodificación de VIN gratuita, resolve, ids estables y URL firmadas.

El problema: la ficha tiene un VIN meses antes de tener una foto

Un registro de inventario en un CRM, un ERP o un sistema de gestión de concesionarios (DMS) nace como un VIN, un número de stock y un precio. La foto llega cuando llega el fotógrafo del concesionario, y para algunas unidades nunca llega: un vehículo en tránsito, una permuta que aún se está reacondicionando, una importación cuyo nombre de modelo no coincide con nada en el feed de imágenes del DMS, un coche de los años noventa del que nadie licenció una foto de prensa. Cada pantalla que muestra ese registro (la lista del vendedor, la tasación del comprador, el presupuesto del cliente) muestra en su lugar un marcador de posición gris.

Las herramientas para concesionarios e importadores de la API rellenan ese marcador de posición con lo que el registro ya contiene. Si tiene un VIN, la imagen está a una decodificación gratuita de distancia. Si solo tiene una línea en una hoja de inventario, la resolución por texto libre llega hasta ella. En cualquier caso, el registro termina guardando un id de vehículo estable, y todas las pantallas muestran el mismo coche de la misma forma.

Cómo es una integración para concesionarios

  • Decodifique al dar de alta. El VIN se decodifica una sola vez, al crear el registro, y el id del vehículo del catálogo se guarda junto a él. Nada posterior escribe una marca o un modelo.
  • Una vista para la lista, otra para el detalle. Un side recto en un recuadro ancho para las listas de inventario; front-3-4 para la página de detalle y el presupuesto.
  • Años de sobra. El stock importado y de ocasión se remonta a los años 90, y se renderiza igual que las novedades: el catálogo abarca desde 1990 hasta el año de modelo actual, incluidos los modelos del mercado doméstico japonés.
  • URL firmadas dentro de la aplicación. El CRM es un navegador, así que carga URL firmadas sin clave generadas por el servidor, hasta cincuenta por llamada, que se renuevan para las fichas que duran más de una semana.

Paso 1: decodifique el VIN, gratis

GET /api/v1/vin/{vin} no cuesta nada y solo necesita una clave de API. Devuelve el año, la marca, el modelo, la versión, el tipo de carrocería y el motor decodificados, además de cualquier otro atributo que conozcan los datos vPIC de la NHTSA y, cuando el catálogo tiene el vehículo, un objeto vehicle con su id estable y un image_path listo para usar. También funcionan los VIN parciales: al menos cinco caracteres, * para cada posición desconocida y, opcionalmente, una pista de year.

Decodificar
curl -s -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/vin/1HGCM82633A004352"
200 OK (recortado)
{
  "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…"
}

Paso 1b: cuando solo tiene una línea en una hoja de inventario

El stock de importación suele llegar como hoja de cálculo: un año, una marca, un nombre de modelo con la ortografía que haya usado la casa de subastas, un código de grado o acabado. POST /api/v1/images/resolve es gratuito y determinista: extrae de la frase las palabras de año, color y vista, busca en el catálogo con lo que queda y devuelve parámetros exactos con un nivel de confianza sobre el que puede actuar.

Resolver una línea de la hoja de inventario
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 (recortado)
{
  "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…"
}

El vehículo es correcto (el Toyota Voxy de 2019), pero la confianza es low, porque «ZS» es un acabado que el catálogo no conoce y hubo que hacer la coincidencia sin él. En una importación por lotes, considere high como resuelto y ponga medium y low delante de una persona con la lista candidates. Cuando la hoja ya tiene el año y la marca en sus propias columnas, envíelos en los campos year y make y deje solo el modelo en query; la coincidencia será mucho más limpia. Una frase sin palabras relativas a vehículos es un 400, y una marca sin ningún modelo coincidente es un 404 que enumera los años de la marca para que pueda pedir el modelo.

Paso 2: guarde el id del vehículo en el registro

Sea cual sea la ruta que le llevó hasta aquí, guarde vehicle.id (o params.vehicle_id) en el registro de inventario como una columna de texto simple. Es determinista y permanente: el mismo vehículo tiene el mismo id en cada despliegue y tras cada versión del catálogo, así que es seguro como clave foránea. A partir de ahí, cada solicitud de imagen es vehicle=veh_…, que no se puede escribir mal, y una marca que el fabricante renombre o que una fuente reclasifique nunca rompe una URL guardada.

Paso 3: una vista para el listado y otra para la página de detalle

Las listas de inventario son anchas y bajas, así que la vista lateral recta en una caja 2:1 es la opción habitual: todas las unidades miran hacia el mismo lado y se apoyan en la misma línea base. trim=1&padding=6 recorta al coche antes de encajarlo, de modo que un Hilux y un Yaris llenan la fila igual; fit=contain mantiene el lienzo en exactamente 640×320 con márgenes transparentes. La página de detalle usa front-3-4 a 1024, y ambas comparten caché: una pintura que no especifique es plateada en las dos.

La imagen de listado para un registro
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

Paso 4: mostrarlas en el CRM mediante URL firmadas

El CRM se ejecuta en un navegador, y un navegador nunca debe contener la clave de API. Cuando una pantalla muestra una página de inventario, el servidor genera una URL firmada por registro con POST /api/v1/image-urls (hasta cincuenta por llamada, un crédito cada una) y la página las carga como cualquier otra imagen. Hay dos ajustes importantes para un registro que permanece en inventario durante meses:

  • ttl_seconds: 604800 con renew: true: la URL sigue funcionando después del TTL de siete días, y cada semana adicional en la que alguien realmente abre la ficha cuesta un crédito más. Las semanas en que nadie mira el coche no cuestan nada.
  • Una Idempotency-Key por cada página de la sincronización: una solicitud reintentada reproduce la primera respuesta y no genera nada dos veces.

Restrinja la clave que genera las URL al origen del CRM en el panel, y una URL que se filtre a otro sitio responderá 403. Revocar la clave invalida todas las URL que haya generado. Si el saldo llega a agotarse, una renovación responde 402 y la misma URL vuelve a funcionar en cuanto llegan los créditos; la recarga automática elimina ese modo de fallo. El ciclo de vida completo está en la documentación de URL firmadas.

Recepción y lista de inventario, con el SDK de TypeScript
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 y 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, … }) y client.createImageUrls(…), como arriba.
  • MCP: decode_vin, resolve_vehicle, get_car_image y create_car_image_urls forman parte del conjunto de herramientas principal, así que un asistente con el sistema de inventario en contexto puede responder "foto de la unidad 4471" a partir del VIN del registro. La configuración está en la página de MCP; los campos y errores del decodificador están en la documentación de VIN.

Preguntas frecuentes

¿Cuánto cuesta tener una foto en cada registro de inventario?
La decodificación del VIN es gratuita. La primera imagen de un vehículo, vista y pintura cuesta un crédito y, a partir de ahí, queda en caché para todos; volver a comprobarla con If-None-Match es gratis. Una URL firmada cuesta un crédito al generarse y, con renew: true, un crédito más por cada semana adicional en la que realmente se abra. Un grupo de concesionarios con unos pocos miles de unidades en stock gasta unos pocos miles de créditos una vez y, después, casi nada.
El VIN se decodifica, pero vehicle es null. ¿Y ahora qué?
El decodificador conocía la marca, el modelo y el año, pero el catálogo no tiene ninguna entrada para esa combinación: un remolque, algunos chasis comerciales, un modelo que las fuentes aún no han registrado. Muestre los campos decodificados, busque en el catálogo con GET /api/v1/vehicles?q= por si la grafía difiere y solicite el vehículo en el tablón de solicitudes; POST /api/v1/requests vota a favor de una solicitud abierta en lugar de duplicarla.
¿La decodificación de VIN cubre importaciones y vehículos que nunca se vendieron en EE. UU.?
El decodificador usa los datos vPIC de la NHTSA, así que un VIN de un fabricante que reporta a la NHTSA se decodifica por completo. Un vehículo nunca certificado para EE. UU. a menudo se decodifica como un fabricante y un año sin modelo, y algunos no se decodifican en absoluto. Para ese inventario, resuélvalo a partir del documento de matriculación: el catálogo en sí es mundial, desde 1990, e incluye modelos del mercado doméstico japonés como el Toyota Voxy.
¿El render muestra la versión que figura en el registro?
No. El catálogo se basa en marca, modelo y año, así que un cupé EX-V6 y un sedán LX se renderizan como el mismo Accord de 2003. Conserve trim y body_class de la decodificación como texto junto a la imagen y nunca describa el render como la unidad concreta.
¿Puede el sitio web del concesionario usar las mismas URL que el CRM?
Genérelas con una clave cuyos orígenes permitidos incluyan el sitio, y una URL que un navegador cargue desde cualquier otro sitio responderá 403 origin_not_allowed. Las cargas sin Referer, como las de un cliente de correo, se permiten. El CRM y el sitio web pueden compartir una clave y un conjunto de URL, o usar una clave cada uno para poder revocar cualquiera de ellas por separado.