Car Image API

Clientes · Clasificados y catálogos de compra de coches

Cómo poner una imagen de estudio del vehículo en cada anuncio de un marketplace

Cómo los sitios de clasificados y los catálogos de compra de coches renderizan una imagen principal por año de modelo a escala de catálogo: ids de vehículo, encuadre, ritmo de solicitudes, caché y el código.

El problema: un anuncio necesita una imagen antes de que el vendedor suba una

Un sitio de clasificados o un catálogo de compra de coches vive o muere por su cuadrícula. Cada tarjeta necesita una imagen desde el momento en que existe el anuncio, y la foto del propio vendedor llega más tarde, si es que llega, desde un ángulo cualquiera y en una entrada de garaje cualquiera. La fotografía de archivo tiene el problema contrario: existe una foto de prensa con licencia para los coches populares de los años populares, con el ángulo y el fondo que eligió el fabricante, y para nada más. Un catálogo que abarca desde 1990 hasta el año de modelo actual tiene decenas de miles de huecos.

Lo que quieren los equipos que crean estos sitios es aburrido en el mejor sentido: una imagen de estudio por año de modelo, el mismo ángulo y la misma pintura para todas, transparente para que encaje sobre cualquier fondo de la tarjeta y lo bastante ligera para servirse diez mil veces al día.

Cómo es una integración de catálogo

Las integraciones de catálogo que funcionan hoy sobre la API tienen la misma forma, ya se trate de un sitio de clasificados que llena sus anuncios, una aplicación de compra de coches que renderiza sus tarjetas comparativas o una aplicación móvil que muestra una imagen principal por vehículo:

  • Una carga inicial y luego un goteo. Miles de renders en pocas horas para cubrir el catálogo y, después, unos pocos al día a medida que llegan nuevos años de modelo y nuevas solicitudes.
  • Un ángulo, una pintura o una paleta corta. La mayoría elige front-3-4 o side en plata o blanco. Un catálogo de compra que permite al usuario elegir un color genera unos cuantos colores predefinidos por vehículo; cada uno es una imagen de vehículo más, no un nuevo flujo de trabajo.
  • WebP en un recuadro fijo. De 512 a 1024 píxeles de ancho, entregado exactamente en el recuadro que usa la tarjeta, para que el front end nunca recorte ni añada bandas.
  • Almacenados por id de vehículo. Los renders se guardan en el almacenamiento de objetos o la CDN del propio equipo, o bien las páginas cargan URL firmadas; en ambos casos, la clave es el id estable veh_… del catálogo, no una cadena de marca-modelo-año.

El resto de esta página describe ese flujo, paso a paso, con el código. Se da por hecho que dispone de una clave de API con el alcance images:read y un plan dimensionado para el catálogo (consulte las preguntas frecuentes).

Paso 1: enumere el catálogo por id, nunca por cómo se escribe el nombre

El fallo más común al construir un catálogo no es el renderizado, es la ortografía. Una compilación que genera cadenas de marca y modelo a partir de otra base de datos puede gastar la mayoría de sus solicitudes en 404 vehicle_not_found: son gratuitas, pero cada una es un viaje de ida y vuelta desperdiciado, y deja una cuadrícula con huecos. La solución es dejar que el catálogo le diga qué existe. GET /api/v1/vehicles es gratuito, no necesita clave, y cada modelo que devuelve lleva un id de vehículo estable (veh_ más 13 caracteres) que nunca cambia entre despliegues ni versiones del catálogo. Guarde ese id en el anuncio y renderice a partir de él.

Recorrer un año de modelo
# every make with a 2024 model year (free, no key)
curl -s "https://carimage.dev/api/v1/vehicles?year=2024"

# every 2024 model of one make, each with the id you will store
curl -s "https://carimage.dev/api/v1/vehicles?year=2024&makeId=584"
200 OK (recortado)
{
  "data": {
    "year": 2024,
    "make_id": 584,
    "models": [
      {
        "name": "718",
        "slug": "718",
        "vehicle_type": "Passenger Car",
        "id": "veh_b4bf090fyb53k"
      },
      {
        "name": "911",
        "slug": "911",
        "vehicle_type": "Passenger Car",
        "id": "veh_78qtwrgh37bkr"
      }
    ]
  }
}

