Node.js · API för virtuell try-on
API för virtuell try-on i Node.js
I en mening
Sätt PHOTTA_API_KEY i env, skriv en liten fetch-hjälpreda för https://api.photta.app/api/v1 med en Bearer-nyckel, POST:a till /api/v1/tryon/apparel, polla sedan /api/v1/tryon/apparel/{id} var 3:e sekund tills status är completed.
- Typisk tid: 1.5–4 min
- Credits: 5 credits vid 2K · 6 credits vid 4K
- Bearbetning: asynkron, polling
- Gränser: 600 requests/min
- Autentisering: Bearer-nyckel
Varje siffra på den här sidan kommer från Photter API-dokumentationen · kontrollerad
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")I korthet
I korthet
- Endpoint
- POST /api/v1/tryon/apparel
- Autentisering
- Bearer API-nyckel
- Bearbetning
- Asynkron — polla status-endpointen
- Typisk tid
- 1.5–4 min
- Credits
- 5 credits vid 2K · 6 credits vid 4K
- Bildförhållanden
- 3:4 · 1:1 · 4:3 · 9:16 · 16:9
- Indatagränser
- Upp till 10 MB per bild; JPEG, PNG, WebP
- Idempotent
- Nej
Hur det fungerar
Fem steg, cirka fem minuter från registrering till första bild.
Steg 1
Registrera dig och generera en nyckel
Skapa ett konto på ai.photta.app. Öppna sektionen Developers i dashboarden, klicka på Generate API key och ta live-nyckeln. Den börjar med `photta_live_` följt av 32 hex-tecken.
Steg 2
Lagra nyckeln i env, inte i källkoden
Lägg till `PHOTTA_API_KEY=...` i `.env` (eller din plattforms hemlighetslager) och läs in den via `process.env`. Checka aldrig in nyckeln; importera den aldrig till en fil markerad med `'use client'` — bundlaren drar då in den i webbläsaren.
node --version # 18 or later ships fetch echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .envSteg 3
Skriv en enkel fetch-helper
En wrapper på 20 rader runt `fetch()` hanterar bas-URL, Authorization-header, JSON-body och felnormalisering. Detta är den enda abstraktion du behöver tills ett officiellt SDK släpps.
// 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; }Steg 4
Skicka en try-on och polla
Gör en POST till `/api/v1/tryon/apparel` med den dokumenterade exempel-bodyn — koden nedan innehåller alla fält. API:et returnerar ett generation-ID direkt. Polla `/api/v1/tryon/apparel/{id}` var 3:e sekund tills `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"); }Steg 5
Spara resultatet persistent
Den slutförda payloaden innehåller `output_url` och `thumbnail_url`. Hämta byten en gång och spara dem i din egen objektlagring — URL:erna är stabila, men din produkt bör inte vara beroende av Phottas CDN för rendering.
Fel
- 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;
}Gränser
- 600 anrop per minut per API-nyckel (Fast fönster; gränsen är densamma på alla planer)
- En 429 innehåller Retry-After: 30 sekunder
- Upp till 10 MB per bild
- Format: JPEG, PNG, WebP
- Samtidiga batcher per plan: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
- Endast polling — API:et skickar inga webhooks.
Varför en helper slår ett klientbibliotek — tills vidare
- Node 18+ har inbyggd fetch — inga runtime-beroenden
- Samma helper fungerar i Next.js route handlers, server actions och alla workers
- Håll API-nyckeln i env; importera aldrig helpern från en 'use client'-modul, annars läcker bundlern den
- Fungerar med alla köer och cron-lösningar: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues
Vad det inte gör
- Inget officiellt @photta/node-paket än — REST är den enda vägen idag
- Polling är den enda signalen på slutförande; API:et skickar inga webhooks
- Endast Bearer-nyckel; det finns inget OAuth client-credentials-flöde
Vanliga utvecklarfrågor
Finns det ett officiellt Photta Node.js-SDK?
Inte än. Den dokumenterade vägen är rå REST via Nodes inbyggda fetch — helpern på den här sidan utgör hela integrationsytan, och den fungerar likadant för varje capability.
Vilka Node.js-versioner stöds?
Alla som stöder inbyggd `fetch` — vilket innebär Node 18 och senare. På Node 16 får du antingen köra polyfill med `node-fetch` eller uppgradera. Resten av koden är ren ECMAScript 2020 (async/await, template literals, dynamiska importer) så det finns inga andra runtime-krav.
Hur autentiserar jag från Node?
Skicka `Authorization: Bearer photta_live_xxx` i varje anrop. Lägg nyckeln i en miljövariabel och läs in den via `process.env`; importera den aldrig från en fil som körs i webbläsaren.
Hur hanterar jag generationsfönstret?
Generations-endpointen är helt asynkron. POST returnerar omedelbart ett generation-ID med `status: 'processing'`. Polla `GET /api/v1/tryon/apparel/{id}` var 3–5:e sekund tills `status` slår om till `completed` eller `failed`, och sätt ett tak för antalet försök så att ett fastnat jobb inte låser en förfrågan.
Kan jag anropa API:et inuti Next.js?
Ja — från en route handler (`app/**/route.ts`), en server action (`'use server'`) eller middleware. Håll API-nyckeln på servern; importera aldrig helpern från en `'use client'`-fil. För långkörande jobb som överskrider Vercels funktionstimeout, lägg ut pollingen på en kö (Inngest, Trigger.dev, BullMQ) och returnera generation-ID:t till webbläsaren så att den kan polla din egen status-endpoint.
Hur signalerar API:et fel?
Svar som inte är 2xx innehåller en JSON-body med ett `error`-objekt: `type`, `code`, `message` och ett request-ID för support. Vanliga fall: 400 invalid_request_error med `param` som pekar ut det felaktiga fältet; 402 insufficient_credits med antal för `required` och `available`; 429 rate_limit_exceeded med `retry_after` i sekunder och en matchande Retry-After-header. 5xx-fel är säkra att försöka igen med exponentiell backoff.
Relaterade sidor
Python
API för virtuell try-on i Python
Anropa Phottas aPI för virtuell try-on i Python med requests-biblioteket. Wrapper på trettio rader, async-vänlig via httpx, fungerar i Django, FastAPI och Celery.
LäscURL
API för virtuell try-on med cURL
Anropa Phottas aPI för virtuell try-on direkt från skalet med cURL. Skicka, polla, ladda ner — alla kodavsnitt fungerar tillsammans med jq för skriptade pipelines.
LäsFunktioner
API för virtuell try-on för apparel
REST API som placerar kläder på AI-mannekänger. Asynkron, 1,5–4 minuters generering, 5 credits vid 2K, 6 vid 4K. Exempel för cURL, Node.js och Python.
LäsBygg
Bygg en virtuell try-on-funktion för din app
Ett heltäckande recept för att driftsätta en virtuell try-on-funktion med Photta API: ladda upp, skicka in, gör polling från en worker, rendera resultatet. TypeScript + server-only-mönster.
LäsBygg
Lägg till virtuell try-on i en iOS- eller Android-app
Så här lägger du till virtuell try-on med AI i en nativ iOS- eller Android-app med hjälp av Photta API: skicka aldrig nyckeln till enheten, använd din backend som proxy, spegla jobbstatus.
LäsSnabbstart
Första Photta-bilden på under fem minuter.
Skapa konto, generera en API-nyckel, kör ditt första cURL-anrop, polla tills det är klart, spara resultatet. Fem steg, dokumenterade från början till slut.
LäsReferens
Photta API-prissättning
Vad varje Photta API-endpoint kostar i credits i 2K och 4K, hur debitering och återbetalning fungerar, samt vilka endpoints som är gratis. Inget fast pris i pengar per bild.
Läs
Varje siffra på den här sidan kommer från Photter API-dokumentationen · kontrollerad
Testa API:et på fem minuter
Generera en Photta API-nyckel, klistra in cURL-kodfragmentet ovan, och du har din första bild på en modell innan kaffet har bryggts klart.
- 1.5–4 min
- 5 credits vid 2K · 6 credits vid 4K
- asynkron, polling
- 600 requests/min
- Bearer-nyckel