Car Image API

Clienți · Car Image API

Cum să includeți imagini cu mașini în e-mailuri cu URL-uri semnate care nu se strică niciodată

Car Image API trimite prima randare a fiecărui client direct în inbox, cu un URL semnat care se reînnoiește automat: mecanismul, calculele și codul pentru a face asta chiar dumneavoastră.

Problema: o imagine care trebuie să funcționeze și în martie

Fiecare cont Car Image API primește un scurt mesaj de la Jonathan la aproximativ o oră după prima sa randare. Cel mai evident lucru de pus în acel e-mail este chiar randarea: exact Porsche 911 din 2024 sau Dodge Charger din 2006 pe care persoana tocmai l-a cerut, ca dovadă că integrarea a funcționat și ca mică laudă.

E-mailul este cea mai nepotrivită suprafață posibilă pentru un URL semnat. O pagină este randată din nou la fiecare vizită; un e-mail este randat o singură dată și deschis oricând ajunge cititorul la el, peste o zi, o lună sau un an, adesea prin proxy-ul de imagini al Gmail. URL-urile semnate de livrare pe care API-ul le oferea deja aveau un TTL maxim de șapte zile, plafonul potrivit pentru un browser, dar care garantează o imagine nefuncțională în inbox până în a doua săptămână. Atașarea sau includerea inline a PNG-ului îngreunează fiecare mesaj.

Ce ne doream era un URL care să se comporte ca o imagine găzduită, să funcționeze cât timp cineva ar putea deschide e-mailul și totuși să taxeze contul corect pentru ceea ce servește efectiv.

Soluția: URL-uri semnate cu reînnoire automată

Am adăugat un singur parametru la POST /api/v1/image-urls: renew: true. Un URL reînnoibil se generează exact ca oricare altul, își numără imaginea ca imagine de vehicul a lunii și este valabil ttl_seconds. Diferența apare după expirarea TTL-ului. În loc de un 403, prima încărcare din fiecare nouă fereastră de ttl_seconds reînnoiește URL-ul și servește imaginea; o reînnoire numără imaginea o dată în luna în care are loc și nimic în plus dacă a fost deja numărată în acea lună. Orice altă încărcare din fereastra respectivă poate fi memorată public în cache, la fel ca în prima fereastră. Așa continuă până la renews_until, cu cel mult un an înainte.

Din acest design au rezultat trei proprietăți, iar fiecare a contat pentru e-mail:

  • Nimic de retrimis sau de regenerat. URL-ul din e-mail rămâne același pentru totdeauna. Fără cron job care rescrie linkurile stocate, fără un al doilea e-mail cu o imagine nouă.
  • Se numără deschiderile, nu timpul. O fereastră în care nimeni nu deschide e-mailul nu se numără deloc. Un e-mail citit de o singură persoană într-o singură zi contează ca o singură imagine de vehicul, cea pentru care a fost emis URL-ul; unul deschis în fiecare săptămână timp de un an numără acea imagine o dată în fiecare lună în care este deschis, de cel mult douăsprezece ori.
  • Contorizare idempotentă. Fiecare fereastră este înregistrată o singură dată, cu cheia renew:<url id>:<window>, unică pentru fiecare URL și fereastră. Cincizeci de deschideri într-o săptămână sau două proxy-uri de e-mail care concurează la prima deschidere se contorizează o singură dată.

E-mailurile de ciclu de viață generează aceste URL-uri prin aceeași cale de cod pe care o folosește endpointul public, ca tokenuri de platformă: nelegate de vreo cheie API și niciodată facturate, pentru că sunt ale noastre, dar servite de aceeași rută GET /api/v1/delivery/{token}, cu aceleași ferestre de șapte zile și același caching. Imaginea din e-mailul primei randări este produsul care se demonstrează singur.

Generați un URL reînnoibil pentru prima randare a clientului
curl -X POST https://carimage.dev/api/v1/image-urls \
  -H "Authorization: Bearer $CAR_IMAGE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"images":[{"make":"porsche","model":"911","year":2024,"view":"front-3-4","color":"red","width":480}],"ttl_seconds":604800,"renew":true}'
201 Created
{
  "data": [
    {
      "id": "3f0c2a7e-1c1e-4c2a-9c39-4f1f0a4b2d10",
      "url": "https://carimage.dev/api/v1/delivery/eyJhbGciOi…",
      "expires_at": "2026-09-21T09:00:00.000Z",
      "max_uses": 0,
      "renews_until": "2027-09-14T09:00:00.000Z",
      "vehicle": {
        "make": "porsche",
        "model": "911",
        "year": 2024,
        "view": "front-3-4",
        "color": "red",
        "width": 480,
        "format": "png"
      }
    }
  ],
  "billing": {
    "charged_on": "creation",
    "credits_charged": 1,
    "credits_remaining": 4869,
    "credits_per_url": 1,
    "renewal": {
      "window_seconds": 604800,
      "credits_per_window": 1,
      "until": "2027-09-14T09:00:00.000Z"
    }
  },
  "request_id": "req_01j9x…"
}

E-mailul propriu-zis

