Node.js · Virtual Try-On API

Virtual Try-On API in Node.js

Es gibt noch kein @photta/node Paket — und Sie brauchen auch keines. Node 18+ unterstützt `fetch` nativ, und ein 20-Zeilen-Helper bringt Sie in etwa fünf Minuten zu Ihrem ersten On-Model-Bild.

Kurz zusammengefasst

Setzen Sie `PHOTTA_API_KEY` in env, schreiben Sie einen kleinen `phottaFetch()` Helper, der `https://ai.photta.app/api/v1` mit `Authorization: Bearer photta_live_xxx` aufruft, POST an `/tryon/apparel` mit Produkt-URL, Mannequin-ID und Pose-ID, dann pollen Sie `/tryon/apparel/:id` alle 3 Sekunden bis `status === 'completed'` — typischerweise innerhalb von 1.5–4 Minuten.

Aktualisiert · 2026-04-19

Ihr erster Request

Node.jsPythoncURLcURL
import { phottaFetch } from "./photta.js";

// 1. Submit the job — returns a generation ID immediately.
const created = await phottaFetch("/tryon/apparel", {
  method: "POST",
  body: JSON.stringify({
    product_type: "dress",
    product_images: ["https://example.com/dress.jpg"],
    mannequin_id: "mnq_athena_ts",
    pose_id: "pose_standing_front",
    resolution: "2K",
    aspect_ratio: "3:4",
  }),
});
const generationId = created.data.id;

// 2. Poll every 3 seconds until processing completes. Typical
// completion is 1.5–4 minutes; put an upper bound so a stuck
// job can't hang your request forever.
const pollInterval = 3000;
const maxAttempts = 120;     // 120 × 3s = 6 minutes
let result;

for (let i = 0; i < maxAttempts; i++) {
  result = await phottaFetch(`/tryon/apparel/${generationId}`);
  if (result.data.status === "completed") break;
  if (result.data.status === "failed") {
    throw new Error(result.data.error_message);
  }
  await new Promise((r) => setTimeout(r, pollInterval));
}

console.log("Result:", result.data.output_url);

Was Sie erwartet

Typical completion

1–3min

2K / 4K credits

4 / 6

Styles

2

Batch-ready

yes

Funktionsweise

Virtual Try-On API in Node.js

Fünf Schritte, etwa fünf Minuten vom Signup zum ersten Bild.

  1. 01

    Schritt 1

    Registrieren und Key generieren

    Erstellen Sie einen Account auf ai.photta.app. Öffnen Sie den Developers-Bereich, klicken Sie auf Generate API key und kopieren Sie den Live-Key. Er beginnt mit `photta_live_`, gefolgt von 32 Hex-Zeichen.

  2. 02

    Schritt 2

    Key in env speichern, nicht im Quellcode

    Fügen Sie `PHOTTA_API_KEY=...` zur `.env` (oder dem Secret-Store Ihrer Plattform) hinzu und laden Sie ihn via `process.env`. Committen Sie den Key niemals; importieren Sie ihn niemals in Dateien mit `'use client'`, da der Bundler ihn sonst in den Browser zieht.

  3. 03

    Schritt 3

    Einen kleinen Fetch-Helper schreiben

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

  4. 04

    Schritt 4

    Try-On senden und pollen

    POST an `/tryon/apparel` mit `product_type`, `product_images`, `mannequin_id`, `pose_id`, `resolution` und `aspect_ratio`. Die API liefert sofort eine Generations-ID. Pollen Sie `/tryon/apparel/:id` alle 3 Sekunden bis `status === 'completed'`.

  5. 05

    Schritt 5

    Ergebnis persistieren

    Die fertige Payload enthält `output_url` und `thumbnail_url`. Laden Sie die Daten einmal herunter und speichern Sie sie in Ihrem eigenen Object-Storage — die URLs sind stabil, aber Ihr Produkt sollte für das Rendering nicht vom Photta-CDN abhängen.

Code, End-to-End

Copy, paste, done.

Four snippets — install prerequisites, wrap the REST call, submit + poll, then handle the errors that actually happen in production.

01No SDK required — use native fetch in Node 18+
bash
# Node 18+ ships fetch natively. No install step needed.
node --version   # ensure v18 or later

# Optional: keep your API key out of source control
echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env
02Wrap the REST call in a tiny client helper
javascript
// photta.js — a 20-line wrapper you can reuse across your app.
const PHOTTA_BASE_URL = "https://ai.photta.app/api/v1";

export async function phottaFetch(path, init = {}) {
  const res = await fetch(`${PHOTTA_BASE_URL}${path}`, {
    ...init,
    headers: {
      "Authorization": `Bearer ${process.env.PHOTTA_API_KEY}`,
      "Content-Type": "application/json",
      ...init.headers,
    },
  });
  const body = await res.json();
  if (!res.ok) {
    const err = new Error(body?.error?.message ?? res.statusText);
    err.status = res.status;
    err.code = body?.error?.code;
    throw err;
  }
  return body;
}
03Submit a try-on job and poll until it lands
javascript
import { phottaFetch } from "./photta.js";

// 1. Submit the job — returns a generation ID immediately.
const created = await phottaFetch("/tryon/apparel", {
  method: "POST",
  body: JSON.stringify({
    product_type: "dress",
    product_images: ["https://example.com/dress.jpg"],
    mannequin_id: "mnq_athena_ts",
    pose_id: "pose_standing_front",
    resolution: "2K",
    aspect_ratio: "3:4",
  }),
});
const generationId = created.data.id;

