Un ghid de implementare scris pe baza comportamentului documentat al API-ului; nu numește niciun client. Publicat pe .
Problema: vânzarea începe înainte să existe fotografiile
Un catalog de licitație este publicat imediat ce sosesc consignațiile: un VIN, un număr de lot și o dată de vânzare pentru fiecare mașină. Fotografiile vin când mașina ajunge în parc și fotograful ajunge la mașină, ceea ce, pentru o parte din vânzare, se întâmplă după deschiderea licitației. Până atunci, fiecare dintre aceste loturi este o casetă gri lângă un rând de text.
O randare din catalog umple caseta cu anul de model corect. Totuși, o licitație este exact locul unde o randare nu trebuie să treacă niciodată drept mașina: ofertanții evaluează starea, iar o randare nu arată nimic din ea, pentru că nu înfățișează niciun vehicul fizic anume. Tot ce urmează decurge din respectarea ambelor idei în același timp.
Cum arată integrarea
- O randare per lot pornind de la VIN-ul său, afișată doar până sosesc fotografiile proprii ale lotului.
- Un selector din catalog pentru loturile al căror VIN nu poate fi decodat.
- O etichetă pe imagine: „Randare din catalog, nu acest lot”.
- Un singur URL per lot, generat o singură dată sub un
Idempotency-Key, valabil pe toată durata licitației.
Pasul 1: de la VIN-ul lotului la un id de vehicul
GET /api/v1/vin/{vin} este gratuit. Când catalogul conține vehiculul, răspunsul include data.vehicle.id, ID-ul stabil de stocat pe lot; echiparea, caroseria și motorul decodate rămân în textul lotului. Catalogul acoperă perioada de la 1990 până la 2027, astfel încât stocul mai vechi al unei licitații se randează la fel ca cel mai nou. Ghidul pentru asigurări parcurge o decodare câmp cu câmp, iar documentația VIN acoperă VIN-urile parțiale și erorile.
# 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'Pasul 2: nu aveți un VIN decodabil? Alegeți vehiculul din catalog
Unele loturi sosesc fără un VIN care poate fi decodat: un vehicul fabricat pentru altă piață, un VIN tastat greșit de sursă, o fișă de consignație cu un an, o marcă și un model și nimic altceva. Adăugați în formularul de consignație trei liste derulante alimentate de GET /api/v1/vehicles, care este gratuit și public: ?year= listează mărcile care au un model în acel an, iar ?year=&makeId= listează modelele acelei mărci, fiecare cu id-ul vehiculului pentru acel an de model.
# 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"
},
"…"
]
}
}Același catalog este pachetul deschis @meterapp/vehicle-db, așa că listele derulante pot funcționa și offline, pe baza aceleiași liste. În ambele cazuri, lotul ajunge să conțină același tip de id ca un VIN decodat, iar nimic din aval nu mai scrie de mână numele unei mașini.
Când sosește deodată o listă întreagă de consignație, POST /api/v1/vehicles/check citește până la 2.000 intrări per apel, fiecare așa cum apare scrisă în listă și cu numărul lotului ca ref, și răspunde pentru fiecare: o potrivire cu id-ul de stocat, sugestii, nicio potrivire sau un rând invalid. Nimic nu este randat și nimic nu este taxat; detaliile se găsesc în documentația pentru vehicule.
Pasul 3: etichetați randarea drept randare
Puneți eticheta pe imaginea în sine, acolo unde se oprește privirea licitantului, și în textul alternativ, nu doar în descrierea de dedesubt. Starea, kilometrajul, daunele, dotările și culoarea reală a mașinii își au locul în textul lotului și, odată ce există, în fotografii. Când sosesc fotografiile, randarea dispare.
<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>Pasul 4: un URL per lot, generat o singură dată
Emiteți URL-ul lotului la preluare cu POST /api/v1/image-urls și un Idempotency-Key format din licitație și lot, din litere, cifre, ., _, : și -. URL-ul contorizează imaginea sa ca imagine de vehicul a lunii când este emis, așa că fără cheie o preluare reîncercată ar emite un al doilea URL. Cu o cheie:
- Aceeași cheie cu același corp, în decurs de 24 ore, reia primul răspuns, inclusiv același URL, cu
Idempotent-Replayed: trueși fără o a doua taxare. - Aceeași cheie cu un corp diferit returnează
422, iar o reîncercare care o depășește pe prima cerere returnează409cuRetry-After. Așadar, fixați tot conținutul corpului, inclusiv durata de valabilitate, la crearea lotului și stocați-l împreună cu lotul. - Salvați și URL-ul în lot: cheia protejează reîncercările, iar URL-ul salvat este cel pe care îl citesc paginile pe tot restul licitației.
Un catalog întreg importat dintr-odată poate genera URL-uri pentru până la 50 loturi per apel, cu o cheie pentru fiecare pachet; fiecare URL din răspuns indică vehiculul și opțiunile pentru care a fost generat.
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 chargedPasul 5: potriviți durata de valabilitate a URL-ului cu licitația
ttl_seconds acceptă până la 604800 (7 zile); o valoare mai mare este redusă la această limită. Pentru o licitație care se încheie în aceeași săptămână, setați-l la timpul rămas până la închidere. Astfel, imaginea provizorie nu mai funcționează odată cu încheierea licitării, iar după aceea URL-ul răspunde cu 403.
- O licitație cu durată limitată mai lungă de 7 zile: emiteți URL-ul cu
renew: true,ttl_secondsla valoarea maximă șirenew_daysacoperind durata licitației. O reînnoire contorizează imaginea o singură dată în luna în care are loc și nimic în plus dacă a fost deja contorizată în acea lună; săptămânile în care nimeni nu deschide lotul nu se contorizează deloc, iar reînnoirea se oprește larenews_until. - Păstrați
max_usesla 0, valoarea implicită: un URL nelimitat poate fi stocat public în cache pe toată durata sa de valabilitate, în timp ce unul limitat esteprivate, no-storeși trimite fiecare încărcare către serverul de origine. - Restricționați cheia de generare la domeniile licitației dumneavoastră din panoul de control: o imagine de lot copiată pe alt site răspunde cu
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 arriveAlegeți planul după mărimea licitației
Fiecare lot reprezintă o imagine de vehicul — vehiculul său, în vopseaua și vederea sa —, cu excepția cazului în care două loturi au toate trei elementele în comun, iar fiecare plan include un număr de imagini de vehicul pe lună: Free 100, Pro 2.500 și Business 10.000; Enterprise se negociază. O imagine deja contorizată luna aceasta este întotdeauna servită, iar o cerere grupată care ar depăși alocarea este refuzată integral, înainte de a se contoriza ceva, cu planul și alocarea incluse în răspuns. Dimensionați planul în funcție de loturile pe care le listați într-o lună. Povestea marketplace explică cum să eșalonați un import mare în limitele de rată și de randare.
Întrebări frecvente
- Poate rămâne randarea afișată după ce sosesc fotografiile lotului?
- Înlocuiți-o. Randarea ține locul anului modelului, iar un ofertant nu ar trebui să se întrebe niciodată care imagine este mașina scoasă la vânzare. Dacă o pagină o păstrează ca referință, eticheta rămâne alături de ea.
- Ce se întâmplă cu URL-ul după vânzare?
- Expiră la sfârșitul duratei de valabilitate sau când un URL cu reînnoire ajunge la capătul perioadei de reînnoire, după care răspunde cu 403. Până atunci, lotul are propriile fotografii sau un rezultat, iar arhiva vânzării ar trebui să afișeze fotografiile. Revocarea cheii care a generat URL-urile le invalidează pe toate deodată.
- O reîncercare a primit răspunsul 422. De ce?
- Același Idempotency-Key a revenit cu un corp diferit. Cauza obișnuită este o durată de valabilitate recalculată după ceas în momentul reîncercării. Stabiliți durata de valabilitate la crearea lotului și stocați-o; astfel, reîncercarea trimite același corp și redă primul răspuns.
- Poate randarea să redea culoarea lotului?
- Da: parametrul color acceptă oricare dintre numele predefinite sau un cod hex, astfel încât imaginea poate corespunde culorii din fișa de consignație, fără cost suplimentar. Rămâne totuși modelul în acea culoare, nu lotul, așa că eticheta rămâne.
- Cât costă o licitație cu 400 loturi?
- 400 de imagini de vehicul din lună: 1 imagine de vehicul pe lot când URL-ul acestuia este emis, iar o emitere reîncercată nu mai contorizează nimic. Fiecare încărcare pe durata de valabilitate a URL-ului este gratuită. Planurile includ Free 100, Pro 2.500 și Business 10.000 imagini de vehicul pe lună, iar loturile care au în comun vehiculul, vopseaua și vederea se contorizează o singură dată.