?make=porsche&model=911 lista todos los años de un modelo con un id por año, y ?q= busca texto libre cuando un vendedor escribe un nombre. El mismo catálogo se publica como el paquete abierto @meterapp/vehicle-db, de modo que los desplegables y la validación pueden funcionar sin conexión con la misma lista. En cualquier caso, al final de este paso tendrá una lista de ids, y nada posterior vuelve a escribir el nombre de un coche.

Los anuncios que ya nombran sus coches con la grafía de otra base de datos se asignan en una sola llamada: POST /api/v1/vehicles/check lee hasta 2000 de ellos como lo haría un render y responde a cada uno con su id de vehículo, los vehículos reales más cercanos cuando el catálogo no tiene ese coche, o un fallo que conviene omitir en todas las vistas y colores. car-image check listings.csv --out checked.csv escribe los id de vuelta en el archivo. Es gratuito y evita descubrir las carencias de un 404 en uno.

Paso 2: una misma forma de solicitud para cada anuncio

Defina la tarjeta una sola vez y codifíquela en la cadena de consulta. Todo lo que aparece después de vehicle= a continuación es una decisión de encuadre que toma una sola vez para todo el catálogo:

Una imagen de anuncio
curl --fail-with-body -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  "https://carimage.dev/api/v1/images/car?vehicle=veh_78qtwrgh37bkr&view=front-3-4&color=silver&w=800&h=600&fit=contain&trim=1&padding=8&format=webp" \
  -o veh_78qtwrgh37bkr.webp
  • w=800&h=600&fit=contain entrega exactamente 800×600 con el coche entero visible y relleno transparente alrededor, para que todas las tarjetas tengan el mismo lienzo. fit=cover, en cambio, llena el recuadro y recorta desde el centro.
  • trim=1&padding=8 recorta al contorno del coche antes de ajustarlo, con un margen del 8 % de su lado más largo, para que un Suburban y un Miata llenen el recuadro de la misma manera en lugar de flotar dentro del encuadre original.
  • color=silver es el valor predeterminado y el neutro más seguro; cualquiera de los 15 preajustes o cualquier color hexadecimal cuenta igual: una imagen de vehículo.
  • format=webp es la codificación con alfa sin pérdida más pequeña. Cuando un navegador carga la URL directamente (URL firmadas, paso 4), format=auto negocia WebP o PNG según el cliente.

La respuesta incluye ETag, X-Image-Source (cache o generated) y X-Vehicle-Id, el vehículo del catálogo que se sirvió. Guarde el ETag junto con el archivo: una solicitud posterior con If-None-Match responde 304 y no cuesta nada; así es como una resincronización nocturna sigue siendo gratuita.

Paso 3: dosifique la carga inicial dentro de los límites

Tres límites condicionan una carga masiva, y cada uno de ellos se anuncia en las cabeceras en lugar de fallar en silencio:

  • Solicitudes por minuto. 120 por clave en Free y Pro, 600 en Business, 1200 en Enterprise, además de un límite por cuenta que abarca todas las claves. Cada respuesta autenticada incluye RateLimit-Remaining; una 429 incluye Retry-After. De cuatro a ocho solicitudes simultáneas son más que suficientes.
  • Vistas de vehículo nuevas. La primera solicitud de una vista de vehículo que aún no hemos preparado tarda un poco mientras la preparamos para que se pueda mostrar en cualquier color; cada solicitud posterior, en cualquier color, se sirve desde la caché. Preparar vistas nuevas consume la parte que corresponde a la cuenta del presupuesto diario de renderizado (2 % en Free, 10 % en Pro, 25 % en Business, 50 % en Enterprise). Al superarla, un render nuevo responde 429 con code: account_generation_cap y reset_at (medianoche UTC), no se cobra nada y las imágenes en caché se siguen sirviendo. Una importación masiva grande lleva unas cuantas noches, no una sola.
  • Imágenes de vehículos al mes. Free incluye 100, Pro 2500, Business 10.000; Enterprise se negocia. Superada esa cuota, una solicitud de una imagen que aún no se ha contado este mes responde 402 (plan_image_limit) y no cuenta nada; una imagen ya contada este mes siempre se sirve, así que una cuadrícula en producción nunca se rompe.

