Node.js · API d'essayage virtuel

API d'essayage virtuel en Node.js

Il n'y a pas encore de package @photta/node — et vous n'en avez pas besoin. Node 18+ intègre `fetch` nativement, et un helper de 20 lignes vous permet d'obtenir votre première image sur mannequin en cinq minutes.

En une phrase

Définissez `PHOTTA_API_KEY` dans l'environnement, écrivez un petit helper `phottaFetch()` qui appelle `https://ai.photta.app/api/v1` avec `Authorization: Bearer photta_live_xxx`, effectuez un POST sur `/tryon/apparel` avec l'URL de l'image, l'ID du mannequin et de la pose, puis interrogez `/tryon/apparel/:id` toutes les 3 secondes jusqu'à `status === 'completed'` — généralement sous 1.5–4 minutes.

Mis à jour · 2026-04-19

Votre première requête

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

À quoi s'attendre

Typical completion

1.5–4min

2K / 4K credits

5 / 7

Jewelry types

4

Close-up mannequins

built-in

Comment ça marche

API d'essayage virtuel en Node.js

Cinq étapes, environ cinq minutes de l'inscription à la première image.

  1. 01

    Étape 1

    S'inscrire et générer une clé

    Créez un compte sur ai.photta.app. Ouvrez la section Développeurs, cliquez sur Générer une clé API, et récupérez la clé de production. Elle commence par `photta_live_` suivi de 32 caractères hexadécimaux.

  2. 02

    Étape 2

    Stocker la clé dans env, pas dans le code

    Ajoutez `PHOTTA_API_KEY=...` à votre fichier `.env` (ou votre gestionnaire de secrets) et chargez-la via `process.env`. Ne committez jamais la clé ; ne l'importez jamais dans un fichier marqué `'use client'` — le bundler l'exposerait dans le navigateur.

  3. 03

    Étape 3

    Écrire un helper fetch minimal

    Un wrapper de 20 lignes autour de `fetch()` gère l'URL de base, l'en-tête Authorization, le corps JSON et la normalisation des erreurs. C'est la seule abstraction nécessaire en l'absence de SDK officiel.

  4. 04

    Étape 4

    Soumettre un essayage et interroger

    POST sur `/tryon/apparel` avec `product_type`, `product_images`, `mannequin_id`, `pose_id`, `resolution` et `aspect_ratio`. L'API renvoie immédiatement un ID de génération. Interrogez `/tryon/apparel/:id` toutes les 3 secondes jusqu'à `status === 'completed'`.

  5. 05

    Étape 5

    Persister le résultat

    Le payload complété inclut `output_url` et `thumbnail_url`. Téléchargez les octets une fois et stockez-les dans votre propre stockage objet — les URLs sont stables mais votre produit ne devrait pas dépendre du CDN de Photta pour l'affichage.

Code, de bout en bout

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

Pourquoi cette structure

Pourquoi un helper vaut mieux qu'une bibliothèque client — pour l'instant

  • 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

Ce qu'il ne fait pas

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

Questions fréquentes des développeurs

Questions other developers ask

Existe-t-il un SDK Node.js Photta officiel ?+

Pas encore. La documentation Photta prévoit des SDK après certains paliers d'adoption : Python à dix utilisateurs API actifs, Node.js à vingt. D'ici là, la méthode recommandée est le REST brut via fetch natif ou requests pour Python. Le helper de 20 lignes sur cette page équivaut à un client pour les endpoints les plus courants.

Quelles versions de Node.js sont supportées ?+

Toute version supportant `fetch` nativement — soit Node 18 et plus. Sur Node 16, utilisez un polyfill comme `node-fetch` ou mettez à jour. Le reste du code est de l'ECMAScript 2020 standard (async/await, templates de chaînes, imports dynamiques), donc pas d'autres prérequis.

Comment s'authentifier depuis Node ?+

Envoyez `Authorization: Bearer photta_live_xxx` à chaque requête. La clé commence par `photta_live_` en production, `photta_test_` quand le mode sandbox sera disponible. Placez-la dans une variable d'environnement et chargez-la via `process.env.PHOTTA_API_KEY`. L'API ne supporte pas encore OAuth ou l'auth par session.

Comment gérer la fenêtre de génération de 1.5–4 minutes ?+

L'endpoint d'essayage est totalement asynchrone. Le POST renvoie un ID de génération immédiatement avec le statut `processing`. Interrogez `GET /tryon/apparel/:id` toutes les 3–5 secondes jusqu'à ce que le statut passe à `completed` ou `failed`. Fixez une limite de tentatives pour éviter les requêtes infinies — 120 essais à 3 secondes couvrent largement la durée documentée.

Puis-je appeler l'API dans Next.js ?+

Oui — depuis un route handler (`app/**/route.ts`), une server action (`'use server'`), ou un middleware. Gardez la clé API sur le serveur ; ne l'importez jamais dans un fichier `'use client'`. Pour les tâches longues dépassant le timeout de Vercel, déléguez le polling à une file d'attente (Inngest, Trigger.dev, BullMQ) et renvoyez l'ID au navigateur pour qu'il interroge votre propre endpoint de statut.

Comment l'API signale-t-elle les erreurs ?+

Les réponses hors 2xx contiennent un corps JSON avec un objet `error` : `type`, `code`, `message` et un ID de requête pour le support. Cas courants : 400 invalid_request_error avec `param` pointant sur le champ erroné ; 402 insufficient_credits avec les comptes `required` et `available` ; 429 rate_limit_exceeded avec `retry_after` en secondes. Les erreurs 5xx peuvent être retentées avec un backoff exponentiel.

Node.js · API d'essayage virtuel

Créer un compte et obtenir une clé API

Définissez `PHOTTA_API_KEY` dans l'environnement, écrivez un petit helper `phottaFetch()` qui appelle `https://ai.photta.app/api/v1` avec `Authorization: Bearer photta_live_xxx`, effectuez un POST sur `/tryon/apparel` avec l'URL de l'image, l'ID du mannequin et de la pose, puis interrogez `/tryon/apparel/:id` toutes les 3 secondes jusqu'à `status === 'completed'` — généralement sous 1.5–4 minutes.

API d'essayage virtuel pour Node.js — Photta | Photta