Node.js · Workflows API
Workflows API 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/workflows/{workflow_id}, polla sedan /api/v1/workflows/generations/{id} var 3:e sekund tills status är completed.
- Typisk tid: 20–60 sec / image
- Credits: 4 credits vid 2K · 5 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/workflows/jewelry-studio-shot \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"images": {
"jewelry": [
"https://cdn.yourstore.com/products/gold-ring.jpg"
]
},
"options": {
"jewelryLighting": "dramatic",
"backdrop": "dark"
},
"user_text": "hero shot, ring angled slightly toward the camera",
"num_images": 2,
"aspect_ratio": "3:4",
"resolution": "2K"
}')
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/workflows/generations/$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/workflows/jewelry-studio-shot", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"images": {
"jewelry": [
"https://cdn.yourstore.com/products/gold-ring.jpg"
]
},
"options": {
"jewelryLighting": "dramatic",
"backdrop": "dark"
},
"user_text": "hero shot, ring angled slightly toward the camera",
"num_images": 2,
"aspect_ratio": "3:4",
"resolution": "2K"
}),
});
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/workflows/generations/${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/workflows/jewelry-studio-shot",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"images": {
"jewelry": [
"https://cdn.yourstore.com/products/gold-ring.jpg"
]
},
"options": {
"jewelryLighting": "dramatic",
"backdrop": "dark"
},
"user_text": "hero shot, ring angled slightly toward the camera",
"num_images": 2,
"aspect_ratio": "3:4",
"resolution": "2K"
},
)
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/workflows/generations/{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/workflows/{workflow_id}
- Autentisering
- Bearer API-nyckel
- Bearbetning
- Asynkron — polla status-endpointen
- Typisk tid
- 20–60 sec / image
- Credits
- 4 credits vid 2K · 5 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/workflows/{workflow_id}` med den dokumenterade exempel-bodyn — koden nedan innehåller alla fält. API:et returnerar ett generation-ID direkt. Polla `/api/v1/workflows/generations/{id}` var 3:e sekund tills `status === 'completed'`.
const res = await fetch("https://api.photta.app/api/v1/workflows/jewelry-studio-shot", { method: "POST", headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "images": { "jewelry": [ "https://cdn.yourstore.com/products/gold-ring.jpg" ] }, "options": { "jewelryLighting": "dramatic", "backdrop": "dark" }, "user_text": "hero shot, ring angled slightly toward the camera", "num_images": 2, "aspect_ratio": "3:4", "resolution": "2K" }), }); 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/workflows/generations/${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("/workflows/jewelry-studio-shot", { method: "POST", body: JSON.stringify({
"images": {
"jewelry": [
"https://cdn.yourstore.com/products/gold-ring.jpg"
]
},
"options": {
"jewelryLighting": "dramatic",
"backdrop": "dark"
},
"user_text": "hero shot, ring angled slightly toward the camera",
"num_images": 2,
"aspect_ratio": "3:4",
"resolution": "2K"
}) });
} 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/workflows/generations/{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
Workflows API i Python
Anropa Phottas workflows API i Python med requests-biblioteket. Wrapper på trettio rader, async-vänlig via httpx, fungerar i Django, FastAPI och Celery.
LäscURL
Workflows API med cURL
Anropa Phottas workflows API direkt från skalet med cURL. Skicka, polla, ladda ner — alla kodavsnitt fungerar tillsammans med jq för skriptade pipelines.
LäsFunktioner
Workflows API ett anrop, en förinställning
Kör färdiga scenmallar mot dina produktfoton. Katalogen deklarerar sina egna bildplatser och alternativ, så en enda integration täcker varje förinställning.
LäsBygg
Bygg en tjänst för AI-produktfotografering
En grundares playbook för att återförsälja Phottas virtuella try-on-API som en white-label-SaaS: klientnycklar, batch-fanout, fakturering per credit, SLA-realiteter.
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.
- 20–60 sec / image
- 4 credits vid 2K · 5 credits vid 4K
- asynkron, polling
- 600 requests/min
- Bearer-nyckel