Car Image API

Kunder · Rubrikkannonsesider og bilkataloger

Slik får du et studiobilde av bilen på hver eneste markedsplassannonse

Hvordan rubrikkannonsesider og bilkataloger genererer ett hovedbilde per årsmodell i katalogskala: kjøretøy-ID-er, utsnitt, tempo, hurtigbufring og koden.

Problemet: en annonse trenger et bilde før selgeren laster opp et

En rubrikkannonsetjeneste eller en bilkatalog står og faller på rutenettet sitt. Hvert kort trenger et bilde i det øyeblikket annonsen opprettes, og selgerens eget bilde kommer senere, om i det hele tatt, fra en tilfeldig vinkel i en tilfeldig innkjørsel. Arkivbilder har det motsatte problemet: et lisensiert pressebilde finnes for de populære bilene i de populære årene, i den vinkelen og med den bakgrunnen produsenten valgte, og for ingenting annet. En katalog som dekker 1990 til gjeldende årsmodell, har titusenvis av hull.

Det teamene som bygger disse sidene ønsker seg, er kjedelig på best mulig måte: ett studiobilde per årsmodell, samme vinkel og samme lakk for alle, gjennomsiktig slik at det passer på hvilken som helst bakgrunn kortet har, og lite nok til å serveres ti tusen ganger om dagen.

Slik ser en katalogintegrasjon ut

Katalogløsningene som kjører på API-et i dag, har alle samme form, enten det er en rubrikkside som fyller opp annonsene sine, en bilkjøpsapp som rendrer sammenligningskortene sine, eller en mobilapp som viser ett hovedbilde per kjøretøy:

  • En backfill, så et jevnt dryss. Tusenvis av renderinger på noen få timer for å dekke katalogen, deretter en håndfull om dagen etter hvert som nye modellår og forespørsler kommer inn.
  • Én vinkel, én lakk eller en kort palett. De fleste velger front-3-4 eller side i sølv eller hvitt. En handlekatalog der brukeren kan velge farge, gjengir noen få forhåndsdefinerte farger per kjøretøy. Hver av dem er ett kjøretøybilde til, ikke en ny pipeline.
  • WebP i en fast boks. 512 til 1024 piksler bredt, levert i nøyaktig den boksen kortet bruker, slik at frontend aldri beskjærer eller legger på kantfelt.
  • Lagret etter kjøretøy-id. Gjengivelsene havner i teamets egen objektlagring eller CDN, eller sidene laster signerte URL-er; uansett er nøkkelen katalogens stabile veh_…-id, ikke en streng med merke, modell og år.

Resten av denne siden viser den pipelinen, steg for steg, med koden. Den forutsetter en API-nøkkel med tilgangen images:read og en plan dimensjonert for katalogen (se FAQ).

Trinn 1: list opp katalogen etter id, aldri etter stavemåte

Den vanligste feilen i et katalogbygg er ikke renderingen, men stavemåten. Et bygg som genererer merke- og modellstrenger fra en annen database, kan bruke mesteparten av forespørslene sine på 404 vehicle_not_found: gratis, men en bortkastet rundtur hver gang, og et rutenett med hull i. Løsningen er å la katalogen fortelle hva som finnes. GET /api/v1/vehicles er gratis, krever ingen nøkkel, og hver modell den returnerer har en stabil kjøretøy-id (veh_ pluss 13 tegn) som aldri endres på tvers av utrullinger eller katalogutgivelser. Lagre den id-en på annonsen og generer bildene ut fra den.

