Car Image API

Zastosowania · Wynajem samochodów

Obrazy samochodów na strony floty wypożyczalni

Każda klasa wypożyczalni prezentowana tak samo: jeden reprezentatywny model na klasę, identyczne kadrowanie dzięki parametrom trim, padding i fit, jeden nazwany lakier oraz URL-e, które można cache’ować.

Przewodnik wdrożeniowy oparty na udokumentowanym działaniu API; nie wymienia żadnego klienta. Opublikowano .

Problem: wynajmuje się klasę, a nie samochód

Klient wypożyczalni rezerwuje klasę — kompakt, średniej wielkości SUV, minivan — i odjeżdża dowolnym samochodem tej klasy, który jest dostępny na placu. Strona rezerwacji nadal potrzebuje obrazu dla każdej klasy, a przyjęło się pokazywać jeden reprezentatywny model z dopiskiem „lub podobny”.

Takie zdjęcia pochodzą zwykle z miejsc, w których akurat udało się je znaleźć: tu zdjęcie prasowe, tam fotografia od dealera, różne kąty, różne tła, samochody, które w różny sposób wypełniają karty. Siatka złożona w ten sposób wygląda na poskładaną. Strona floty potrzebuje czegoś odwrotnego: każdej klasy pokazanej w ten sam sposób, tak aby jedyną rzeczą zmieniającą się między kartami był samochód.

Jak wygląda integracja

  • Jeden reprezentatywny model na klasę, przechowywany jako identyfikator pojazdu z katalogu, z dopiskiem „lub podobny” w etykiecie, ale nigdy na obrazie.
  • Jeden kształt żądania dla każdej karty: ten sam widok, ramka, dopasowanie, kadrowanie, margines, lakier, tło i format.
  • Najwyżej dwa zdjęcia na klasę: karta w siatce i zdjęcie główne na stronie klasy.
  • Buforowane, bo siatka jest taka sama dla każdego odwiedzającego: pliki w CDN lub podpisane URL-e wygenerowane raz i używane ponownie.

Krok 1: wybór reprezentatywnego modelu dla każdej klasy według id

Proszę wybrać model, pod którym sprzedawana jest każda klasa, i sprawdzić jego aktualny rocznik. GET /api/v1/vehicles?make=&model= jest bezpłatny i publiczny oraz zwraca wszystkie roczniki danego modelu, każdy ze stałym identyfikatorem pojazdu, który Państwo zapiszą; POST /api/v1/images/resolve robi to samo na podstawie frazy, np. „2026 toyota rav4”.

Identyfikator jednego rocznika modelu
# 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"}
fleet.ts
// 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
};

Identyfikatory nigdy się nie zmieniają, więc ta mapa to jedyne miejsce, którego dotyczy zmiana floty: gdy klasa średnia przechodzi na inny model lub na kolejny rok modelowy, wystarczy podmienić jeden identyfikator, a każda karta, sekcja hero i e-mail odczytujące mapę zaktualizują się same.

Krok 2: jedna struktura żądania dla wszystkich klas

Widoki kamery (9) są kadrowane identycznie dla każdego pojazdu w katalogu i właśnie dzięki temu siatka jest równa. Reszta karty to kilka parametrów ustalanych raz:

  • view=side dla kart: każdy samochód jest zwrócony w tę samą stronę na tej samej linii bazowej. Każdy kąt lewej strony ma bliźniaczy wariant -right (side-right), więc karty mogą być zwrócone do wnętrza układu. Strona klasy używa front-3-4, czyli kąta głównego.
  • w=640&h=320&fit=contain: dokładnie 640×320 dla każdej klasy, z widocznym całym samochodem. Nagłówki odpowiedzi X-Image-Width i X-Image-Height potwierdzają rozmiar płótna.
  • trim=1&padding=6: przycięcie do samochodu przed dopasowaniem, z marginesem równym 6% jego dłuższego boku, dzięki czemu Corolla i Tahoe wypełniają swoje karty w ten sam sposób, zamiast unosić się w kwadratowej ramce źródłowej.
  • background=f4f4f4 nakłada obraz karty na tę samą szarość, której używa siatka. Pominięcie tego parametru zachowuje przezroczyste tło, przez które prześwituje kolor karty.
  • format=webp dla zapisywanych plików; format=auto w podpisanych adresach URL, który serwuje każdej przeglądarce WebP lub PNG.
Karta i baner główny dla jednej klasy
# 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

Krok 3: jeden nazwany lakier dla całej siatki