// 2. Poll every 3 seconds until processing completes. Typical
// completion is 1.5–4 minutes; put an upper bound so a stuck
// job can't hang your request forever.
const pollInterval = 3000;
const maxAttempts = 120;     // 120 × 3s = 6 minutes
let result;

for (let i = 0; i < maxAttempts; i++) {
  result = await phottaFetch(`/tryon/apparel/${generationId}`);
  if (result.data.status === "completed") break;
  if (result.data.status === "failed") {
    throw new Error(result.data.error_message);
  }
  await new Promise((r) => setTimeout(r, pollInterval));
}

console.log("Result:", result.data.output_url);
04Handle 402 credit exhaustion and 429 rate limits
javascript
try {
  await phottaFetch("/tryon/apparel", {
    method: "POST",
    body: JSON.stringify({ /* … */ }),
  });
} catch (err) {
  if (err.status === 402) {
    // Out of credits — surface a top-up CTA to the user.
    // err.code === "insufficient_credits"
  } else if (err.status === 429) {
    // Rate-limited. Honour the Retry-After header.
    const retryAfter = err.retryAfter ?? 30;
    await new Promise((r) => setTimeout(r, retryAfter * 1000));
    // Then retry…
  } else if (err.status >= 500) {
    // Server-side issue — backoff + retry.
  }
  throw err;
}

Warum diese Struktur

Warum ein Helper aktuell besser ist als eine Library

  • Node 18+ ships native fetch — no runtime deps required
  • Same helper works inside Next.js route handlers, API routes, server actions and edge functions
  • Keep API keys in env; never import the helper from a 'use client' module or the bundler will leak them
  • Works with any queue/cron: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues

Was es nicht kann

Honest caveats

  • No official @photta/node SDK yet — REST is the only path today
  • No built-in webhook delivery; polling is the documented pattern (3–5s interval)
  • Bearer token lives in env; the API doesn't support OAuth client credentials yet

Fragen anderer Entwickler

Questions other developers ask

Gibt es ein offizielles Photta Node.js SDK?+

Noch nicht. Die Dokumentation plant SDKs nach Erreichen bestimmter Nutzerzahlen: Python ab zehn API-Kunden, Node.js ab zwanzig. Bis dahin ist der dokumentierte Weg natives REST via cURL, Node fetch oder Python requests. Der 20-Zeilen-Helper auf dieser Seite entspricht funktional einem Client für die meistgenutzten Endpunkte.

Welche Node.js Versionen werden unterstützt?+

Alle Versionen mit nativem `fetch`-Support — also Node 18 und neuer. Bei Node 16 nutzen Sie entweder ein Polyfill wie `node-fetch` oder führen ein Upgrade durch. Der restliche Code ist Standard-ECMAScript 2020 (async/await, Template Literals, Dynamic Imports).

Wie authentifiziere ich mich in Node?+

Senden Sie `Authorization: Bearer photta_live_xxx` bei jedem Request. Der Key beginnt in Produktion mit `photta_live_`, im Sandbox-Modus (sobald verfügbar) mit `photta_test_`. Nutzen Sie Umgebungsvariablen über `process.env.PHOTTA_API_KEY`. OAuth oder Session-basierte Auth werden noch nicht unterstützt.

Wie gehe mit dem 1.5–4 Minuten Zeitfenster um?+

Der Try-On-Endpunkt ist vollständig asynchron. POST liefert sofort eine Generations-ID mit `status: 'processing'`. Pollen Sie `GET /tryon/apparel/:id` alle 3–5 Sekunden, bis der `status` auf `completed` oder `failed` wechselt. Begrenzen Sie die Anzahl der Versuche — 120 Versuche alle 3 Sekunden decken das dokumentierte Fenster mit Puffer ab.

Kann ich die API innerhalb von Next.js aufrufen?+

Ja — aus einem Route Handler (`app/**/route.ts`), einer Server Action (`'use server'`) oder einer Middleware. Halten Sie den API-Key auf dem Server; importieren Sie den Helper niemals in einer `'use client'` Datei. Bei Jobs, die das Vercel-Timeout überschreiten, lagern Sie das Polling in eine Queue aus (Inngest, Trigger.dev, BullMQ) und geben die Generations-ID an den Browser zurück, damit dieser einen Webhook oder Ihren Status-Endpunkt abfragen 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` Hinweis; 402 insufficient_credits mit Zähler für `required` und `available`; 429 rate_limit_exceeded mit `retry_after` Angabe. 5xx-Fehler können mit Exponential Backoff erneut versucht werden.

Node.js · Virtual Try-On API

Account erstellen und API-Key erhalten

Setzen Sie `PHOTTA_API_KEY` in env, schreiben Sie einen kleinen `phottaFetch()` Helper, der `https://ai.photta.app/api/v1` mit `Authorization: Bearer photta_live_xxx` aufruft, POST an `/tryon/apparel` mit Produkt-URL, Mannequin-ID und Pose-ID, dann pollen Sie `/tryon/apparel/:id` alle 3 Sekunden bis `status === 'completed'` — typischerweise innerhalb von 1.5–4 Minuten.

Virtual Try-On API für Node.js — Photta | Photta