Node.js · Ghost-Mannequin-API

Ghost-Mannequin-API in Node.js

In aller Kürze

Setzen Sie PHOTTA_API_KEY im Env, schreiben Sie einen kleinen fetch-Helper für https://api.photta.app/api/v1 mit einem Bearer-Key, senden Sie einen POST an /api/v1/ghost-mannequin und pollen Sie /api/v1/ghost-mannequin/{id} alle 3 Sekunden, bis der Status completed ist.

  • Typische Dauer: 1.5–4 min
  • Credits: 4 Credits bei 2K · 5 Credits bei 4K
  • Verarbeitung: asynchron, Polling
  • Limits: 600 Anfragen/Min.
  • Authentifizierung: Bearer-Key

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

POST/api/v1/ghost-mannequin
const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
    "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
    "image_side": "front",
    "angle": "side",
    "style": "3d",
    "background_color": "white",
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "user_instruction": "closed front, cream interior lining",
    "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
  }),
});
const { data } = await res.json(); // data.id, data.status

async function waitFor(id) {
  for (let attempt = 0; attempt < 120; attempt++) {
    const res = await fetch(`https://api.photta.app/api/v1/ghost-mannequin/${id}`, { 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 ?? "generation failed");
    await new Promise((r) => setTimeout(r, 3000));
  }
  throw new Error("timed out after 6 minutes");
}

Auf einen Blick

Auf einen Blick

Endpoint
POST /api/v1/ghost-mannequin
Authentifizierung
Bearer-API-Schlüssel
Verarbeitung
Asynchron — Polling über den Status-Endpoint
Typische Dauer
1.5–4 min
Credits
4 Credits bei 2K · 5 Credits bei 4K
Seitenverhältnisse
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Eingabelimits
Bis zu 10 MB pro Bild; JPEG, PNG, WebP
Idempotent
Nein

Funktionsweise

Fünf Schritte, etwa fünf Minuten von der Registrierung bis zum ersten Bild.

  1. Schritt 1

    Registrieren und Key generieren

    Erstellen Sie einen Account unter ai.photta.app. Öffnen Sie den Entwicklerbereich im Dashboard, klicken Sie auf API-Key generieren und kopieren Sie den Live-Key. Er beginnt mit `photta_live_`, gefolgt von 32 Hexadezimalzeichen.

  2. Schritt 2

    Key im Env speichern, nicht im Sourcecode

    Fügen Sie `PHOTTA_API_KEY=...` zu `.env` (oder dem Secret-Store Ihrer Plattform) hinzu und laden Sie ihn über `process.env`. Den Key niemals committen; niemals in eine Datei mit der Kennzeichnung `'use client'` importieren — der Bundler bindet ihn sonst im Browser ein.

    node --version   # 18 or later ships fetch
    echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env
  3. Schritt 3

    Schreiben Sie einen winzigen fetch-Helper

    Ein 20-zeiliger Wrapper um `fetch()` verarbeitet die Basis-URL, den Authorization-Header, den JSON-Body und die Fehlernormalisierung. Dies ist die einzige Abstraktion, die Sie benötigen, bis ein offizielles SDK veröffentlicht wird.

    // photta.js — one helper for every endpoint
    const BASE = "https://api.photta.app/api/v1";
    export async function photta(path, init = {}) {
      const res = await fetch(BASE + path, { ...init, headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json", ...(init.headers ?? {}) } });
      const body = await res.json();
      if (!res.ok) throw Object.assign(new Error(body.error?.message ?? res.statusText), { status: res.status, retryAfter: res.headers.get("Retry-After"), body });
      return body;
    }
  4. Schritt 4

    Einen Try-on absenden und pollen

    Senden Sie einen POST-Request an `/api/v1/ghost-mannequin` mit dem dokumentierten Beispiel-Body — der folgende Code enthält jedes Feld. Die API liefert sofort eine Generation-ID zurück. Pollen Sie `/api/v1/ghost-mannequin/{id}` alle 3 Sekunden, bis `status === 'completed'` gilt.

    const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({
        "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
        "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
        "image_side": "front",
        "angle": "side",
        "style": "3d",
        "background_color": "white",
        "resolution": "2K",
        "aspect_ratio": "3:4",
        "user_instruction": "closed front, cream interior lining",
        "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
      }),
    });
    const { data } = await res.json(); // data.id, data.status
    
    async function waitFor(id) {
      for (let attempt = 0; attempt < 120; attempt++) {
        const res = await fetch(`https://api.photta.app/api/v1/ghost-mannequin/${id}`, { 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 ?? "generation failed");
        await new Promise((r) => setTimeout(r, 3000));
      }
      throw new Error("timed out after 6 minutes");
    }
  5. Schritt 5

    Das Ergebnis persistieren

    Die abgeschlossene Payload enthält `output_url` und `thumbnail_url`. Rufen Sie die Bytes einmal ab und speichern Sie sie in Ihrem eigenen Objektspeicher — die URLs sind stabil, aber Ihr Produkt sollte für das Rendering nicht vom CDN von Photta abhängen.

Fehler

400invalid_request_error
The request is malformed or contains invalid parameters.
401authentication_error
The API key is missing, invalid, or expired.
402insufficient_credits_error
Your account does not have enough credits.
404not_found_error
The requested resource does not exist.
409conflict_error
The request conflicts with current state — e.g. your concurrent-batch cap is reached.
429rate_limit_error
Too many requests. Slow down and retry.Retry-After: 30
500api_error
An internal server error occurred. Retry later.
try {
  await photta("/ghost-mannequin", { method: "POST", body: JSON.stringify({
    "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
    "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
    "image_side": "front",
    "angle": "side",
    "style": "3d",
    "background_color": "white",
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "user_instruction": "closed front, cream interior lining",
    "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
  }) });
} catch (err) {
  if (err.status === 402) console.error("insufficient_credits_error: top up before retrying");
  else if (err.status === 429) await new Promise((r) => setTimeout(r, Number(err.retryAfter ?? 30) * 1000));
  else throw err;
}

Limits

  • 600 Anfragen pro Minute pro API-Schlüssel (Festes Zeitfenster; das Limit ist in jedem Tarif identisch)
  • Ein 429 enthält Retry-After: 30 Sekunden
  • Bis zu 10 MB pro Bild
  • Formate: JPEG, PNG, WebP
  • Gleichzeitige Batches pro Tarif: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Nur Polling — die API sendet keine Webhooks.

Warum ein Helper besser ist als eine Client-Bibliothek — vorerst

  • Node 18+ bringt natives fetch mit — keine Laufzeit-Abhängigkeiten
  • Derselbe Helper funktioniert innerhalb von Next.js Route Handlers, Server Actions und jedem Worker
  • Behalten Sie den API-Key in env; importieren Sie den Helper niemals aus einem 'use client'-Modul, da der Bundler ihn sonst leakt
  • Funktioniert mit jeder Queue oder jedem Cron: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues

Was es nicht tut

  • Noch kein offizielles @photta/node-Paket — REST ist derzeit der einzige Weg
  • Polling ist das einzige Signal für den Abschluss; die API sendet keine Webhooks
  • Nur Bearer-Keys; es gibt keinen OAuth-Client-Credentials-Flow

Häufige Fragen von Entwicklern

Gibt es ein offizielles Photta Node.js-SDK?

Noch nicht. Der dokumentierte Weg ist reines REST über das native fetch von Node — der Helper auf dieser Seite deckt die gesamte Integrationsfläche ab und funktioniert für jede Capability identisch.

Welche Node.js-Versionen werden unterstützt?

Alles, was natives `fetch` unterstützt — also Node 18 und neuer. Unter Node 16 verwenden Sie entweder einen Polyfill mit `node-fetch` oder führen ein Upgrade durch. Der restliche Code ist reines ECMAScript 2020 (async/await, Template-Literale, dynamische Importe), es gibt also keine weiteren Laufzeit-Anforderungen.

Wie authentifiziere ich mich aus Node?

Senden Sie `Authorization: Bearer photta_live_xxx` bei jedem Request. Hinterlegen Sie den Key in einer Umgebungsvariable und laden Sie ihn über `process.env`; importieren Sie ihn niemals aus einer Datei, die im Browser ausgeführt wird.

Wie gehe ich mit dem Generierungsfenster um?

Der Generierungs-Endpoint ist vollständig asynchron. POST gibt sofort eine Generation-ID mit `status: 'processing'` zurück. Pollen Sie `GET /api/v1/ghost-mannequin/{id}` alle 3–5 Sekunden, bis der `status` auf `completed` oder `failed` wechselt, und begrenzen Sie die Versuche, damit ein hängengebliebener Job keinen Request blockiert.

Kann ich die API innerhalb von Next.js aufrufen?

Ja — über einen Route Handler (`app/**/route.ts`), eine Server Action (`'use server'`) oder Middleware. Halten Sie den API-Key auf dem Server; importieren Sie den Helper niemals aus einer `'use client'`-Datei. Bei lang laufenden Jobs, die das Funktions-Timeout von Vercel überschreiten, lagern Sie das Polling in eine Queue aus (Inngest, Trigger.dev, BullMQ) und geben die Generation-ID an den Browser zurück, damit dieser Ihren eigenen Status-Endpoint pollen kann.

Wie signalisiert die API Fehler?

Nicht-2xx-Antworten enthalten einen JSON-Body mit einem `error`-Objekt: `type`, `code`, `message` und eine Request-ID für den Support. Häufige Fälle: 400 invalid_request_error mit `param`, das auf das fehlerhafte Feld verweist; 402 insufficient_credits mit Zählerständen für `required` und `available`; 429 rate_limit_exceeded mit `retry_after` in Sekunden und einem passenden Retry-After-Header. 5xx-Fehler können sicher mit exponentiellem Backoff wiederholt werden.

Testen Sie die API in fünf Minuten

Generieren Sie einen Photta-API-Schlüssel, fügen Sie das obige cURL-Snippet ein, und Sie erhalten Ihr erstes Bild am Model, noch bevor der Kaffee fertig gebrüht ist.

  • 1.5–4 min
  • 4 Credits bei 2K · 5 Credits bei 4K
  • asynchron, Polling
  • 600 Anfragen/Min.
  • Bearer-Key