Predefiniowane kolory (15) to nazwane lakiery: white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple. Domyślny to silver, a grey jest traktowany jako gray. Warto wybrać jeden dla każdej klasy, aby karty tworzyły spójny zestaw; powyżej pokazano white. Każdy predefiniowany kolor ma własną próbkę lakieru zamiast koloru CSS o tej samej nazwie (red to #b3151b), a każdy lakier, także podany jako hex, jest przebarwieniem jednego przygotowanego widoku, więc każdy lakier to jeden obraz pojazdu.

Krok 4: buforowanie plików lub URL-i

Siatka klas jest identyczna dla każdego odwiedzającego, więc koszt jednej wizyty powinien być bliski zeru. Można to osiągnąć na dwa sposoby:

  • Przechowywanie plików. Każdą kartę i grafikę główną należy pobrać raz przez GET /api/v1/images/car i serwować z własnego CDN jak każdy inny zasób; plan płatny pozwala trzymać kopie na własnych serwerach do obsługi produktu, dopóki jest aktywny (należy je usunąć w ciągu 30 dni od jego zakończenia lub kupić Image Pack, by zachować zestaw na stałe). Warto zachować ETag każdego pliku: nocne ponowne sprawdzenie z If-None-Match zwraca 304 i nic nie kosztuje. Dla powyższej floty to 8 obrazów pojazdów w miesiącu, a każdego można używać dowolnie często.
  • Można też raz wygenerować podpisane URL-e i używać ich ponownie. POST /api/v1/image-urls przyjmuje do 50 obrazów na wywołanie i zwraca URL-e bez klucza, ważne do 7 dni. URL bez limitu użyć może być publicznie buforowany w okresie ważności, więc gdy każdy odwiedzający ładuje ten sam URL, kolejne wczytania są bezpłatnie obsługiwane przez CDN. Po dodaniu renew: true zapisany URL działa dalej po upływie okresu ważności; odnowienie liczy obraz raz w miesiącu, w którym nastąpi, i nic więcej, jeśli obraz został już policzony w tym miesiącu, więc powyższa flota zużywa miesięcznie najwyżej 8 obrazów pojazdów.

Klucz, który generuje adresy URL, należy ograniczyć do domeny serwisu rezerwacji w panelu — wtedy URL skopiowany na inną stronę zwróci 403.

URL-e siatki, generowane raz, za pomocą TypeScript SDK
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 }))
);

Krok 5: potwierdzenie rezerwacji

E-mail z potwierdzeniem pokazuje zarezerwowaną klasę, a e-maile są otwierane wtedy, gdy najemca do nich zajrzy. Zdjęcie warto wygenerować jako odnawiany URL: ttl_seconds ustawione na maksimum 7 dni, renew: true i renew_days sięgające poza datę zwrotu. Tygodnie, w których nikt nie otwiera e-maila, nic nie kosztują, a po zakończeniu wynajmu URL przestaje się odnawiać. Idempotency-Key dla każdej rezerwacji sprawia, że ponowiona wysyłka odtwarza pierwszy URL zamiast tworzyć drugi, a zapisanie URL przy rezerwacji pozwala wykorzystać go przy każdej kolejnej wysyłce. Tak działają nasze własne e-maile cyklu życia klienta; mechanizm i kod HTML opisuje historia o e-mailach.

Odnawiany adres URL dla jednego potwierdzenia
// 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 it

CLI, SDK i MCP

  • CLI: npx @meterapp/car-image get --vehicle veh_… --view side --width 640 --height 320 --fit contain --trim --padding 6 --out card.webp zapisuje kartę do pliku; car-image url --batch classes.json --renew generuje partię URL-i.
  • SDK: client.vehicles({ make, model }) dla identyfikatorów, client.getImage(…) dla plików, client.createImageUrls(…) dla adresów URL.
  • MCP: resolve_vehicle i create_car_image_urls pozwalają asystentowi przygotować kartę klasy na podstawie opisu „SUV średniej wielkości, RAV4 lub podobny”. Konfiguracja jest opisana na stronie MCP.

Najczęściej zadawane pytania

Czy karta może pokazywać dokładnie ten samochód, który otrzyma klient?
Nie, i nie powinien tego robić. Klasę wynajmuje się z zastrzeżeniem „lub podobny”, a render przedstawia markę, model i rocznik z katalogu, a nie samochód z Państwa parkingu. Należy pokazać jeden reprezentatywny model z dopiskiem „lub podobny” w opisie. Gdy przy ladzie zostanie przypisany konkretny samochód, jego VIN można bezpłatnie zdekodować do pojazdu z katalogu, jeśli chcą Państwo pokazać właśnie ten model.
Dlaczego samochody w siatce nie zachowują skali?
Ponieważ trim przycina każdy render do samochodu, a fit=contain wypełnia nim kartę, więc kompakt i pełnowymiarowy SUV wypełniają swoje karty tak samo. To utrzymuje porządek w siatce. Wielkość należy opisać słowami: nazwą klasy, liczbą miejsc i bagaży.
Ile kosztuje siatka klas?
Flota 4 klas z kartą i obrazem głównym dla każdej to 8 obrazów pojazdów miesięcznie, każdy dostarczany dowolnie często w dowolnym rozmiarze. Pliki przechowywane we własnym CDN przy aktywnym płatnym planie liczą się tylko w miesiącu pobrania, z bezpłatnym ponownym sprawdzaniem przez ETag. Jeśli zamiast tego serwowane są odnawiane podpisane URL-e, te same obrazy liczą się raz w każdym miesiącu, w którym strony są otwierane.
Jaki lakier zastosować w siatce klas?
Jeden gotowy kolor dla każdej klasy, aby karty wyglądały jak spójny zestaw. Dostępne gotowe kolory (15) to white, black, gray, silver, blue, red, green, brown, beige, tan, orange, yellow, gold, burgundy, purple, a domyślny to silver; działa też dowolny kod hex, w tej samej cenie. Klient wypożyczalni dostaje kolor samochodu, który stoi na parkingu, a karta nigdy nie obiecywała innego.
Co zrobić, jeśli modelu z danej klasy nie ma w katalogu?
Dla pojazdu, którego nie ma w katalogu, API zwraca 404 z sugestiami: najbliższymi pojazdami z katalogu, każdy z identyfikatorem. Można użyć jednego z nich lub poprosić o dodanie pojazdu na publicznej tablicy próśb. Katalog jest open source.

Czytaj dalej

Historia klienta · Narzędzia dla programistówJak osadzać zdjęcia samochodów w e-mailach za pomocą podpisanych URL-i, które nigdy nie przestają działaćNasze własne e-maile z cyklu życia klienta zawierają dokładnie pierwszy render każdego klienta jako aktywny podpisany URL, który sam się odnawia przez rok. Oto jak to działa i jak to powtórzyć.