Node.js · Ghost mannequin API
Ghost mannequin API w Node.js
W jednym zdaniu
Ustaw PHOTTA_API_KEY w env, napisz prosty helper fetch dla https://api.photta.app/api/v1 z kluczem Bearer, wyślij żądanie POST do /api/v1/ghost-mannequin, a następnie odpytuj /api/v1/ghost-mannequin/{id} co 3 sekundy, aż status zmieni się na completed.
- Typowy czas: 1.5–4 min
- Credits: 4 credits w 2K · 5 credits w 4K
- Przetwarzanie: asynchroniczne, polling
- Limity: 600 requests/min
- Uwierzytelnianie: Klucz Bearer
Każda liczba na tej stronie pochodzi z dokumentacji API Photta · sprawdzono
RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/ghost-mannequin \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
}')
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/ghost-mannequin/$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/ghost-mannequin", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
}),
});
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/ghost-mannequin/${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/ghost-mannequin",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
},
)
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/ghost-mannequin/{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")W skrócie
W skrócie
- Endpoint
- POST /api/v1/ghost-mannequin
- Uwierzytelnianie
- Klucz API Bearer
- Przetwarzanie
- Asynchroniczne — odpytuj endpoint statusu
- Typowy czas
- 1.5–4 min
- Credits
- 4 credits w 2K · 5 credits w 4K
- Proporcje obrazu
- 3:4 · 1:1 · 4:3 · 9:16 · 16:9
- Limity wejściowe
- Do 10 MB na obraz; JPEG, PNG, WebP
- Idempotentne
- Nie
Jak to działa
Pięć kroków, około pięciu minut od rejestracji do pierwszego obrazu.
Krok 1
Zarejestruj się i wygeneruj klucz
Utwórz konto na ai.photta.app. Otwórz sekcję Developers w panelu, kliknij Generate API key i pobierz klucz produkcyjny. Zaczyna się od `photta_live_`, po którym następuje 32 znaków szesnastkowych.
Krok 2
Przechowuj klucz w env, nie w kodzie źródłowym
Dodaj `PHOTTA_API_KEY=...` do `.env` (lub magazynu sekretów swojej platformy) i ładuj go przez `process.env`. Nigdy nie commituj klucza; nigdy nie importuj go do pliku oznaczonego jako `'use client'` — bundler wyeksponuje go w przeglądarce.
node --version # 18 or later ships fetch echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .envKrok 3
Napisz prosty helper fetch
Jeden 20-wierszowy wrapper wokół `fetch()` obsługuje bazowy URL, nagłówek Authorization, body JSON oraz normalizację błędów. To jedyna abstrakcja, jakiej potrzebujesz, dopóki nie pojawi się oficjalne SDK.
// 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; }Krok 4
Wyślij zadanie try-on i wykonaj polling
Wyślij POST do `/api/v1/ghost-mannequin` z przykładowym body z dokumentacji — poniższy kod zawiera każde pole. API natychmiast zwraca ID generowania. Wykonuj polling do `/api/v1/ghost-mannequin/{id}` co 3 sekundy, aż `status === 'completed'`.
const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", { method: "POST", headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg", "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg", "image_side": "front", "angle": "side", "style": "3d", "background_color": "white", "resolution": "2K", "aspect_ratio": "3:4", "user_instruction": "closed front, cream interior lining", "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67" }), }); 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/ghost-mannequin/${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"); }Krok 5
Zapisz wynik na stałe
Ukończony payload zawiera `output_url` i `thumbnail_url`. Pobierz bajty raz i zapisz je we własnym object storage — adresy URL są stabilne, ale Twój produkt nie powinien zależeć od CDN-u Photta przy renderowaniu.
Błędy
- 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("/ghost-mannequin", { method: "POST", body: JSON.stringify({
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
}) });
} 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;
}Limity
- 600 żądań na minutę na klucz API (Stałe okno czasowe; limit jest taki sam w każdym planie)
- Odpowiedź 429 zawiera nagłówek Retry-After: 30 s
- Do 10 MB na obraz
- Formaty: JPEG, PNG, WebP
- Jednoczesne zadania wsadowe w zależności od planu: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
- Tylko polling — API nie wysyła webhooków.
Dlaczego helper wygrywa z biblioteką klienta — na ten moment
- Node 18+ zawiera natywny fetch — zero zależności w runtime
- Ten sam helper działa wewnątrz route handlerów Next.js, server actions i dowolnego workera
- Trzymaj klucz API w env; nigdy nie importuj helpera z modułu 'use client', bo inaczej bundler go ujawni
- Działa z każdą kolejką lub cronem: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues
Czego nie robi
- Brak oficjalnego pakietu @photta/node — na dziś REST to jedyna ścieżka
- Polling jest jedynym sygnałem ukończenia; API nie wysyła webhooków
- Tylko klucz Bearer; brak przepływu OAuth client-credentials
Pytania zadawane przez programistów
Czy istnieje oficjalne Photta Node.js SDK?
Jeszcze nie. Udokumentowaną ścieżką jest czysty REST przez natywny fetch w Node — helper na tej stronie to cała powierzchnia integracji i działa tak samo dla każdej capability.
Jakie wersje Node.js są obsługiwane?
Wszystkie obsługujące natywny `fetch` — czyli Node 18 i nowsze. Na Node 16 musisz użyć polyfilla z `node-fetch` albo zrobić upgrade. Reszta kodu to zwykły ECMAScript 2020 (async/await, template literals, dynamic imports), więc brak innych wymagań runtime.
Jak uwierzytelniać się z poziomu Node?
Wysyłaj `Authorization: Bearer photta_live_xxx` przy każdym żądaniu. Umieść klucz w zmiennej środowiskowej i wczytuj go przez `process.env`; nigdy nie importuj go z pliku uruchamianego w przeglądarce.
Jak obsłużyć okno generowania?
Endpoint generowania jest w pełni asynchroniczny. POST natychmiast zwraca ID generowania ze statusem `status: 'processing'`. Wykonuj polling `GET /api/v1/ghost-mannequin/{id}` co 3–5 sekund, aż `status` zmieni się na `completed` lub `failed`, i ustaw limit prób, aby zablokowane zadanie nie zawiesiło żądania.
Czy mogę wywoływać API wewnątrz Next.js?
Tak — z poziomu route handlera (`app/**/route.ts`), server action (`'use server'`) lub middleware. Trzymaj klucz API na serwerze; nigdy nie importuj helpera z pliku `'use client'`. W przypadku długo trwających zadań przekraczających timeout funkcji w Vercel, oddeleguj polling do kolejki (Inngest, Trigger.dev, BullMQ) i zwróć ID generowania do przeglądarki, aby mogła odpytywać Twój własny endpoint statusu.
Jak API sygnalizuje błędy?
Odpowiedzi inne niż 2xx zawierają body JSON z obiektem `error`: `type`, `code`, `message` oraz ID żądania dla celów wsparcia. Typowe przypadki: 400 invalid_request_error z parametrem `param` wskazującym na błędne pole; 402 insufficient_credits z liczbami `required` i `available`; 429 rate_limit_exceeded z wartością `retry_after` w sekundach i pasującym nagłówkiem Retry-After. Błędy 5xx można bezpiecznie ponawiać z użyciem exponential backoff.
Powiązane strony
Python
Ghost mannequin API w Pythonie
Wywołuj Photta ghost mannequin API w Pythonie za pomocą biblioteki requests. Trzydziestowierszowy wrapper, przyjazny dla async dzięki httpx, działa w Django, FastAPI i Celery.
CzytajcURL
Ghost mannequin API z cURL
Wywołuj ghost mannequin API Photta bezpośrednio z powłoki za pomocą cURL. Wysyłaj, odpytuj, pobieraj — każdy fragment kodu współpracuje z jq w zautomatyzowanych potokach.
CzytajMożliwości
Ghost mannequin API do zdjęć produktowych typu hollow-man
Endpoint AI ghost mannequin. Usuń manekina ze zdjęcia odzieży i zachowaj detale wnętrza. 3D lub flat-lay, przetwarzanie wsadowe, 4 credits w 2K.
CzytajTwórz
Zautomatyzuj wycinanie manekina (ghost mannequin) w swoim katalogu
Przepis na nocną automatyzację katalogu: pobierz wczorajsze aktualizacje produktów, wyślij je wsadowo do API ghost-mannequin w Photta, odpytuj nadrzędny batch i zapisz wyniki w bazie danych.
CzytajSzybki start
Pierwszy obraz z Photta w mniej niż pięć minut.
Zarejestruj się, wygeneruj klucz API, wykonaj pierwsze wywołanie cURL, odpytuj aż do ukończenia, zapisz wynik. Pięć kroków opisanych od początku do końca.
CzytajDokumentacja
Cennik Photta API
Informacje o kosztach każdego endpointu Photta API w credits dla rozdzielczości 2K i 4K, zasadach naliczania opłat i zwrotów oraz bezpłatnych endpointach. Brak bezpośredniej ceny pieniężnej za zdjęcie.
Czytaj
Każda liczba na tej stronie pochodzi z dokumentacji API Photta · sprawdzono
Wypróbuj API w 5 minut
Wygeneruj klucz Photta API, wklej powyższy snippet cURL, a otrzymasz swoje pierwsze zdjęcie na modelu, zanim zaparzy się kawa.
- 1.5–4 min
- 4 credits w 2K · 5 credits w 4K
- asynchroniczne, polling
- 600 requests/min
- Klucz Bearer