Node.js · Virtuel Try-On API

Virtuel Try-On API i Node.js

Der findes endnu ikke en @photta/node-pakke — og du har ikke brug for en. Node 18+ understøtter `fetch` nativt, og en helper på 20 linjer giver dig dit første on-model billede på omkring fem minutter.

Kort fortalt

Sæt `PHOTTA_API_KEY` i env, skriv en lille `phottaFetch()` helper, der kalder `https://ai.photta.app/api/v1` med `Authorization: Bearer photta_live_xxx`, lav en POST til `/tryon/apparel` med en produktbillede-URL, mannequin-ID og positur-ID, og polle derefter `/tryon/apparel/:id` hvert 3 sekund, indtil `status === 'completed'` — typisk inden for 1.5–4 minutter.

Opdateret · 2026-04-19

Din første 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);

Hvad kan man forvente

Typical completion

1–3min

2K / 4K credits

4 / 6

Styles

2

Batch-ready

yes

Sådan virker det

Virtuel Try-On API i Node.js

Fem trin, omkring fem minutter fra oprettelse til første billede.

  1. 01

    Trin 1

    Opret dig og generer en nøgle

    Opret en konto på ai.photta.app. Åbn Developers-sektionen i dashboardet, klik på Generate API key, og kopier live-nøglen. Den starter med `photta_live_` efterfulgt af 32 hex-karakterer.

  2. 02

    Trin 2

    Gem nøglen i env, ikke i kildekoden

    Tilføj `PHOTTA_API_KEY=...` til `.env` (eller din platforms secret store) og indlæs den via `process.env`. Commit aldrig nøglen; importer den aldrig i en fil markeret med `'use client'` — bundleren vil trække den med ud i browseren.

  3. 03

    Trin 3

    Skriv en lille fetch-helper

    En wrapper på 20 linjer omkring `fetch()` håndterer base-URL, Authorization-header, JSON-body og fejlnormalisering. Dette er den eneste abstraktion, du har brug for, indtil en officiel SDK frigives.

  4. 04

    Trin 4

    Indsend en try-on og polle

    POST til `/tryon/apparel` med `product_type`, `product_images`, `mannequin_id`, `pose_id`, `resolution` og `aspect_ratio`. API'et returnerer straks et generations-ID. Polle `/tryon/apparel/:id` hvert 3 sekund, indtil `status === 'completed'`.

  5. 05

    Trin 5

    Persistér resultatet

    Den færdige payload inkluderer `output_url` og `thumbnail_url`. Hent bytes én gang og gem dem i din egen object storage — URL'erne er stabile, men dit produkt bør ikke afhænge af Phottas CDN til rendering.

Kode, ende-til-ende

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;
}

Hvorfor denne struktur

Hvorfor en helper er bedre end et klient-bibliotek — lige nu

  • 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

Hvad det ikke gør

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

Spørgsmål fra andre udviklere

Questions other developers ask

Findes der en officiel Photta Node.js SDK?+

Ikke endnu. Photta-dokumentationen planlægger eksplicit SDK'er efter adoptions-tærskler: Python når ti API-brugere er ombord, Node.js ved tyve. Indtil da er den dokumenterede vej rå REST via cURL, Nodes native fetch eller Python requests-biblioteket. Helperen på 20 linjer på denne side svarer til en klient for de endpoints, du vil bruge mest.

Hvilke Node.js-versioner understøttes?+

Alt, der understøtter native `fetch` — hvilket betyder Node 18 og senere. På Node 16 skal du enten bruge en polyfill med `node-fetch` eller opgradere. Resten af koden er ren ECMAScript 2020 (async/await, template literals, dynamiske imports), så der er ingen andre runtime-krav.

Hvordan autentificerer jeg fra Node?+

Send `Authorization: Bearer photta_live_xxx` ved hver request. Nøglen starter med `photta_live_` i produktion og `photta_test_`, når sandbox-tilstand frigives. Læg den i en miljøvariabel og indlæs den via `process.env.PHOTTA_API_KEY`. API'et understøtter endnu ikke OAuth client credentials eller sessionsbaseret auth.

Hvordan håndterer jeg generations-vinduet på 1.5–4 minutter?+

Try-on-endpointet er fuldt asynkront. POST returnerer straks et generations-ID med `status: 'processing'`. Polle `GET /tryon/apparel/:id` hvert 3–5 sekund, indtil `status` skifter til `completed` eller `failed`. Sæt en øvre grænse for forsøg, så et fastlåst job ikke hænger din request for evigt — 120 forsøg á 3 sekunder dækker det dokumenterede vindue med margin.

Kan jeg kalde API'et inde i Next.js?+

Ja — fra en route handler (`app/**/route.ts`), en server action (`'use server'`) eller middleware. Behold API-nøglen på serveren; importer aldrig helperen fra en `'use client'` fil. For langvarige jobs, der overskrider Vercels function timeout, bør du udskyde polling til en kø (Inngest, Trigger.dev, BullMQ) og returnere generations-ID'et til browseren, så den kan polle en webhook eller dit eget status-endpoint.

Hvordan signalerer API'et fejl?+

Ikke-2xx responser indeholder en JSON-body med et `error`-objekt: `type`, `code`, `message` og et request-ID til support. Almindelige tilfælde: 400 invalid_request_error med `param`, der peger på det forkerte felt; 402 insufficient_credits med `required` og `available` tællere; 429 rate_limit_exceeded med `retry_after` i sekunder og en matchende Retry-After header. 5xx fejl er sikre at prøve igen med eksponentiel backoff.

Node.js · Virtuel Try-On API

Opret en konto og hent en API-nøgle

Sæt `PHOTTA_API_KEY` i env, skriv en lille `phottaFetch()` helper, der kalder `https://ai.photta.app/api/v1` med `Authorization: Bearer photta_live_xxx`, lav en POST til `/tryon/apparel` med en produktbillede-URL, mannequin-ID og positur-ID, og polle derefter `/tryon/apparel/:id` hvert 3 sekund, indtil `status === 'completed'` — typisk inden for 1.5–4 minutter.

Virtuel Try-On API til Node.js — Photta | Photta