Node.js · API de try-on virtuel
API de try-on virtuel en Node.js
En une phrase
Définissez PHOTTA_API_KEY dans l'environnement, écrivez un léger helper fetch pour https://api.photta.app/api/v1 avec une clé Bearer, envoyez un POST à /api/v1/tryon/apparel, puis interrogez /api/v1/tryon/apparel/{id} toutes les 3 secondes jusqu'à ce que le statut soit completed.
- Délai typique: 1.5–4 min
- Crédits: 5 crédits en 2K · 6 crédits en 4K
- Traitement: asynchrone, polling
- Limites: 600 requêtes/min
- Authentification: Clé Bearer
Chaque chiffre sur cette page provient de la documentation de l'API Photta · vérifié
RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')
# $ID is data.id from the POST response. Poll every 3 seconds until status is "completed" or "failed".
for i in $(seq 1 120); do
RESULT=$(curl -s "https://api.photta.app/api/v1/tryon/apparel/$ID" -H "Authorization: Bearer $PHOTTA_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.data.status')
[ "$STATUS" = "completed" ] && break
[ "$STATUS" = "failed" ] && echo "generation failed" && exit 1
sleep 3
done
echo "$RESULT" | jq -r '.data.output_url'const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}),
});
const { data } = await res.json(); // data.id, data.status
async function waitFor(id) {
for (let attempt = 0; attempt < 120; attempt++) {
const res = await fetch(`https://api.photta.app/api/v1/tryon/apparel/${id}`, { headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` } });
const { data } = await res.json();
if (data.status === "completed") return data.output_url;
if (data.status === "failed") throw new Error(data.error_message ?? "generation failed");
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error("timed out after 6 minutes");
}import os, requests
res = requests.post(
"https://api.photta.app/api/v1/tryon/apparel",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": True,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
},
)
data = res.json()["data"] # data["id"], data["status"]
import time
def wait_for(job_id):
for _ in range(120):
res = requests.get(f"https://api.photta.app/api/v1/tryon/apparel/{job_id}", headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"})
data = res.json()["data"]
if data["status"] == "completed":
return data["output_url"]
if data["status"] == "failed":
raise RuntimeError(data.get("error_message", "generation failed"))
time.sleep(3)
raise TimeoutError("timed out after 6 minutes")En un coup d'œil
En un coup d'œil
- Endpoint
- POST /api/v1/tryon/apparel
- Authentification
- Clé API Bearer
- Traitement
- Asynchrone — interrogez l'endpoint de statut par polling
- Délai typique
- 1.5–4 min
- Crédits
- 5 crédits en 2K · 6 crédits en 4K
- Rapports d'aspect
- 3:4 · 1:1 · 4:3 · 9:16 · 16:9
- Limites d'entrée
- Jusqu'à 10 Mo par image ; JPEG, PNG, WebP
- Idempotent
- Non
Comment ça fonctionne
Cinq étapes, environ cinq minutes de l'inscription à la première image.
Étape 1
S'inscrire et générer une clé
Créez un compte sur ai.photta.app. Ouvrez la section Développeurs du dashboard, cliquez sur Générer une clé d'API et copiez la clé live. Elle commence par `photta_live_` suivi de 32 caractères hexadécimaux.
Étape 2
Stocker la clé dans l'environnement, pas dans le code source
Ajoutez `PHOTTA_API_KEY=...` dans `.env` (ou dans le gestionnaire de secrets de votre plateforme) et chargez-la via `process.env`. Ne committez jamais la clé ; ne l'importez jamais dans un fichier annoté avec `'use client'` — le bundler l'exposerait côté navigateur.
node --version # 18 or later ships fetch echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .envÉ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 dont vous avez besoin en attendant la sortie d'un SDK officiel.
// photta.js — one helper for every endpoint const BASE = "https://api.photta.app/api/v1"; export async function photta(path, init = {}) { const res = await fetch(BASE + path, { ...init, headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json", ...(init.headers ?? {}) } }); const body = await res.json(); if (!res.ok) throw Object.assign(new Error(body.error?.message ?? res.statusText), { status: res.status, retryAfter: res.headers.get("Retry-After"), body }); return body; }Étape 4
Soumettre un try-on et faire du polling
Envoyez un POST vers `/api/v1/tryon/apparel` avec le corps d'exemple documenté — le code ci-dessous inclut chaque champ. L'API renvoie immédiatement un identifiant de génération. Interrogez `/api/v1/tryon/apparel/{id}` par polling toutes les 3 secondes jusqu'à ce que `status === 'completed'`.
const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", { method: "POST", headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "product_type": "top", "product_images": [ "https://cdn.yourstore.com/products/shirt-front.jpg" ], "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg", "product_category": "t_shirt", "mannequin_id": "mnk_f3a9b1", "pose_id": "pose_c2d4e5", "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg", "lock_background": true, "resolution": "2K", "aspect_ratio": "3:4", "body_size": "M", "expression": "neutral", "user_instruction": "Keep the collar pattern crisp and centered." }), }); const { data } = await res.json(); // data.id, data.status async function waitFor(id) { for (let attempt = 0; attempt < 120; attempt++) { const res = await fetch(`https://api.photta.app/api/v1/tryon/apparel/${id}`, { headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` } }); const { data } = await res.json(); if (data.status === "completed") return data.output_url; if (data.status === "failed") throw new Error(data.error_message ?? "generation failed"); await new Promise((r) => setTimeout(r, 3000)); } throw new Error("timed out after 6 minutes"); }Étape 5
Persister le résultat
Le payload final inclut `output_url` et `thumbnail_url`. Récupérez les octets une seule fois via fetch et stockez-les dans votre propre stockage objet — les URL sont stables mais votre produit ne devrait pas dépendre du CDN de Photta pour le rendu.
Erreurs
- 400
invalid_request_error - The request is malformed or contains invalid parameters.
- 401
authentication_error - The API key is missing, invalid, or expired.
- 402
insufficient_credits_error - Your account does not have enough credits.
- 404
not_found_error - The requested resource does not exist.
- 409
conflict_error - The request conflicts with current state — e.g. your concurrent-batch cap is reached.
- 429
rate_limit_error - Too many requests. Slow down and retry.Retry-After: 30
- 500
api_error - An internal server error occurred. Retry later.
try {
await photta("/tryon/apparel", { method: "POST", body: JSON.stringify({
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}) });
} catch (err) {
if (err.status === 402) console.error("insufficient_credits_error: top up before retrying");
else if (err.status === 429) await new Promise((r) => setTimeout(r, Number(err.retryAfter ?? 30) * 1000));
else throw err;
}Limites
- 600 requêtes par minute par clé API (Fenêtre fixe ; la limite est identique sur tous les forfaits)
- Une 429 renvoie Retry-After: 30 secondes
- Jusqu'à 10 Mo par image
- Formats: JPEG, PNG, WebP
- Lots simultanés par forfait: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
- Polling uniquement — l'API n'envoie aucun webhook.
Pourquoi un helper surpasse une bibliothèque cliente — pour l'instant
- Node 18+ intègre fetch en natif — aucune dépendance d'exécution
- Le même helper fonctionne dans les route handlers Next.js, les server actions et n'importe quel worker
- Conservez la clé d'API dans l'environnement ; n'importez jamais le helper depuis un module 'use client' sous peine de fuite via le bundler
- Fonctionne avec n'importe quelle file d'attente ou cron : BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues
Ce qu'il ne fait pas
- Aucun package officiel @photta/node pour l'instant — REST est l'unique voie aujourd'hui
- Le polling est le seul signal d'achèvement ; l'API n'envoie aucun webhook
- Clé Bearer uniquement ; il n'y a pas de flux client-credentials OAuth
Questions fréquentes des développeurs
Existe-t-il un SDK officiel Photta pour Node.js ?
Pas encore. La méthode documentée repose sur du pur REST via le fetch natif de Node — le helper sur cette page représente l'intégralité de la surface d'intégration, et fonctionne de manière identique pour chaque fonctionnalité.
Quelles versions de Node.js sont prises en charge ?
Toutes celles supportant `fetch` nativement — c'est-à-dire Node 18 et versions ultérieures. Sur Node 16, utilisez un polyfill avec `node-fetch` ou mettez à niveau votre version. Le reste du code est du pur ECMAScript 2020 (async/await, template literals, imports dynamiques), sans autre exigence d'exécution.
Comment s'authentifier depuis Node ?
Envoyez `Authorization: Bearer photta_live_xxx` à chaque requête. Placez la clé dans une variable d'environnement et chargez-la via `process.env` ; ne l'importez jamais depuis un fichier exécuté dans le navigateur.
Comment gérer la fenêtre de génération ?
L'endpoint de génération est entièrement asynchrone. Le POST renvoie immédiatement un identifiant de génération avec `status: 'processing'`. Interrogez `GET /api/v1/tryon/apparel/{id}` par polling toutes les 3 à 5 secondes jusqu'à ce que `status` passe à `completed` ou `failed`, et limitez le nombre de tentatives afin qu'un job bloqué ne suspende pas indéfiniment une requête.
Puis-je appeler l'API au sein de Next.js ?
Oui — depuis un route handler (`app/**/route.ts`), une server action (`'use server'`) ou un middleware. Conservez la clé d'API côté serveur ; n'importez jamais le helper depuis un fichier `'use client'`. Pour les jobs longs qui dépassent le timeout des fonctions Vercel, déléguez le polling à une file d'attente (Inngest, Trigger.dev, BullMQ) et renvoyez l'identifiant de génération au navigateur pour qu'il interroge votre propre endpoint d'état.
Comment l'API signale-t-elle les erreurs ?
Les réponses autres que 2xx contiennent un corps JSON avec un objet `error` : `type`, `code`, `message` et un identifiant de requête pour le support. Cas fréquents : 400 invalid_request_error avec `param` pointant vers le champ invalide ; 402 insufficient_credits avec les soldes `required` et `available` ; 429 rate_limit_exceeded avec `retry_after` en secondes et un en-tête Retry-After correspondant. Les erreurs 5xx peuvent être réessayées sans risque avec un backoff exponentiel.
Pages associées
Python
API de try-on virtuel en Python
Appelez aPI de try-on virtuel de Photta en Python avec la bibliothèque requests. Un wrapper de trente lignes, compatible asynchrone via httpx, fonctionnant dans Django, FastAPI et Celery.
LirecURL
API de try-on virtuel avec cURL
Appelez aPI de try-on virtuel de Photta directement depuis le shell avec cURL. Soumettez, effectuez le polling, téléchargez — chaque extrait s'associe à jq pour vos pipelines scriptés.
LireFonctionnalités
API de try-on virtuel pour les vêtements
API REST qui positionne des vêtements sur des mannequins générés par IA. Traitement asynchrone, génération en 1.5–4 minutes, 5 crédits en 2K, 6 en 4K. Exemples en cURL, Node.js et Python.
LireDévelopper
Intégrez une fonctionnalité de try-on virtuel à votre application
Guide d'implémentation de bout en bout pour intégrer le try-on virtuel avec l'API Photta : upload, soumission, polling via un worker, rendu du résultat. Architecture TypeScript + server-only.
LireDévelopper
Ajouter le virtual try-on à une application iOS ou Android
Comment ajouter le virtual try-on IA à une application native iOS ou Android avec l'API Photta : ne livrez jamais la clé sur l'appareil, passez par un proxy sur votre backend, répliquez l'état des jobs.
LireDémarrage rapide
Première image Photta en moins de cinq minutes.
Inscrivez-vous, générez une clé d'API, lancez votre premier appel cURL, effectuez le polling jusqu'à la complétion, persistez le résultat. Cinq étapes documentées de bout en bout.
LireRéférence
Tarification de l'API Photta
Le coût en credits de chaque endpoint de l’API Photta en 2K et 4K, le fonctionnement de la facturation et des remboursements, et les endpoints gratuits. Aucun prix monétaire par image.
Lire
Chaque chiffre sur cette page provient de la documentation de l'API Photta · vérifié
Testez l'API en cinq minutes
Générez une clé d'API Photta, collez le snippet cURL ci-dessus, et vous obtiendrez votre première photo portée sur modèle avant même que le café ait fini de couler.
- 1.5–4 min
- 5 crédits en 2K · 6 crédits en 4K
- asynchrone, polling
- 600 requêtes/min
- Clé Bearer