Gå gjennom én modellårgang
# 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 (forkortet)
{
  "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 lister alle årganger av én modell med en ID per år, og ?q= søker i fritekst når en selger skriver inn et navn. Den samme katalogen er publisert som den åpne @meterapp/vehicle-db-pakken, så nedtrekkslister og validering kan kjøre offline mot nøyaktig samme liste. Uansett har du ved slutten av dette steget en liste med ID-er, og ingenting senere i flyten staver en bil igjen.

Annonser som allerede navngir bilene med en annen databases stavemåte, kobles i ett kall: POST /api/v1/vehicles/check leser opptil 2 000 av dem slik en rendering ville gjort, og svarer på hver med kjøretøy-ID-en, de nærmeste virkelige kjøretøyene når katalogen ikke har en slik bil, eller et bom som skal hoppes over i alle visninger og farger. car-image check listings.csv --out checked.csv skriver ID-ene tilbake i filen. Det er gratis, og du slipper å oppdage hullene én 404 om gangen.

Steg 2: én forespørselsform for alle annonser

Bestem kortet én gang og kod det inn i spørrestrengen. Alt etter vehicle= nedenfor er en innrammingsbeslutning du tar én gang for hele katalogen:

Ett annonsebilde
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 gir nøyaktig 800×600 med hele bilen synlig og gjennomsiktig luft rundt, slik at alle kort får samme lerret. fit=cover fyller i stedet boksen og beskjærer fra midten.
  • trim=1&padding=8 beskjærer til bilens omriss før tilpasning, med 8 % av den lengste siden som marg, slik at en Suburban og en Miata fyller boksen på samme måte i stedet for å flyte rundt i kilderammen.
  • color=silver er standard og det tryggeste nøytrale valget; hvilken som helst av de 15 forhåndsinnstillingene eller en hvilken som helst hex-kode teller likt, som ett kjøretøybilde.
  • format=webp er den minste kodingen med tapsfri alfakanal. Når en nettleser laster URL-en direkte (signerte URL-er, steg 4), forhandler format=auto fram WebP eller PNG per klient.

Svaret inneholder ETag, X-Image-Source (cache eller generated) og X-Vehicle-Id, katalogkjøretøyet som ble levert. Lagre ETag sammen med filen: En senere forespørsel med If-None-Match svarer 304 og koster ingenting, og det er slik en nattlig resynkronisering forblir gratis.

Trinn 3: hold tempoet i etterfyllingen innenfor grensene

Tre grenser former en backfill, og hver av dem gir beskjed i headere i stedet for å feile i det stille:

  • Forespørsler per minutt. 120 per nøkkel på Free og Pro, 600 på Business, 1 200 på Enterprise, pluss en grense per konto på tvers av alle nøkler. Hvert autentisert svar inneholder RateLimit-Remaining; en 429 inneholder Retry-After. Fire til åtte samtidige forespørsler er mer enn nok.
  • Nye kjøretøyvisninger. Den første forespørselen om en kjøretøyvisning vi ikke har klargjort ennå, tar litt tid mens vi klargjør den slik at den kan vises i alle farger; alle senere forespørsler, i alle farger, leveres fra hurtigbufferen. Klargjøring av nye visninger trekker på kontoens andel av dagens renderingsbudsjett (2 % på Free, 10 % på Pro, 25 % på Business, 50 % på Enterprise). Når andelen er brukt opp, svarer en ny rendering 429 med code: account_generation_cap og reset_at (midnatt UTC), ingenting belastes, og bufrede bilder leveres fortsatt. En stor etterfylling tar noen kvelder, ikke én.
  • Kjøretøybilder i måneden. Free inkluderer 100, Pro 2 500, Business 10 000; Enterprise forhandles. Utover denne kvoten besvares en forespørsel om et bilde som ennå ikke er telt denne måneden, med 402 (plan_image_limit) og teller ingenting; et bilde som allerede er telt denne måneden, leveres alltid, slik at et aktivt rutenett aldri slutter å fungere.

Renderingsfeil (502) gir kjøretøybildet tilbake automatisk, samtidige forespørsler om den samme nye varianten deler én rendering, og en vanlig GET er trygg å prøve på nytt. SDK-et prøver 429 og 503 på nytt for deg, respekterer Retry-After og prøver aldri en 402 på nytt.

Gjenopptakbar etterfylling med TypeScript SDK
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;
      }
    }
  })
);

Trinn 4: lever det fra ditt eget CDN eller via signerte URL-er

Det finnes to gode måter å vise bildet til kjøperen på, og katalogbyggene bruker begge:

  • Lagre filene. Skriv hver rendering til din egen objektlagring eller CDN under kjøretøy-ID-en, og server den som enhver annen ressurs. Dette er riktig løsning for et rutenett som vises millioner av ganger: ingen kall til oss per innlasting, og lisensen i et betalt abonnement dekker kopier du beholder for å levere produktet ditt.
  • Opprett signerte URL-er. POST /api/v1/image-urls tar opptil femti bilder per kall, teller bildet til hver URL som et av månedens kjøretøybilder når den opprettes, og returnerer URL-er uten nøkkel som nettleseren laster direkte. Sett ttl_seconds til opptil sju dager; legg til renew: true for annonsesider som lever lenger enn det (en fornyelse teller bildet én gang i måneden den faller i, og ikke noe mer hvis det allerede er telt den måneden). Begrens nøkkelen til nettstedets opprinnelser i dashbordet, så svarer en URL som kopieres til andre steder, med 403.

