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
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–3min
2K / 4K credits
4 / 6
Styles
2
Batch-ready
yes
Comment ça marche
API d'essayage virtuel en Node.js
Cinq étapes, environ cinq minutes de l'inscription à la première image.
- 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.
- 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.
- 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.
- 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'`.
- 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.
# 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// 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;
}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);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.