Node.js · Virtual Try-On API

Virtual Try-On API i Node.js

Det finns inget @photta/node-paket ännu — och du behöver inget. Node 18+ har inbyggd fetch, och en hjälpare på 20 rader tar dig till din första bild på modell på cirka fem minuter.

I en mening

Spara PHOTTA_API_KEY i env, skriv en liten phottaFetch()-hjälpare som anropar https://ai.photta.app/api/v1 med Authorization: Bearer photta_live_xxx, POST:a till /tryon/apparel med en produkt-URL, mannequin_id och pose_id, polla sedan /tryon/apparel/:id var 3:e sekund tills status === 'completed' — vanligtvis inom 1.5–4 minuter.

Uppdaterad · 2026-04-19

Din första förfrågan

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

Vad du kan förvänta dig

Typical completion

1–3min

2K / 4K credits

4 / 6

Styles

2

Batch-ready

yes

Så fungerar det

Virtual Try-On API i Node.js

Fem steg, cirka fem minuter från registrering till första bild.

  1. 01

    Steg 1

    Registrera dig och generera en nyckel

    Skapa ett konto på ai.photta.app. Öppna sektionen för utvecklare på instrumentpanelen, klicka på Generate API key och hämta live-nyckeln. Den börjar med photta_live_ följt av 32 hexadecimala tecken.

  2. 02

    Steg 2

    Spara nyckeln i env, inte i källkoden

    Lägg till PHOTTA_API_KEY=... i .env (eller din plattforms hemlighetshantering) och läs in den via process.env. Checka aldrig in nyckeln; importera den aldrig i en fil markerad med 'use client' — byggverktyget kommer då att inkludera den i webbläsaren.

  3. 03

    Steg 3

    Skriv en liten fetch-hjälpare

    En wrapper på 20 rader runt fetch() hanterar bas-URL, Authorization-header, JSON-body och felhantering. Detta är den enda abstraktion du behöver tills ett officiellt SDK lanseras.

  4. 04

    Steg 4

    Skicka en provning och polla

    Skicka POST till /tryon/apparel med product_type, product_images, mannequin_id, pose_id, resolution och aspect_ratio. API:et returnerar ett generations-ID omedelbart. Polla /tryon/apparel/:id var 3:e sekund tills status === 'completed'.

  5. 05

    Steg 5

    Spara resultatet

    Svaret vid slutfört jobb inkluderar output_url och thumbnail_url. Hämta rådatan en gång och spara den i din egen lagring — URL:erna är stabila, men din produkt bör inte vara beroende av Phottas CDN för rendering.

Kod, hela vägen

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

Varför denna struktur

Varför en hjälpare slår ett klientbibliotek — just 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

Vad den inte 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

Frågor från andra utvecklare

Questions other developers ask

Finns det ett officiellt Photta Node.js SDK?+

Inte ännu. Phottas dokumentation planerar SDK:er efter specifika trösklar: Python när 10 API-användare har lanserat, Node.js vid 20. Fram tills dess är den rekommenderade vägen ren REST via cURL, Nodes inbyggda fetch eller Pythons requests-bibliotek. Hjälparen på 20 rader på denna sida motsvarar en klient för de slutpunkter du kommer använda mest.

Vilka Node.js-versioner stöds?+

Alla som stöder inbyggd fetch — vilket innebär Node 18 och senare. På Node 16 får du antingen använda en polyfill som node-fetch eller uppgradera. Resten av koden är vanlig ECMAScript 2020 (async/await, template literals, dynamiska importer) så inga andra krav finns på miljön.

Hur autentiserar jag från Node?+

Skicka Authorization: Bearer photta_live_xxx vid varje anrop. Nyckeln börjar med photta_live_ i produktion, photta_test_ när sandbox-läget lanseras. Spara den i en miljövariabel och läs in den via process.env.PHOTTA_API_KEY. API:et stöder ännu inte OAuth client credentials eller sessionsbaserad autentisering.

Hur hanterar jag genereringsfönstret på 1.5–4 minuter?+

Slutpunkten för provning är helt asynkron. POST returnerar ett generations-ID omedelbart med status: 'processing'. Polla GET /tryon/apparel/:id var 3–5 sekund tills status ändras till completed eller failed. Sätt en övre gräns för antalet försök så att ett fastnat jobb inte låser din förfrågan för evigt — 120 försök med 3 sekunders mellanrum täcker det dokumenterade fönstret med god marginal.

Kan jag anropa API:et inuti Next.js?+

Ja — från en route handler (app/**/route.ts), en server action ('use server') eller middleware. Behåll API-nyckeln på servern; importera aldrig hjälparen från en 'use client'-fil. För långkörande jobb som överskrider Vercels timeout för funktioner bör du flytta polling till en kö (Inngest, Trigger.dev, BullMQ) och returnera generations-ID:t till webbläsaren så att den kan polla en webhook eller din egen status-slutpunkt.

Hur signalerar API:et fel?+

Svar som inte är 2xx innehåller en JSON-body med ett error-objekt: type, code, message och ett request-ID för support. Vanliga fall: 400 invalid_request_error där param pekar på det felaktiga fältet; 402 insufficient_credits med antal för required och available; 429 rate_limit_exceeded med retry_after i sekunder och en matchande Retry-After-header. 5xx-fel är säkra att försöka igen med exponentiell backoff.

Node.js · Virtual Try-On API

Skapa ett konto och hämta en API-nyckel

Spara PHOTTA_API_KEY i env, skriv en liten phottaFetch()-hjälpare som anropar https://ai.photta.app/api/v1 med Authorization: Bearer photta_live_xxx, POST:a till /tryon/apparel med en produkt-URL, mannequin_id och pose_id, polla sedan /tryon/apparel/:id var 3:e sekund tills status === 'completed' — vanligtvis inom 1.5–4 minuter.

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