Un ghid de implementare scris pe baza comportamentului documentat al API-ului; nu numește niciun client. Publicat pe .
Problema: se închiriază o clasă, nu o mașină
Un client de închirieri rezervă o clasă (o mașină compactă, un SUV mediu, un monovolum) și pleacă cu orice mașină din acea clasă se află în parcare. Pagina de rezervare are totuși nevoie de o imagine pentru fiecare clasă, iar convenția este un model reprezentativ însoțit de mențiunea „sau similar”.
Aceste imagini provin de obicei de oriunde a putut fi găsită fiecare: o fotografie de presă aici, o fotografie de la un dealer acolo, unghiuri diferite, fundaluri diferite, mașini care își umplu cardurile în mod diferit. O grilă alcătuită astfel arată ca un colaj. O pagină de flotă are nevoie de opusul: fiecare clasă redată la fel, astfel încât singurul lucru care se schimbă de la un card la altul să fie mașina.
Cum arată integrarea
- Un model reprezentativ pentru fiecare clasă, păstrat ca id de vehicul din catalog, cu „sau similar” în etichetă și niciodată în imagine.
- Aceeași structură de cerere pentru fiecare card: aceeași vedere, casetă, încadrare, decupare, spațiere, culoare, fundal și format.
- Cel mult două imagini pe clasă: cardul din grilă și imaginea principală de pe pagina clasei.
- În cache, pentru că grila este aceeași pentru fiecare vizitator: fișiere pe CDN-ul dumneavoastră sau URL-uri semnate generate o singură dată și reutilizate.
Pasul 1: alegeți un model reprezentativ pentru fiecare clasă, după id
Alegeți modelul sub care este vândută fiecare clasă și căutați anul de model curent. GET /api/v1/vehicles?make=&model= este gratuit și public și listează fiecare an al unui model, fiecare cu ID-ul stabil de vehicul pe care îl veți stoca; POST /api/v1/images/resolve face același lucru pornind de la o expresie precum „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
};Id-urile nu se schimbă niciodată, așa că această mapare este singurul loc afectat de o schimbare a flotei: când clasa medie trece la alt model sau la următorul an de model, înlocuiți un singur id, iar fiecare card, imagine principală și e-mail care citește maparea se actualizează automat.
Pasul 2: o singură formă de cerere pentru fiecare clasă
Cele 9 unghiuri de cameră sunt încadrate identic pentru fiecare vehicul din catalog, iar asta face ca o grilă să se alinieze. Restul cardului înseamnă câțiva parametri, stabiliți o singură dată:
view=sidepentru carduri: fiecare mașină este orientată în aceeași direcție, pe aceeași linie de bază. Fiecare unghi din partea stângă are un geamăn-right(side-right), astfel încât cardurile pot fi orientate spre interiorul paginii. Pagina clasei foloseștefront-3-4, unghiul principal.w=640&h=320&fit=contain: exact 640×320 pentru fiecare clasă, cu întreaga mașină vizibilă. AnteteleX-Image-WidthșiX-Image-Heightdin răspuns confirmă dimensiunile pânzei.trim=1&padding=6: decupează imaginea la conturul mașinii înainte de încadrare, cu o margine de 6% din latura ei mai lungă, astfel încât o Corolla și un Tahoe să-și umple cardurile la fel, în loc să plutească în cadrul pătrat al imaginii sursă.background=f4f4f4aplatizează cardul pe nuanța de gri a grilei. Omiteți-l pentru a păstra fundalul transparent și a lăsa culoarea cardului să se vadă.format=webppentru fișierele stocate;format=autopentru URL-urile semnate, care servește WebP sau PNG fiecărui browser.
# 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.webpPasul 3: o singură culoare denumită pentru toată grila
Cele 15 presetări sunt vopsele cu nume: white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple. Valoarea implicită este silver, iar grey este interpretat ca gray. Alegeți una pentru fiecare clasă, astfel încât cardurile să arate ca un set; mai sus este afișat white. Fiecare presetare își păstrează propria mostră de vopsea, nu culoarea CSS cu același nume (red este #b3151b), iar fiecare vopsea, inclusiv un hex, este o recolorare a unei singure vederi pregătite, deci fiecare vopsea înseamnă o imagine de vehicul.
Pasul 4: stocați în cache fișierele sau URL-urile
Grila de clase este identică pentru fiecare vizitator, așa că ar trebui să coste aproape nimic per vizită. Există două moduri de a ajunge aici:
- Stocați fișierele. Descărcați fiecare card și imagine principală o singură dată cu
GET /api/v1/images/carși serviți-le de pe CDN-ul dumneavoastră ca pe orice altă resursă; un plan plătit permite copii pe propriile servere pentru a vă servi produsul cât timp este activ (ștergeți-le în cel mult 30 de zile după încheierea lui sau cumpărați un Image Pack pentru a păstra definitiv un set). PăstrațiETag-ul fiecărui fișier: o reverificare nocturnă cuIf-None-Matchprimește răspunsul304și nu costă nimic. Pentru flota de mai sus, asta înseamnă 8 imagini de vehicul pe lună, refolosite ori de câte ori este nevoie. - Sau emiteți o singură dată URL-uri semnate și refolosiți-le.
POST /api/v1/image-urlsacceptă până la 50 imagini per apel și returnează URL-uri fără cheie, valabile până la 7 zile. Un URL cu utilizări nelimitate poate fi stocat public în cache pe durata valabilității sale, așa că, atunci când toți vizitatorii încarcă același URL, încărcările repetate vin gratuit din CDN. Adăugațirenew: trueși un URL stocat funcționează și după expirarea valabilității; o reînnoire contorizează imaginea o singură dată în luna în care are loc și nimic în plus dacă imaginea a fost deja contorizată în acea lună, astfel încât flota de mai sus rămâne la cel mult 8 imagini de vehicul pe lună.
Restricționați la domeniul dumneavoastră de rezervări cheia care generează URL-urile, din panoul de control, iar un URL copiat pe alt site va răspunde cu 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 }))
);Pasul 5: confirmarea rezervării
E-mailul de confirmare arată clasa rezervată, iar e-mailurile sunt deschise oricând ajunge clientul la ele. Generați imaginea ca URL care se reînnoiește: ttl_seconds la maximul de 7 zile, renew: true și renew_days până după data returnării. Săptămânile în care nimeni nu deschide e-mailul nu costă nimic, iar după închiriere URL-ul nu se mai reînnoiește. Un Idempotency-Key per rezervare face ca o retrimitere să returneze primul URL în loc să genereze unul nou, iar stocarea URL-ului în rezervare permite fiecărei retrimiteri ulterioare să îl refolosească. Propriile noastre e-mailuri de ciclu de viață funcționează astfel; povestea despre e-mail descrie mecanismul și codul 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 și MCP
- CLI:
npx @meterapp/car-image get --vehicle veh_… --view side --width 640 --height 320 --fit contain --trim --padding 6 --out card.webpscrie un card într-un fișier;car-image url --batch classes.json --renewgenerează un set de URL-uri. - SDK:
client.vehicles({ make, model })pentru id-uri,client.getImage(…)pentru fișiere,client.createImageUrls(…)pentru URL-uri. - MCP:
resolve_vehicleșicreate_car_image_urlspermit unui asistent să schițeze un card de clasă pornind de la „SUV mediu, RAV4 sau similar”. Configurarea este descrisă pe pagina MCP.
Întrebări frecvente
- Poate cardul să arate exact mașina pe care o va primi clientul?
- Nu, și nici nu ar trebui să încerce. O clasă se închiriază „sau similar”, iar o randare înfățișează o marcă, un model și un an din catalog, nu o mașină din parcul dumneavoastră. Afișați un model reprezentativ cu „sau similar” în etichetă. După ce o anumită mașină este alocată la ghișeu, VIN-ul ei se decodează gratuit în vehiculul corespunzător din catalog, dacă doriți să afișați în schimb acel model.
- De ce mașinile din grilă nu sunt la scară?
- Pentru că trim decupează fiecare randare pe conturul mașinii, iar fit=contain umple cardul cu ea, astfel încât o mașină compactă și un SUV mare își umplu cardurile la fel. Asta păstrează grila ordonată. Exprimați dimensiunea în cuvinte: numele clasei, numărul de locuri și de bagaje.
- Cât costă grila de clase?
- O flotă cu 4 clase, fiecare cu un card și o imagine principală, înseamnă 8 imagini de vehicule pe lună, fiecare livrată ori de câte ori este nevoie, la orice dimensiune. Stocați fișierele pe CDN-ul dumneavoastră cât timp un plan plătit este activ și acestea se contorizează doar în luna în care le preluați, cu reverificări gratuite prin ETag. Dacă serviți în schimb URL-uri semnate care se reînnoiesc, aceleași imagini se contorizează o dată în fiecare lună în care paginile sunt deschise.
- Ce culoare de vopsea ar trebui să folosească grila?
- O singură culoare predefinită pentru toate clasele, ca cardurile să arate ca un set. Culorile predefinite (15) sunt white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple, iar cea implicită este silver; funcționează și orice cod hex, la același preț. Clientul primește culoarea mașinii din parc, pe care cardul nu a promis-o niciodată.
- Ce se întâmplă dacă modelul unei clase nu se află în catalog?
- Un vehicul care nu există în catalog răspunde cu 404 și sugestii: cele mai apropiate vehicule din catalog, fiecare cu id-ul său. Folosiți unul dintre ele sau solicitați vehiculul pe panoul public de cereri. Catalogul este open source.