Build · Virtual Try-On

Baue ein Virtual-Try-On-Feature für deine App

In aller Kürze

Nimm das Produktfoto in deinem Backend entgegen, sende es per POST an /api/v1/tryon/apparel mit einer mannequin ID, polle die zurückgegebene Generation-ID über einen Background-Worker (niemals im HTTP-Request-Thread), bis der Status auf completed wechselt, persistiere dann output_url in deinem eigenen Object Storage und rendere es im UI.

  • Credits: 5 Credits bei 2K · 6 Credits bei 4K
  • Typische Dauer: 1.5–4 min
  • Verarbeitung: asynchron, Polling

Jeder Zahlenwert auf dieser Seite stammt aus der Photta-API-Dokumentation · geprüft

Ein produktionsreifes Rezept: Kunde lädt ein Produktfoto hoch, dein Backend stellt einen Photta-Try-On-Job in die Queue, ein Worker pollt bis zur Fertigstellung, das Frontend zeigt das Ergebnis am Model. Keine blockierenden Requests, keine geleakten API-Keys, kein Pseudo-SDK.

RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
  -H "Authorization: Bearer $PHOTTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "product_type": "top",
  "product_images": [
    "https://cdn.yourstore.com/products/shirt-front.jpg"
  ],
  "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
  "product_category": "t_shirt",
  "mannequin_id": "mnk_f3a9b1",
  "pose_id": "pose_c2d4e5",
  "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
  "lock_background": true,
  "resolution": "2K",
  "aspect_ratio": "3:4",
  "body_size": "M",
  "expression": "neutral",
  "user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')

Funktionsweise

Vom Upload zum Bild am Model

Sechs konkrete Schritte. Rechne beim ersten Mal mit zehn bis fünfzehn Minuten Integrationsaufwand.

  1. Schritt 1

    Datenfluss skizzieren

    Kundengerät → dein Backend (Upload) → Photta API (Submit) → Photta API (Poll) → deine Datenbank (Status-Mirror) → Kundengerät (Rendern). Zeichne das auf Papier auf, bevor du die erste Zeile schreibst — die Schnittstelle zwischen deinem Backend und dem von Photta ist das Einzige, worauf es ankommt.

  2. Schritt 2

    API-Key generieren und speichern

    Live-Keys beginnen mit photta_live_. Speichere ihn in einer Umgebungsvariablen. Liefere ihn niemals an den Browser aus. Ein einziger Key deckt jede Photta-Funktion ab, du brauchst also keine separaten Keys für Try-On, Jewelry oder Ghost Mannequin.

  3. Schritt 3

    Upload-Endpoint anbinden

    Nimm das Produktfoto des Kunden zuerst in deinem Object Storage entgegen. Photta eine öffentliche URL zu übergeben ist einfacher als Base64 und liefert dir einen Audit-Trail für jeden Request.

  4. Schritt 4

    Job vom Server aus absenden

    POST /api/v1/tryon/apparel mit der Produkt-URL, mannequin_id, Auflösung und aspect_ratio. Die API antwortet mit 202 Accepted + einer Generation-ID. Speichere die ID in deiner Datenbank, damit dein Client deinen eigenen Endpoint pollt, nicht den von Photta.

  5. Schritt 5

    Über einen Background-Worker pollen

    Polle nicht innerhalb des HTTP-Requests — der Job dauert 1.5 bis 4 Minuten, was die meisten Serverless-Timeouts überschreitet. Nutze Trigger.dev, Inngest, BullMQ, Vercel Cron oder deine eigene Queue, um alle 3 Sekunden einen erneuten Poll-Versuch einzuplanen, bis der Job abgeschlossen ist.

  6. Schritt 6

    Ergebnis rendern

    Sobald der Status auf completed wechselt, kopiere data.output_url in deine Datenbank und sende ein Realtime-Event (WebSocket, SSE oder Long-Polling) an das Kundengerät. Das UI tauscht das Loading-Skeleton gegen das Bild aus. Fertig.

Drei Code-Beispiele, End-to-End

Upload-Handler, Job-Dispatcher, worker-seitiger Poller — alle Bausteine, die du für das Feature brauchst.

// POST /app/try-on → your backend upload handler
import { put } from "@vercel/blob";

export async function uploadProduct(file: File) {
  const { url } = await put(`products/${crypto.randomUUID()}.jpg`, file, {
    access: "public",
  });
  return url;
}
const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "product_type": "top",
    "product_images": [
      "https://cdn.yourstore.com/products/shirt-front.jpg"
    ],
    "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
    "product_category": "t_shirt",
    "mannequin_id": "mnk_f3a9b1",
    "pose_id": "pose_c2d4e5",
    "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
    "lock_background": true,
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "body_size": "M",
    "expression": "neutral",
    "user_instruction": "Keep the collar pattern crisp and centered."
  }),
});
const { data } = await res.json(); // data.id, data.status
// Trigger.dev / Inngest / BullMQ task
const BASE = "https://api.photta.app/api/v1";

export const pollTryOnTask = task({
  id: "poll-try-on",
  run: async ({ generationId, attempt = 0 }) => {
    const res = await fetch(`${BASE}/tryon/apparel/${generationId}`, {
      headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` },
    });
    const { data } = await res.json();
    if (data.status === "completed") return data.output_url;
    if (data.status === "failed") throw new Error(data.error_message);
    if (attempt >= 120) throw new Error("try-on timed out");
    // Re-schedule this same task after 3 seconds.
    return ctx.retry.after(3000, { generationId, attempt: attempt + 1 });
  },
});

Häufige Fragen von Entwicklern

Fragen vor dem Go-Live

Geht das auch ohne Backend?

Nein. Dein Photta-API-Key muss serverseitig bleiben. Selbst ein einfacher Next.js Route Handler oder ein Cloudflare Worker gilt dafür als Backend – der Key muss lediglich an einem Ort liegen, den ein User-Agent nicht auslesen kann.

Wie verhindere ich hängende HTTP-Requests?

Niemals innerhalb eines Request Handlers pollen. Übergib den Job synchron, gib die Generation-ID an den Client zurück und führe das Polling über einen Background Worker aus. Der Client pollt DEINEN Status-Endpoint, nicht den von Photta – so sind Rate Limits dein Problem und nicht das jedes einzelnen Nutzers.

Was passiert, wenn ein Job mittendrin fehlschlägt?

Photta erstattet die Credits bei einem Fehlschlag automatisch zurück, und die Response enthält data.error_code + data.error_message. Zeige dem Nutzer eine verständliche Fehlermeldung an und biete einen Retry-Button, der einen neuen Job anstößt.

Kann ich echten Fortschritt anzeigen?

Photta liefert keinen Zwischenstatus – der Status ist entweder processing, completed oder failed. Gut funktioniert ein zeitbasierter Fortschrittsbalken, der auf das Zeitfenster von 1,5–4 Minuten kalibriert ist, oder ein einfacher Skeleton Loader. Mache keine falschen Prozentangaben.

Ist die Ergebnis-URL permanent?

Die CDN-URL ist stabil, aber dein Produkt sollte sich beim langfristigen Rendern nicht darauf verlassen. Lade die Bytes einmalig herunter und speichere sie in deinem eigenen S3/GCS/R2-Bucket – dann funktioniert deine PDP auch weiter, falls das CDN von Photta umzieht.

Virtual Try-on an einem Nachmittag deployen

Jedes Codebeispiel auf dieser Seite entspricht der offiziellen Photta-Dokumentation. Hol dir einen API-Key, und du hast einen funktionierenden Prototyp, noch bevor der Kaffee fertig gebrüht ist.