Los fallos de renderizado (502) devuelven automáticamente su imagen de vehículo, las solicitudes simultáneas de la misma variante nueva comparten un único render y un GET simple se puede reintentar sin riesgo. El SDK reintenta los 429 y 503 por usted, respetando Retry-After, y nunca reintenta un 402.

Una carga masiva reanudable con el SDK de TypeScript
import { CarImageClient, CarImageError } from "@meterapp/car-image-sdk";

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

// One make, one model year: the ids are what you store and what you render by.
const { data } = await client.vehicles({ year: 2024, makeId: 584 });
const queue = data.models.flatMap((model) => (model.id ? [model.id] : []));

// Four in flight stays well inside 120 requests a minute, and a cold render
// that takes a few seconds never holds up the rest of the batch.
await Promise.all(
  Array.from({ length: 4 }, async () => {
    for (let id = queue.shift(); id; id = queue.shift()) {
      try {
        const image = await client.getImage({
          vehicle: id, view: "front-3-4", color: "silver",
          width: 800, height: 600, fit: "contain", trim: true, padding: 8, format: "webp",
        });
        await store(id, image.bytes, image.etag); // your object store or CDN, keyed by vehicle id
      } catch (error) {
        // 429 and 503 were already retried with Retry-After; a 404 is a vehicle to request, not a failure.
        if (error instanceof CarImageError && error.status === 404) continue;
        throw error;
      }
    }
  })
);

Paso 4: sírvala desde su CDN o mediante URL firmadas

Hay dos buenas formas de mostrar la imagen al comprador, y las integraciones de catálogo usan ambas:

  • Almacene los bytes. Guarde cada render en su propio almacenamiento de objetos o CDN bajo su id de vehículo y sírvalo como cualquier otro recurso. Es la respuesta correcta para una cuadrícula que se muestra millones de veces: ninguna llamada a nosotros por cada carga, y la licencia de un plan de pago cubre las copias que conserve para servir su producto.
  • Genere URLs firmadas. POST /api/v1/image-urls admite hasta cincuenta imágenes por llamada, cuenta la imagen de cada URL como una imagen de vehículo del mes cuando se genera y devuelve URLs sin clave que el navegador carga directamente. Configure ttl_seconds hasta siete días; añada renew: true para páginas de anuncios que duren más (una renovación cuenta la imagen una vez en el mes en que ocurre, y nada más si ya se contó ese mes). Restrinja la clave a los orígenes de su sitio en el panel y una URL copiada en otro lugar responderá 403.

Envíe una Idempotency-Key por cada página de anuncios cuando genere URL por lotes: una llamada reintentada con la misma clave y el mismo cuerpo reproduce la primera respuesta y no vuelve a contar nada.

listings.json — de cincuenta en cincuenta, con el encuadre del paso 2
{
  "images": [
    {
      "vehicle": "veh_78qtwrgh37bkr",
      "view": "front-3-4",
      "color": "silver",
      "width": 800,
      "height": 600,
      "fit": "contain",
      "trim": true,
      "padding": 8,
      "format": "auto"
    },
    {
      "vehicle": "veh_b4bf090fyb53k",
      "view": "front-3-4",
      "color": "silver",
      "width": 800,
      "height": 600,
      "fit": "contain",
      "trim": true,
      "padding": 8,
      "format": "auto"
    }
  ]
}

Cuando un vehículo no está en el catálogo

Busque primero: GET /api/v1/vehicles?q= encuentra un modelo por nombre, prefijo o coincidencia aproximada, y POST /api/v1/images/resolve convierte una frase de texto libre en parámetros exactos con un nivel de confianza sobre el que puede actuar. Lo que aún falte después va al tablero de solicitudes: POST /api/v1/requests crea la solicitud o, si ya existe una abierta para la misma marca, modelo y año, le suma un voto en lugar de duplicarla. El catálogo en sí es de código abierto, y las incorporaciones llegan a todos los clientes.

