Node.js · Virtual Try-On API

Virtual Try-On API in Node.js

Non esiste ancora un pacchetto @photta/node — e non ne hai bisogno. Node 18+ include fetch nativamente, e un helper di 20 righe ti permette di ottenere la tua prima immagine su modella in circa cinque minuti.

In una frase

Imposta PHOTTA_API_KEY nell'ambiente, scrivi un piccolo helper phottaFetch() che chiama https://ai.photta.app/api/v1 con Authorization: Bearer photta_live_xxx, invia una POST a /tryon/apparel con l'URL immagine, ID manichino e ID posa, poi polling di /tryon/apparel/:id ogni 3 secondi finché status === 'completed' — solitamente tra 1.5–4 minuti.

Aggiornato · 2026-04-19

La tua prima richiesta

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

Cosa aspettarsi

Typical completion

1.5–4min

2K / 4K credits

5 / 7

Jewelry types

4

Close-up mannequins

built-in

Come funziona

Virtual Try-On API in Node.js

Cinque step, circa cinque minuti dalla registrazione alla prima immagine.

  1. 01

    Step 1

    Registrati e genera una chiave

    Crea un account su ai.photta.app. Apri la sezione Developers della dashboard, clicca su Generate API key e copia la chiave live. Inizia con photta_live_ seguito da 32 caratteri esadecimali.

  2. 02

    Step 2

    Salva la chiave in env, non nel codice

    Aggiungi PHOTTA_API_KEY=... al file .env (o al secret store della tua piattaforma) e caricala tramite process.env. Non caricare mai la chiave nel codice; non importarla mai in file contrassegnati da 'use client' — il bundler la includerebbe nel browser.

  3. 03

    Step 3

    Scrivi un piccolo helper fetch

    Un wrapper di 20 righe attorno a fetch() gestisce URL di base, header Authorization, body JSON e normalizzazione degli errori. Questa è l'unica astrazione necessaria finché non verrà rilasciato un SDK ufficiale.

  4. 04

    Step 4

    Invia un try-on e polling

    POST su /tryon/apparel con product_type, product_images, mannequin_id, pose_id, resolution e aspect_ratio. L'API restituisce immediatamente un ID generazione. Polling di /tryon/apparel/:id ogni 3 secondi finché status === 'completed'.

  5. 05

    Step 5

    Salva il risultato

    Il payload completato include output_url e thumbnail_url. Scarica i byte una volta e salvali nel tuo storage — gli URL sono stabili ma il tuo prodotto non dovrebbe dipendere dalla CDN di Photta per il rendering.

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

Perché questa struttura

Perché un helper è meglio di una libreria client — per ora

  • 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

Cosa non fa

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

Domande frequenti degli sviluppatori

Questions other developers ask

Esiste un SDK Node.js ufficiale di Photta?+

Non ancora. La documentazione di Photta prevede il rilascio degli SDK al raggiungimento di determinate soglie di adozione: Python a dieci utenti API, Node.js a venti. Fino ad allora, il percorso documentato è REST tramite cURL, fetch nativo di Node o la libreria requests di Python. L'helper di 20 righe in questa pagina equivale a un client per gli endpoint più utilizzati.

Quali versioni di Node.js sono supportate?+

Qualsiasi versione che supporti fetch nativo — ovvero Node 18 e successivi. Su Node 16 è necessario usare un polyfill come node-fetch o aggiornare. Il resto del codice è ECMAScript 2020 standard (async/await, template literals, dynamic imports), quindi non ci sono altri requisiti di runtime.

Come effettuo l'autenticazione da Node?+

Invia Authorization: Bearer photta_live_xxx in ogni richiesta. La chiave inizia con photta_live_ in produzione, photta_test_ quando sarà disponibile la sandbox. Salvala in una variabile d'ambiente e caricala tramite process.env.PHOTTA_API_KEY. L'API non supporta ancora OAuth o autenticazione basata su sessioni.

Come gestisco la finestra di generazione di 1.5–4 minuti?+

L'endpoint try-on è completamente asincrono. La POST restituisce immediatamente un ID generazione con status: 'processing'. Effettua il polling di GET /tryon/apparel/:id ogni 3–5 secondi finché status diventa completed o failed. Imposta un limite massimo di tentativi per evitare job infiniti — 120 tentativi a 3 secondi coprono la finestra documentata con margine.

Posso chiamare l'API dentro Next.js?+

Sì — da un route handler (app/**/route.ts), una server action ('use server') o un middleware. Mantieni la API key sul server; non importare mai l'helper da un file 'use client'. Per job lunghi che superano il timeout di Vercel, delega il polling a una coda (Inngest, Trigger.dev, BullMQ) e restituisci l'ID generazione al browser perché interroghi un webhook o il tuo endpoint di stato.

Come vengono segnalati gli errori dall'API?+

Le risposte non-2xx includono un body JSON con un oggetto error: type, code, message e un ID richiesta per il supporto. Casi comuni: 400 invalid_request_error con param che indica il campo errato; 402 insufficient_credits con i conteggi required e available; 429 rate_limit_exceeded con retry_after in secondi. Gli errori 5xx possono essere ritentati con backoff esponenziale.

Node.js · Virtual Try-On API

Crea un account e ottieni una API key

Imposta PHOTTA_API_KEY nell'ambiente, scrivi un piccolo helper phottaFetch() che chiama https://ai.photta.app/api/v1 con Authorization: Bearer photta_live_xxx, invia una POST a /tryon/apparel con l'URL immagine, ID manichino e ID posa, poi polling di /tryon/apparel/:id ogni 3 secondi finché status === 'completed' — solitamente tra 1.5–4 minuti.

Virtual Try-On API per Node.js — Photta | Photta