Python · API di Virtual try-on
API di Virtual try-on in Python
In sintesi
Installa requests, carica PHOTTA_API_KEY dalle variabili d'ambiente, scrivi un wrapper photta() che invia la chiave Bearer e solleva un PhottaError tipizzato sulle risposte non-2xx, quindi invia una POST a /api/v1/tryon/apparel ed esegui il polling su /api/v1/tryon/apparel/{id} ogni 3 secondi finché lo status non è completed.
- Tempo tipico: 1.5–4 min
- Credits: 5 credits a 2K · 6 credits a 4K
- Elaborazione: asincrono, polling
- Limiti: 600 richieste/min
- Autenticazione: Chiave Bearer
Ogni dato in questa pagina proviene da la documentazione dell'API di Photta · verificato
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")Panoramica
Panoramica
- Endpoint
- POST /api/v1/tryon/apparel
- Autenticazione
- API key Bearer
- Elaborazione
- Asincrona — effettua il polling dell'endpoint di stato
- Tempo tipico
- 1.5–4 min
- Credits
- 5 credits a 2K · 6 credits a 4K
- Rapporti d'aspetto
- 3:4 · 1:1 · 4:3 · 9:16 · 16:9
- Limiti di input
- Fino a 10 MB per immagine; JPEG, PNG, WebP
- Idempotente
- No
Come funziona
Cinque passaggi, zero dipendenze specifiche di Photta — requests copre tutto.
Passaggio 1
Registrati e genera una chiave
Stesso percorso di qualsiasi altro linguaggio: ai.photta.app → Developers → Generate API key. Le chiavi iniziano con `photta_live_` e funzionano per ogni capability di Photta.
Passaggio 2
Carica la chiave dalle variabili d'ambiente
Imposta `PHOTTA_API_KEY` nell'ambiente e leggila tramite `os.environ`. In FastAPI o Django, caricala una sola volta all'avvio in un modulo settings. Non incorporare la chiave nel codice sorgente o nella cronologia Git pubblica.
python3 -m pip install requests export PHOTTA_API_KEY="photta_live_xxxxx"Passaggio 3
Scrivi un wrapper per requests
Una funzione `photta_request()` di trenta righe gestisce l'URL di base, l'header Authorization, la serializzazione JSON e la traduzione degli errori. È l'unica astrazione di cui hai bisogno finché non sarà disponibile l'SDK Python.
# photta.py — one helper for every endpoint import os, requests BASE = "https://api.photta.app/api/v1" class PhottaError(Exception): def __init__(self, status, error, retry_after=None): super().__init__(error.get("message", "request failed")) self.status, self.type, self.retry_after = status, error.get("type"), retry_after def photta(method, path, **kwargs): res = requests.request(method, BASE + path, headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"}, timeout=30, **kwargs) body = res.json() if not res.ok: raise PhottaError(res.status_code, body.get("error", {}), res.headers.get("Retry-After")) return bodyPassaggio 4
Invia ed effettua il polling
Invia una POST a `/api/v1/tryon/apparel` per ottenere un ID di generazione, quindi esegui il polling di `/api/v1/tryon/apparel/{id}` a intervalli di 3 secondi. In Celery o RQ, suddividi il loop di polling su più task in modo che un job di diversi minuti non blocchi un worker.
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")Passaggio 5
Salva il risultato
Il payload completato include `output_url` e `thumbnail_url`. Scarica i byte nel tuo object storage — S3, GCS, Cloudflare R2 — così il tuo prodotto non dipenderà dal CDN di Photta per il rendering a lungo termine.
Errori
- 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:
photta("POST", "/tryon/apparel", 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."
})
except PhottaError as e:
if e.status == 402:
print("insufficient_credits_error: top up before retrying")
elif e.status == 429:
time.sleep(int(e.retry_after or 30))
else:
raiseLimiti
- 600 richieste al minuto per API key (Finestra fissa; il limite è lo stesso per ogni piano)
- Un 429 restituisce Retry-After: 30 secondi
- Fino a 10 MB per immagine
- Formati: JPEG, PNG, WebP
- Batch simultanei per piano: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
- Solo polling — l'API non invia webhook.
Perché requests è la scelta giusta oggi
- Nessuna dipendenza specifica per Photta — requests è già presente nella maggior parte dei progetti Python
- Funziona ovunque giri Python: Django, FastAPI, Flask, worker Celery, Lambda, script
- Il wrapper client è di circa trenta righe — incollalo in photta.py e vai avanti
- Si abbina ad asyncio tramite httpx quando hai bisogno di invii paralleli
Cosa non fa
- Nessun pacchetto Python ufficiale di Photta per ora — REST con requests è il pattern documentato
- Il polling è l'unico segnale di completamento; l'API non invia webhook
- Solo Bearer key; non esiste un flusso OAuth client-credentials
Domande frequenti degli sviluppatori
Esiste un SDK Python ufficiale di Photta?
Non ancora. Il percorso di integrazione supportato prevede la libreria requests (sincrona) o httpx (asincrona) — entrambe richiedono solo un sottile wrapper, e quello presente in questa pagina funziona per ogni funzionalità.
Quali versioni di Python sono supportate?
Python 3.9 e successive. Il wrapper utilizza type hint, f-string e la sintassi `str | None`, perfetta su 3.10+. Su 3.9 sostituisci `str | None` con `Optional[str]`. requests supporta ufficialmente la versione 3.8+, ma la 3.9+ rappresenta il minimo pratico per i progetti Photta moderni.
Dovrei usare requests o httpx?
requests se devi effettuare una manciata di chiamate sequenziali — è più semplice ed è già presente nella maggior parte delle codebase. httpx se ti serve la concorrenza asincrona (invii paralleli, backfill massivi) o HTTP/2. Il wrapper è minuscolo in entrambi i casi; sostituisci `requests.request` con `httpx.Client().request` e il resto del codice rimane identico.
Posso chiamarlo da Django?
Sì. Inserisci il wrapper in `services/photta.py`, importalo da una view o da un task Celery. Non chiamare l'API all'interno di un request handler sincrono se il job richiede tempo — invialo dalla view, restituisci l'ID di generazione ed esegui il polling da un background task o da un consumer Channels.
Come eseguo il polling da un worker Celery?
Invia il job da un task, poi pianifica un task successivo (tramite `apply_async(countdown=3)`) che effettua il polling una volta e si rischedula da solo fino al completamento del job o al raggiungimento della soglia massima di tentativi. In questo modo i worker rimangono liberi ed eviti task a lunga esecuzione che mandano in crisi l'autoscaling.
In che modo l'API segnala gli errori?
Le risposte non-2xx contengono un body JSON con un oggetto `error`: `type`, `code`, `message`, oltre a `param` sui 400 e `retry_after` sui 429. Il wrapper in questa pagina solleva un `PhottaError` contenente tutti questi campi, consentendo al codice chiamante di gestire i branch in base allo status code senza dover parsare manualmente il body.
Pagine correlate
Node.js
API di Virtual try-on in Node.js
Chiama aPI di Virtual try-on di Photta da un backend Node.js con fetch nativo. Nessun SDK richiesto: salva la chiave, invia il job, esegui il polling per il risultato.
LeggicURL
API di Virtual try-on con cURL
Chiama aPI di Virtual try-on di Photta direttamente dalla shell con cURL. Invia, effettua il polling, scarica — ogni snippet si integra con jq per pipeline basate su script.
LeggiFunzionalità
API di Virtual try-on per abbigliamento
REST API per applicare capi di abbigliamento su manichini AI. Generazione asincrona in 1.5–4 minuti, 5 crediti a 2K, 6 a 4K. Esempi per cURL, Node.js e Python.
LeggiSviluppa
Implementa una funzionalità di virtual try-on per la tua applicazione
Ricetta end-to-end per rilasciare una funzionalità di virtual try-on con l'API Photta: upload, invio, polling tramite un worker, rendering del risultato. Pattern TypeScript + server-only.
LeggiSviluppa
Aggiungi il try-on virtuale a un'app iOS o Android
Come aggiungere il try-on virtuale basato su IA a un'app nativa iOS o Android usando l'API di Photta: non rilasciare mai la chiave sul dispositivo, usa il backend come proxy, rispecchia lo stato dei job.
LeggiGuida rapida
La prima immagine con Photta in meno di cinque minuti.
Registrati, genera una chiave API, esegui la tua prima chiamata cURL, fai polling fino al completamento, salva il risultato. Cinque passaggi, interamente documentati.
LeggiRiferimento
Prezzi dell'API Photta
Il costo in crediti di ogni endpoint delle API di Photta a 2K e 4K, il funzionamento di addebiti e rimborsi, e quali endpoint sono gratuiti. Nessun prezzo monetario per immagine.
Leggi
Ogni dato in questa pagina proviene da la documentazione dell'API di Photta · verificato
Prova l'API in 5 minuti
Genera una chiave API di Photta, incolla lo snippet cURL qui sopra e otterrai la tua prima immagine con modello prima ancora che il caffè sia pronto.
- 1.5–4 min
- 5 credits a 2K · 6 credits a 4K
- asincrono, polling
- 600 richieste/min
- Chiave Bearer