CLI, SDK y MCP

Todo el flujo se ejecuta desde la CLI sin nada de código, que es como se pobló más de un catálogo en la API:

npx @meterapp/car-image
# One file per vehicle id. Re-running skips what exists, so a stopped backfill resumes.
while read -r id; do
  [ -f "cdn/$id.webp" ] || npx @meterapp/car-image get --vehicle "$id" \
      --view front-3-4 --color silver --width 800 --height 600 --fit contain \
      --trim --padding 8 --format webp --out "cdn/$id.webp"
done < vehicle-ids.txt

# Or fifty signed URLs in one call, for a page of listings the browser loads itself.
npx @meterapp/car-image url --batch listings.json --ttl 604800 --renew --json
  • SDK: client.vehicles({ year, makeId }) para enumerar, client.getImage({ vehicle, … }) para renderizar y client.createImageUrls(…) para lotes de URL firmadas. Consulte la documentación de imágenes para ver todos los parámetros.
  • MCP: un asistente conectado a https://carimage.dev/api/mcp tiene el mismo catálogo (search_vehicles, resolve_vehicle) y los mismos renders (get_car_image, create_car_image_urls), lo que lo convierte en la herramienta adecuada para un curador que añade un vehículo a mano, y en la equivocada para un relleno masivo de miles: use la CLI o el SDK para eso y reserve el asistente para los casos pendientes. La configuración está en la página de MCP.

Preguntas frecuentes

¿Qué ángulo debería usar un anuncio?
front-3-4 es el ángulo predeterminado y el clásico ángulo principal, con el frontal hacia la izquierda. Cada ángulo del lado izquierdo del coche tiene un gemelo -right (front-3-4-right, side-right, rear-3-4-right), para que una tarjeta mire hacia el interior del diseño en lugar de hacia fuera. Elija uno y manténgalo: la coherencia entre anuncios es la mayor parte del valor.
¿Cuánto cuesta un catálogo de 20.000 anuncios?
20.000 imágenes de vehículo al mes si cada anuncio muestra un vehículo en un color y una vista, cada una entregada tantas veces como haga falta y en cualquier tamaño; los anuncios que comparten vehículo, color y vista son una sola imagen, y volver a comprobar con If-None-Match es gratis. Pro incluye 2500 imágenes de vehículo al mes y Business 10.000, así que un catálogo de ese tamaño corresponde a Enterprise, o a un Image Pack de pago único que conserva y aloja usted mismo para siempre. Una carga retroactiva que supere el cupo responde 402 y no contabiliza nada.
¿Podemos alojar los archivos en nuestra propia CDN?
Sí. Un plan de pago le otorga licencia sobre los renders para usarlos dentro de su producto, incluidas las copias en sus propios servidores o CDN y sin atribución, mientras el plan esté activo; en los 30 días posteriores a su finalización, las copias almacenadas se eliminan (las imágenes de un Image Pack pueden conservarse para siempre). Lo que la licencia no permite es ofrecerlas como biblioteca, feed o conjunto de datos independiente. Un plan activo es lo que le permite generar los renders del siguiente año de modelo.
¿Qué ocurre cuando el catálogo incorpora un nuevo año de modelo?
El catálogo @meterapp/vehicle-db se actualiza a medida que las fuentes publican, y los ids existentes nunca cambian. Enumere el nuevo año, renderice los ids que aún no tenga y no toque el resto. Las solicitudes llevan un ETag; una solicitud repetida con If-None-Match responde 304 y no cuesta nada.
¿Por qué algunas de nuestras cadenas de marca y modelo devuelven 404?
Porque los escribió otra base de datos. El catálogo acepta nombres, slugs y muchas variantes de insignias y tipos de carrocería, pero una cadena que nunca ha visto devuelve un 404 vehicle_not_found (gratis, pero es un viaje de ida y vuelta desperdiciado). Recorra el catálogo y guarde sus ids en lugar de traducir sus propias cadenas, y busque o resuelva los casos restantes.