Șablonul este React Email cu stiluri inline, deoarece clienții de e-mail elimină foile de stil. Randarea stă într-o celulă de tabel cu chenar, pe un fundal discret, solicitată la 480 pixeli și afișată la 240, ca să rămână clară pe ecranele retina, cu o etichetă rotunjită deasupra și două rânduri de descriere dedesubt. PNG-ul transparent este esența produsului, așa că îl păstrăm; pe un Outlook vechi care colorează canalul alfa în negru, soluția de rezervă este o randare format: "jpg" pe un fundal de celulă uniform.

Cardul, ca HTML simplu
<!-- inline styles only: mail clients strip stylesheets -->
<table role="presentation" width="100%" cellpadding="0" cellspacing="0">
  <tr>
    <td align="center" style="padding:24px;background:#fafaf9;border:1px solid #e7e5e4;border-radius:16px;">
      <img
        src="https://carimage.dev/api/v1/delivery/eyJhbGciOi…"
        alt="2024 Porsche 911, red, front three-quarter view"
        width="240" height="240"
        style="display:block;margin:0 auto;max-width:100%;height:auto;"
      />
      <p style="margin:14px 0 2px;font:700 18px/26px -apple-system,Segoe UI,Roboto,sans-serif;color:#1c1917;">2024 Porsche 911</p>
      <p style="margin:0;font:13px/20px ui-monospace,Menlo,monospace;color:#78716c;">Front three-quarter · Red</p>
    </td>
  </tr>
</table>

Tot restul mesajului este text: ce este URL-ul, de ce continuă să funcționeze, cererea POST exactă prin care pot genera unul pentru propriul vehicul și un link către această pagină. E-mailul conține un link de dezabonare și antetele List-Unsubscribe, iar fiecare link de produs este etichetat, astfel încât să putem vedea, în raportul de achiziție, dacă povestea pe care o citiți a adus pe cineva înapoi.

Faceți-o chiar dumneavoastră, în trei pași

  1. Generați pe server, când construiți e-mailul. Un apel per vehicul sau până la cincizeci per apel pentru un rezumat. Stocați url și renews_until împreună cu mesajul.
  2. Puneți URL-ul într-un <img> cu lățime, înălțime și text alternativ. Textul alternativ numește vehiculul („Porsche 911 2024, roșu, vedere frontală din trei sferturi”), nu „mașină”.
  3. Mențineți contul alimentat. O reînnoire contorizează imaginea o singură dată în luna în care are loc; dacă imaginile de vehicule ale planului sunt epuizate, răspunde cu 402 până când cota se resetează pe 1 ale lunii, așa că dimensionați planul în funcție de imaginile pe care le serviți.
Cu SDK-ul TypeScript
import { CarImageClient } from "@meterapp/car-image-sdk";

const client = new CarImageClient({ apiKey: process.env.CAR_IMAGE_API_KEY });

// One call per email: the vehicle the person rendered, at 2x the display width.
const { data } = await client.createImageUrls(
  [{ make: "porsche", model: "911", year: 2024, view: "front-3-4", color: "red", width: 480 }],
  { ttlSeconds: 604_800, renew: true, renewDays: 365 }
);
const src = data[0].url; // drop into <img src>, store data[0].renews_until next to it

Referința completă a parametrilor, antetele de caching și codurile de eroare se găsesc în documentația despre URL-urile semnate. Abilitatea de agent livrată cu pluginul cunoaște aceleași reguli, astfel încât un asistent căruia i se cere să „pună această mașină în newsletter” generează un URL reînnoibil în loc să lipească o cheie într-un șablon.

Întrebări frecvente

De ce să nu atașați imaginea sau să o includeți inline ca base64?
Atașamentele și base64 îngreunează fiecare mesaj. Un URL semnat are câteva sute de octeți și se încarcă prin proxy-ul de imagini al clientului de e-mail, ca orice imagine găzduită.
Cât costă un URL cu reînnoire automată?
O imagine de vehicul a lunii la creare, apoi aceeași imagine contorizată o dată în fiecare lună ulterioară în care o fereastră de reînnoire este efectiv deschisă, până la renews_until; o lună în care nimeni nu deschide e-mailul nu contorizează nimic. Pro, la 49 USD pe lună, include 2.500 imagini de vehicul pe lună.
Ce se întâmplă când imaginile de vehicul ale lunii s-au epuizat?
Încărcarea răspunde cu 402, iar imaginea apare ca defectă până la resetarea alocării lunare sau până la trecerea la un plan superior; URL-ul în sine rămâne valid și funcționează din nou la următoarea încărcare. O imagine deja contorizată luna aceasta continuă să fie servită.
Funcționează în Gmail, Outlook și Apple Mail?
Da. Endpointul de livrare este un simplu GET public cu Cache-Control, un ETag și antete CORS, exact ceea ce așteaptă proxy-urile de imagini. Transparența PNG se afișează corect în toți clienții actuali; pentru versiunile foarte vechi de Outlook, solicitați formatul jpg pe un fundal uniform.
Poate fi revocat un URL?
Revocați cheia API care l-a generat și fiecare URL creat cu acea cheie va răspunde cu 403 la următoarea încărcare, inclusiv reînnoirile. Cache-urile partajate continuă să servească imaginea cel mult o oră după aceea.