Node.js · Virtual Try-On API
Virtual Try-On API in Node.js
Er is nog geen @photta/node package — en je hebt er ook geen nodig. Node 18+ bevat native `fetch`, en een helper van 20 regels brengt je in ongeveer vijf minuten naar je eerste afbeelding op een model.
In één zin
Stel `PHOTTA_API_KEY` in in env, schrijf een kleine `phottaFetch()` helper die `https://ai.photta.app/api/v1` aanroept met `Authorization: Bearer photta_live_xxx`, doe een POST naar `/tryon/apparel` met een product image-URL, mannequin_id en pose_id, poll vervolgens `/tryon/apparel/:id` elke 3 seconden totdat `status === 'completed'` — meestal binnen 1.5–4 minuten.
Bijgewerkt · 2026-04-19
Je eerste verzoek
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);Wat je kunt verwachten
Typical completion
1.5–4min
2K / 4K credits
5 / 7
Aspect ratios
5
Product types
6
Hoe het werkt
Virtual Try-On API in Node.js
Vijf stappen, ongeveer vijf minuten van aanmelding tot eerste afbeelding.
- 01
Stap 1
Meld je aan en genereer een sleutel
Maak een account aan op ai.photta.app. Open de Developers-sectie van het dashboard, klik op Generate API key en kopieer de live sleutel. Deze begint met `photta_live_` gevolgd door 32 hex-tekens.
- 02
Stap 2
Bewaar de sleutel in env, niet in code
Voeg `PHOTTA_API_KEY=...` toe aan `.env` (of de secret store van je platform) en laad deze via `process.env`. Voeg de sleutel nooit toe aan je code; importeer hem nooit in een bestand gemarkeerd als `'use client'` — de bundler zal hem dan naar de browser trekken.
- 03
Stap 3
Schrijf een kleine fetch-helper
Eén wrapper van 20 regels rond `fetch()` handelt de basis-URL, Authorization header, JSON-body en fout-normalisatie af. Dit is de enige abstractie die je nodig hebt totdat er een officiële SDK verschijnt.
- 04
Stap 4
Dien een try-on in en poll
POST naar `/tryon/apparel` met `product_type`, `product_images`, `mannequin_id`, `pose_id`, `resolution` en `aspect_ratio`. De API retourneert direct een generatie-ID. Poll `/tryon/apparel/:id` elke 3 seconden totdat `status === 'completed'`.
- 05
Stap 5
Sla het resultaat op
De voltooid-payload bevat `output_url` en `thumbnail_url`. Haal de bytes eenmalig op en sla ze op in je eigen object storage — de URL's zijn stabiel, maar je product moet voor weergave niet afhankelijk zijn van Photta's CDN.
Code, van begin tot eind
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;
}Waarom deze vorm
Waarom een helper beter is dan een client library — voor 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
Wat het niet doet
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
Vragen die andere developers stellen
Questions other developers ask
Is er een officiële Photta Node.js SDK?+
Nog niet. De Photta-documentatie plant SDK's op basis van adoptiedrempels: Python zodra tien API-gebruikers aan boord zijn, Node.js bij twintig. Tot die tijd is het gedocumenteerde pad raw REST via cURL, Node's native fetch of de Python requests-bibliotheek. De helper van 20 regels op deze pagina staat gelijk aan een client voor de endpoints die je het meest zult gebruiken.
Welke Node.js versies worden ondersteund?+
Alles wat native `fetch` ondersteunt — dus Node 18 en later. Op Node 16 gebruik je een polyfill zoals `node-fetch` of voer je een upgrade uit. De rest van de code is gewone ECMAScript 2020 (async/await, template literals, dynamic imports), dus er zijn geen andere runtime-vereisten.
Hoe authenticeer ik vanuit Node?+
Stuur `Authorization: Bearer photta_live_xxx` mee bij elk verzoek. De sleutel begint met `photta_live_` in productie, `photta_test_` wanneer de sandbox-modus verschijnt. Zet deze in een omgevingsvariabele en laad hem via `process.env.PHOTTA_API_KEY`. De API ondersteunt nog geen OAuth client credentials of sessie-gebaseerde auth.
Hoe ga ik om met het generatievenster van 1.5–4 minuten?+
Het try-on endpoint is volledig asynchroon. De POST retourneert direct een generatie-ID met `status: 'processing'`. Poll `GET /tryon/apparel/:id` elke 3–5 seconden totdat `status` verspringt naar `completed` of `failed`. Stel een maximum aantal pogingen in zodat een vastgelopen taak je verzoek niet eeuwig blokkeert — 120 pogingen met een interval van 3 seconden dekt het gedocumenteerde venster met marge.
Kan ik de API aanroepen binnen Next.js?+
Ja — vanuit een route handler (`app/**/route.ts`), een server action (`'use server'`) of middleware. Houd de API-sleutel op de server; importeer de helper nooit vanuit een `'use client'` bestand. Voor langlopende taken die de timeout van Vercel-functies overschrijden, verplaats je het pollen naar een wachtrij (Inngest, Trigger.dev, BullMQ) en retourneer je het generatie-ID naar de browser zodat deze een webhook of je eigen status-endpoint kan pollen.
Hoe signaleert de API fouten?+
Niet-2xx responses bevatten een JSON-body met een `error`-object: `type`, `code`, `message` en een verzoek-ID voor ondersteuning. Veelvoorkomende gevallen: 400 invalid_request_error waarbij `param` wijst naar het foute veld; 402 insufficient_credits met `required` en `available` aantallen; 429 rate_limit_exceeded met `retry_after` in seconden en een bijbehorende Retry-After header. 5xx-fouten kunnen veilig opnieuw worden geprobeerd met exponentiële back-off.
Node.js · Virtual Try-On API
Maak een account aan en ontvang een API-sleutel
Stel `PHOTTA_API_KEY` in in env, schrijf een kleine `phottaFetch()` helper die `https://ai.photta.app/api/v1` aanroept met `Authorization: Bearer photta_live_xxx`, doe een POST naar `/tryon/apparel` met een product image-URL, mannequin_id en pose_id, poll vervolgens `/tryon/apparel/:id` elke 3 seconden totdat `status === 'completed'` — meestal binnen 1.5–4 minuten.