Un guide d’intégration rédigé à partir du comportement documenté de l’API ; il ne cite aucun client. Publié le .
Le problème : la vente commence avant les photos
Un catalogue de vente aux enchères est mis en ligne dès que les véhicules sont consignés : un VIN, un numéro de lot et une date de vente pour chaque voiture. Les photos arrivent quand la voiture atteint le parc et que le photographe atteint la voiture, ce qui, pour une partie de la vente, se produit après l'ouverture des enchères. D'ici là, chacun de ces lots n'est qu'un carré gris à côté d'une ligne de texte.
Un rendu catalogue remplit l’emplacement avec la bonne année-modèle. Mais une vente aux enchères est aussi précisément l’endroit où un rendu ne doit jamais passer pour la voiture : les enchérisseurs évaluent l’état, et un rendu n’en montre aucun, car il ne représente aucun véhicule physique spécifique. Tout ce qui suit découle de la nécessité de concilier ces deux réalités.
À quoi ressemble l’intégration
- Un rendu par lot à partir de son VIN, affiché uniquement jusqu’à l’arrivée des photos du lot.
- Un sélecteur de catalogue pour les lots dont le VIN ne se décode pas.
- Une mention sur l’image : « Rendu du catalogue, pas ce lot ».
- Une URL par lot, générée une seule fois sous une
Idempotency-Key, valable aussi longtemps que la vente.
Étape 1 : du VIN du lot à un identifiant de véhicule
GET /api/v1/vin/{vin} est gratuit. Lorsque le catalogue contient le véhicule, la réponse inclut data.vehicle.id, l’identifiant stable à stocker sur le lot ; la finition, la carrosserie et le moteur décodés restent dans le texte du lot. Le catalogue couvre les années 1990 à 2027, si bien que les véhicules les plus anciens d’une vente aux enchères ont un rendu comparable aux plus récents. Le guide assurance détaille un décodage champ par champ, et la documentation VIN traite des VIN partiels et des erreurs.
# 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'Étape 2 : pas de VIN décodable ? Choisissez le véhicule dans le catalogue
Certains lots arrivent sans VIN décodable : un véhicule construit pour un autre marché, un VIN mal saisi par la source, une fiche de dépôt avec une année, une marque, un modèle et rien d'autre. Dotez le formulaire de dépôt de trois listes déroulantes alimentées par GET /api/v1/vehicles, gratuit et public : ?year= liste les marques ayant un modèle cette année-là, et ?year=&makeId= liste les modèles de cette marque, chacun avec l'identifiant de véhicule de cette année-modèle.
# 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"
},
"…"
]
}
}Ce même catalogue est disponible sous la forme du package open source @meterapp/vehicle-db : les listes déroulantes peuvent donc aussi fonctionner hors ligne sur une liste identique. Dans les deux cas, le lot contient le même type d’identifiant qu’un VIN décodé, et rien en aval n’a besoin d’écrire le nom d’une voiture en toutes lettres.
Lorsqu’une feuille de dépôt complète arrive d’un coup, POST /api/v1/vehicles/check lit jusqu’à 2 000 entrées par appel, chacune telle que la feuille l’orthographie et avec le numéro de lot comme ref, et répond pour chacune : une correspondance avec l’identifiant à stocker, des suggestions, une absence de résultat ou une ligne invalide. Rien n’est rendu et rien n’est facturé ; la documentation vehicles donne tous les détails.
Étape 3 : indiquer clairement que le rendu est un rendu
Placez la mention sur l'image elle-même, là où se pose le regard de l'enchérisseur, et dans le texte alternatif, pas seulement dans la description en dessous. L'état, le kilométrage, les dommages, les options et la peinture réelle du véhicule relèvent du texte du lot et, dès qu'elles existent, des photos. Quand les photos arrivent, le rendu disparaît.
<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>Étape 4 : une URL par lot, générée une seule fois
Générez l’URL du lot lors de son enregistrement avec POST /api/v1/image-urls et une Idempotency-Key construite à partir de la vente et du lot, composée de lettres, de chiffres, de ., _, : et -. L’URL est facturée au moment de sa génération (1 crédit) : sans clé, un enregistrement relancé générerait et paierait donc deux fois l’URL. Avec une clé :
- La même clé avec le même corps dans un délai de 24 heures rejoue la première réponse, URL comprise, avec
Idempotent-Replayed: trueet sans seconde facturation. - La même clé avec un corps différent renvoie une
422, et une nouvelle tentative qui devance la première requête renvoie une409avec un en-têteRetry-After. Fixez donc tout le contenu du corps, durée de vie comprise, au moment de la création du lot, et stockez-le avec le lot. - Enregistrez aussi l'URL sur le lot : la clé protège les nouvelles tentatives, et l'URL enregistrée est celle que les pages lisent pendant le reste de la vente.
Un catalogue entier importé d'un coup peut générer jusqu'à 50 lots par appel, avec une clé par envoi groupé ; chaque URL de la réponse reprend le véhicule et les options pour lesquels elle a été générée.
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Étape 5 : adaptez la durée de vie de l’URL à la vente
ttl_seconds peut aller jusqu’à 604800 (7 jours) ; une valeur supérieure est ramenée à ce maximum. Pour une vente qui se clôture dans la semaine, définissez-le sur le temps restant jusqu’à la clôture. L’image cesse alors de fonctionner en même temps que les enchères, et l’URL renvoie ensuite 403.
- Une vente chronométrée de plus de 7 jours : générez l’URL avec
renew: true,ttl_secondsau maximum etrenew_dayscouvrant toute la vente. Chaque semaine supplémentaire où le lot est consulté coûte 1 crédit, les semaines sans consultation ne coûtent rien, et le renouvellement s’arrête àrenews_until. - Laissez
max_usesà 0, la valeur par défaut : une URL illimitée peut être mise en cache publiquement pendant toute sa durée de vie, alors qu'une URL plafonnée estprivate, no-storeet renvoie chaque chargement vers l'origine. - Restreignez la clé d’émission aux domaines de votre site d’enchères dans le tableau de bord : une image de lot copiée sur un autre site renvoie
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 arriveAnticipez le volume de la vente
Chaque lot est un véhicule distinct, sauf si deux lots partagent la même marque, le même modèle et la même année, et chaque forfait plafonne le nombre de véhicules distincts par mois : Free 100, Pro 2 500 et Business 15 000 ; aucun plafond pour Enterprise. Un véhicule déjà servi ce mois-ci est toujours autorisé, et un envoi groupé qui dépasserait le plafond est refusé en entier, avant toute facturation, avec le forfait et le plafond indiqués dans la réponse. Dimensionnez le forfait selon les lots que vous mettez en vente en un mois, pas selon les crédits. Le cas d’usage des places de marché explique comment cadencer un import volumineux dans le respect des limites de débit et de rendu.
Questions fréquentes
- Le rendu peut-il rester en ligne une fois les photos du lot arrivées ?
- Remplacez-le. Le rendu tient lieu d’image provisoire pour le millésime, et un enchérisseur ne devrait jamais avoir à se demander quelle image montre la voiture mise en vente. Si une page le conserve à titre de référence, le libellé l’accompagne.
- Que devient l’URL après la vente ?
- Elle expire à la fin de sa durée de vie, ou lorsqu’une URL renouvelable atteint la fin de son renouvellement, et renvoie alors 403. D’ici là, le lot dispose de ses propres photos ou d’un résultat, et l’archive de la vente doit montrer les photos. Révoquer la clé qui a généré les URL les invalide toutes d’un coup.
- Une nouvelle tentative a renvoyé 422. Pourquoi ?
- La même Idempotency-Key est revenue avec un corps différent. La cause habituelle : une durée de validité recalculée à partir de l'horloge au moment de la nouvelle tentative. Fixez la durée de validité à la création du lot et enregistrez-la : la nouvelle tentative enverra alors le même corps et rejouera la première réponse.
- Le rendu peut-il montrer la teinte du lot ?
- Oui : color accepte n’importe quel nom prédéfini ou une valeur hexadécimale, pour que l’image corresponde à la peinture indiquée sur le bordereau de dépôt-vente, sans coût supplémentaire. Il s’agit toujours du modèle dans cette teinte, pas du lot lui-même : la mention reste donc affichée.
- Combien coûte une vente de 400 lots ?
- 400 crédits : 1 crédit par lot lorsque son URL est générée, et une génération relancée ne coûte rien. Chaque chargement pendant la durée de validité de l’URL est gratuit. Les forfaits plafonnent le nombre de véhicules distincts par mois (Free 100, Pro 2 500 et Business 15 000 ; aucun plafond pour Enterprise), et les lots qui partagent la même marque, le même modèle et la même année ne comptent qu’une fois.