Send én Idempotency-Key per side med annonser når du oppretter i bunker. Et nytt forsøk med samme nøkkel og brødtekst spiller av det første svaret og teller ingenting på nytt.

listings.json — femti om gangen, med samme utsnitt som i trinn 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"
    }
  ]
}

Når et kjøretøy ikke finnes i katalogen

Søk først: GET /api/v1/vehicles?q= finner en modell etter navn, prefiks eller omtrentlig treff, og POST /api/v1/images/resolve gjør en fritekstfrase om til eksakte parametere med en konfidensverdi du kan handle ut fra. Det som fortsatt mangler etter det, hører hjemme på forespørselstavlen: POST /api/v1/requests oppretter forespørselen, eller gir en stemme til en åpen forespørsel for samme merke, modell og år hvis det finnes en, i stedet for å lage et duplikat. Selve katalogen er åpen kildekode, og tillegg leveres til alle kunder.

CLI, SDK og MCP

Hele pipelinen kjører fra CLI-en helt uten kode, og det var slik mer enn én katalog i API-et ble fylt opp:

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 }) for å liste opp, client.getImage({ vehicle, … }) for å gjengi, client.createImageUrls(…) for grupper av signerte URL-er. Se bildedokumentasjonen for alle parametere.
  • MCP: en assistent koblet til https://carimage.dev/api/mcp har samme katalog (search_vehicles, resolve_vehicle) og samme renderinger (get_car_image, create_car_image_urls), noe som gjør den til riktig verktøy for en kurator som legger til et kjøretøy manuelt, og feil verktøy for en etterfylling av tusenvis: bruk CLI eller SDK til det, og spar assistenten til etternølerne. Oppsett finnes på MCP-siden.

Ofte stilte spørsmål

Hvilken vinkel bør en annonse bruke?
front-3-4 er standard og den klassiske hovedvinkelen, med fronten mot venstre. Hver vinkel av bilens venstre side har en -right-tvilling (front-3-4-right, side-right, rear-3-4-right), slik at et kort kan vende inn mot oppsettet i stedet for ut av det. Velg én og hold dere til den: konsistensen på tvers av annonsene er det meste av verdien.
Hva koster en katalog med 20 000 annonser?
20 000 kjøretøybilder i måneden hvis hver annonse viser ett kjøretøy i én lakkfarge og visning, hvert levert så ofte som nødvendig i hvilken som helst størrelse; annonser som deler kjøretøy, lakk og visning, er ett bilde, og ny kontroll med If-None-Match er gratis. Pro inkluderer 2 500 kjøretøybilder i måneden og Business 10 000, så en katalog av den størrelsen er Enterprise, eller en Image Pack som engangskjøp som du beholder og hoster selv for godt. En etterfylling ut over kvoten svarer 402 og telles ikke.
Kan vi lagre filene på vårt eget CDN?
Ja. En betalt plan lisensierer renderingene for bruk i produktet ditt, inkludert kopier på egne servere eller CDN, uten kildehenvisning, så lenge planen er aktiv. Innen 30 dager etter at den avsluttes, slettes lagrede kopier (bilder fra en Image Pack kan beholdes for godt). Det lisensen ikke tillater, er å tilby dem som et frittstående bibliotek, en feed eller et datasett. Det er en aktiv plan som gir renderinger av neste modellår.
Hva skjer når katalogen får et nytt modellår?
@meterapp/vehicle-db-katalogen oppdateres etter hvert som kildene publiserer, og eksisterende id-er endres aldri. List opp det nye året, generer de id-ene du ikke har ennå, og la resten være. Forespørsler har en ETag; en gjentatt forespørsel med If-None-Match svarer 304 og koster ingenting.
Hvorfor gir noen av våre merke- og modellstrenger 404?
Fordi de ble stavet av en annen database. Katalogen godtar navn, slugs og mange varianter av modellbetegnelser og karosserityper, men en streng den aldri har sett, gir 404 vehicle_not_found (gratis, men en bortkastet forespørsel). List opp katalogen og lagre ID-ene derfra i stedet for å oversette dine egne strenger, og søk opp eller slå opp de som gjenstår.