Un guide d’intégration rédigé à partir du comportement documenté de l’API ; il ne cite aucun client. Publié le .
Le problème : vous louez une catégorie, pas une voiture
Un client de location réserve une catégorie (citadine compacte, SUV intermédiaire, monospace) et repart avec n’importe quelle voiture de cette catégorie disponible sur le parc. La page de réservation a tout de même besoin d’une image pour chaque catégorie, et l’usage veut un modèle représentatif accompagné de la mention « ou similaire ».
Ces images proviennent généralement de partout où l’on a pu les trouver : une photo presse ici, une photo de concessionnaire là, des angles différents, des arrière-plans différents, des voitures qui occupent leur carte différemment. Une grille constituée ainsi a l’air rafistolée. Ce qu’il faut à une page de flotte, c’est l’inverse : chaque catégorie représentée de la même manière, pour que seule la voiture change d’une carte à l’autre.
À quoi ressemble l’intégration
- Un modèle représentatif par catégorie, conservé sous forme d’identifiant de véhicule du catalogue, avec « ou similaire » dans le libellé et jamais dans l’image.
- Une seule forme de requête pour chaque fiche : la même vue, le même cadre, le même ajustement, le même recadrage, la même marge, la même peinture, le même arrière-plan et le même format.
- Deux images par catégorie au maximum : la carte dans la grille et l’image principale sur la page de la catégorie.
- Mis en cache, car la grille est la même pour chaque visiteur : fichiers sur votre CDN, ou URL signées émises une fois et réutilisées.
Étape 1 : choisissez un modèle représentatif par catégorie, par identifiant
Choisissez le modèle sous lequel chaque catégorie est commercialisée et recherchez son année-modèle actuelle. GET /api/v1/vehicles?make=&model= est gratuit et public, et liste toutes les années d’un modèle, chacune avec l’identifiant de véhicule stable que vous stockerez ; POST /api/v1/images/resolve fait de même à partir d’une expression comme « 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
};Les identifiants ne changent jamais : cette table est donc le seul endroit touché par un changement de flotte. Quand la catégorie intermédiaire passe à un autre modèle, ou à l'année-modèle suivante, remplacez un identifiant, et chaque carte, visuel principal et e-mail qui lit la table suit.
Étape 2 : un seul format de requête pour toutes les catégories
Les 8 vues de caméra sont cadrées de façon identique pour chaque véhicule du catalogue, ce qui permet à une grille de s’aligner. Le reste de la vignette se résume à quelques paramètres, fixés une fois pour toutes :
view=sidepour les cartes : chaque voiture est orientée dans le même sens, sur la même ligne de base. Chaque angle côté gauche a un jumeau-right(side-right), pour que les cartes puissent être orientées vers l’intérieur de la mise en page. La page de catégorie utilisefront-3-4, l’angle vedette.w=640&h=320&fit=contain: exactement 640×320 pour chaque catégorie, avec la voiture entièrement visible. Les en-têtesX-Image-WidthetX-Image-Heightde la réponse confirment le canevas.trim=1&padding=6: recadre sur la voiture avant de l’ajuster, avec une marge de 6 % de son plus grand côté, pour qu’une Corolla et un Tahoe remplissent leurs cartes de la même façon au lieu de flotter dans le cadre carré d’origine.background=f4f4f4place la carte sur le gris de la grille. Omettez-le pour conserver le fond transparent et laisser apparaître la couleur de la carte.format=webppour les fichiers stockés ;format=autosur les URL signées, qui sert du WebP ou du PNG selon le navigateur.
# 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Étape 3 : une seule peinture nommée pour toute la grille
Les 15 préréglages sont des peintures nommées : white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple. La valeur par défaut est silver, et grey est interprété comme gray. Choisissez-en une pour chaque catégorie afin que les fiches forment un ensemble ; white est présenté ci-dessus. Chaque préréglage conserve sa propre teinte de peinture plutôt que la couleur CSS du même nom (red correspond à #b3151b), et chaque peinture, y compris une valeur hexadécimale, est une recoloration d'un même rendu neutre : elle coûte donc toujours 1 crédit.
Étape 4 : mettre en cache les fichiers ou les URL
La grille des catégories est identique pour chaque visiteur : elle ne devrait donc presque rien coûter par visite. Deux façons d’y parvenir :
- Stockez les fichiers. Récupérez chaque carte et chaque visuel principal une seule fois avec
GET /api/v1/images/caret servez-les depuis votre CDN comme n'importe quel autre fichier ; un forfait payant autorise des copies sur vos propres serveurs pour servir votre produit, et elles conservent leur licence après la fin du forfait. Conservez l’ETagde chaque fichier : une revérification nocturne avecIf-None-Matchrépond304et ne coûte rien. Pour la flotte ci-dessus, cela représente 8 crédits, une seule fois. - Ou émettez des URL signées une fois et réutilisez-les.
POST /api/v1/image-urlsaccepte jusqu’à 50 images par appel et renvoie des URL sans clé valables jusqu’à 7 jours. Une URL à utilisations illimitées peut être mise en cache publiquement pendant sa durée de validité : lorsque chaque visiteur charge la même URL, les chargements suivants proviennent gratuitement du CDN. Ajoutezrenew: trueet une URL enregistrée continue de fonctionner au-delà de sa durée de validité, à raison de 1 crédit par image pour chaque semaine supplémentaire où elle est chargée : au maximum 8 crédits par semaine pour la flotte ci-dessus.
Limitez la clé qui génère les URL à votre domaine de réservation dans le tableau de bord : une URL copiée sur un autre site renverra alors 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 }))
);Étape 5 : la confirmation de réservation
L'e-mail de confirmation montre la catégorie réservée, et les e-mails sont ouverts quand le locataire en a le temps. Générez son image sous forme d'URL renouvelable : ttl_seconds au maximum de 7 jours, renew: true, et renew_days allant au-delà de la date de restitution. Les semaines où personne n'ouvre l'e-mail ne coûtent rien, et après la location, l'URL cesse de se renouveler. Une Idempotency-Key par réservation fait qu'un envoi relancé rejoue la première URL au lieu d'en générer une deuxième, et enregistrer l'URL dans la réservation permet de la réutiliser à chaque renvoi ultérieur. Nos propres e-mails de cycle de vie fonctionnent ainsi ; le cas de l'e-mail détaille le mécanisme et le 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 et MCP
- CLI :
npx @meterapp/car-image get --vehicle veh_… --view side --width 640 --height 320 --fit contain --trim --padding 6 --out card.webpécrit une vignette dans un fichier ;car-image url --batch classes.json --renewgénère un lot d’URL. - SDK :
client.vehicles({ make, model })pour les identifiants,client.getImage(…)pour les fichiers,client.createImageUrls(…)pour les URL. - MCP :
resolve_vehicleetcreate_car_image_urlspermettent à un assistant de rédiger une fiche de catégorie à partir de « SUV intermédiaire, RAV4 ou similaire ». La configuration est décrite sur la page MCP.
Questions fréquentes
- La fiche peut-elle montrer la voiture exacte que le client recevra ?
- Non, et ce n’est pas son rôle. Une catégorie se loue « ou similaire », et un rendu représente une marque, un modèle et une année du catalogue, pas une voiture de votre parc. Affichez un modèle représentatif avec « ou similaire » dans la légende. Une fois qu’une voiture précise est attribuée au comptoir, son VIN se décode gratuitement en son véhicule du catalogue si vous préférez afficher ce modèle.
- Pourquoi les voitures de la grille ne sont-elles pas à l’échelle ?
- Parce que trim recadre chaque rendu sur la voiture et que fit=contain l’agrandit pour remplir la vignette : une compacte et un grand SUV remplissent ainsi leur vignette de la même manière. C’est ce qui garde une grille nette. Exprimez la taille avec des mots : le nom de la catégorie, le nombre de places et de bagages.
- Combien coûte la grille des catégories ?
- Une flotte de 4 catégories, avec une vignette et une image principale pour chacune, revient à 8 crédits. Stockez les fichiers sur votre CDN et c’est toute la facture, les revérifications par ETag étant gratuites. Servez plutôt des URL signées renouvelables et cela coûte au plus 8 crédits par semaine, uniquement pour les semaines où les pages sont ouvertes.
- Quelle peinture utiliser pour la grille ?
- Une seule couleur prédéfinie pour toutes les catégories, afin que les cartes forment un ensemble. Les 15 couleurs prédéfinies sont white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple, et la couleur par défaut est silver ; tout code hex fonctionne aussi, au même prix. Le client reçoit la couleur disponible sur le parc, ce que la carte n’a jamais promis.
- Et si le modèle d’une catégorie n’est pas dans le catalogue ?
- Un véhicule absent du catalogue renvoie une 404 avec des suggestions : les véhicules du catalogue les plus proches, chacun avec son identifiant. Utilisez l'un d'eux ou demandez le véhicule sur le tableau public des demandes. Le catalogue est open source.