Python · Virtual Try-On API
Virtual Try-On API in Python
Non serve nessun pip install photta — la documentazione raccomanda ufficialmente la libreria requests. Un wrapper di trenta righe si integra in Django, FastAPI, Celery e Lambda senza complicazioni.
In una frase
Installa requests, carica PHOTTA_API_KEY da env, scrivi un wrapper photta_request() che invia Authorization: Bearer photta_live_xxx e solleva una PhottaError tipizzata per risposte non-2xx, quindi POST su /tryon/apparel e polling di /tryon/apparel/:id ogni 3 secondi finché data.status == 'completed' — solitamente tra 1.5 e 4 minuti.
Aggiornato · 2026-04-19
La tua prima richiesta
import time
from photta import photta_request, PhottaError
# 1. Submit the job
created = photta_request("POST", "/tryon/apparel", json={
"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",
})
generation_id = created["data"]["id"]
# 2. Poll every 3 seconds. Upper bound: 120 attempts ≈ 6 minutes,
# comfortably above the documented 1.5–4 minute window.
for _ in range(120):
result = photta_request("GET", f"/tryon/apparel/{generation_id}")
status = result["data"]["status"]
if status == "completed":
print("Result:", result["data"]["output_url"])
break
if status == "failed":
raise RuntimeError(result["data"]["error_message"])
time.sleep(3)Cosa aspettarsi
Typical completion
1–3min
2K / 4K credits
4 / 6
Styles
2
Batch-ready
yes
Come funziona
Virtual Try-On API in Python
Cinque step, zero dipendenze specifiche di Photta — requests copre tutto.
- 01
Step 1
Registrati e genera una chiave
Stesso percorso degli altri linguaggi: ai.photta.app → Developers → Generate API key. Le chiavi iniziano con photta_live_ e funzionano per ogni funzionalità Photta.
- 02
Step 2
Carica la chiave da env
Imposta PHOTTA_API_KEY nell'ambiente e leggila tramite os.environ. In FastAPI o Django, caricala all'avvio in un modulo settings. Non inserire la chiave nel codice sorgente o nella cronologia Git pubblica.
- 03
Step 3
Scrivi un wrapper per requests
Una funzione photta_request() di trenta righe gestisce URL base, header Authorization, serializzazione JSON e traduzione degli errori. È l'unica astrazione necessaria finché non uscirà l'SDK Python.
- 04
Step 4
Invia e polling
POST su /tryon/apparel per ottenere un ID generazione, poi polling di /tryon/apparel/:id ogni 3 secondi. In Celery o RQ, dividi il loop di polling tra i task per non bloccare un worker per 4 minuti.
- 05
Step 5
Salva il risultato
Il payload completato include output_url e thumbnail_url. Scarica i byte nel tuo storage (S3, GCS, Cloudflare R2) in modo che il tuo prodotto non dipenda dalla CDN di Photta a lungo termine.
Codice, end to end
Copy, paste, done.
Four snippets — install prerequisites, wrap the REST call, submit + poll, then handle the errors that actually happen in production.
# Photta doesn't ship an official Python SDK yet — requests is the
# recommended path in the docs. Standard library urllib works too if
# you need zero dependencies.
pip install requests
# Store your API key in env (dotenv optional but convenient)
echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env# photta.py
import os
import requests
PHOTTA_BASE_URL = "https://ai.photta.app/api/v1"
class PhottaError(Exception):
def __init__(self, status: int, code: str, message: str, retry_after: int | None = None):
super().__init__(message)
self.status = status
self.code = code
self.retry_after = retry_after
def photta_request(method: str, path: str, **kwargs):
headers = {
"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}",
"Content-Type": "application/json",
**kwargs.pop("headers", {}),
}
response = requests.request(method, f"{PHOTTA_BASE_URL}{path}", headers=headers, **kwargs)
body = response.json()
if not response.ok:
err = body.get("error", {})
raise PhottaError(
status=response.status_code,
code=err.get("code", "unknown"),
message=err.get("message", response.reason),
retry_after=err.get("retry_after"),
)
return bodyimport time
from photta import photta_request, PhottaError
# 1. Submit the job
created = photta_request("POST", "/tryon/apparel", json={
"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",
})
generation_id = created["data"]["id"]
# 2. Poll every 3 seconds. Upper bound: 120 attempts ≈ 6 minutes,
# comfortably above the documented 1.5–4 minute window.
for _ in range(120):
result = photta_request("GET", f"/tryon/apparel/{generation_id}")
status = result["data"]["status"]
if status == "completed":
print("Result:", result["data"]["output_url"])
break
if status == "failed":
raise RuntimeError(result["data"]["error_message"])
time.sleep(3)from photta import photta_request, PhottaError
import time
try:
photta_request("POST", "/tryon/apparel", json={ ... })
except PhottaError as err:
if err.status == 402:
# Out of credits — err.code == "insufficient_credits"
raise
elif err.status == 429:
# Rate-limited. Honour the Retry-After header.
time.sleep(err.retry_after or 30)
# then retry…
elif err.status >= 500:
# Server-side — retry with exponential backoff.
raise
else:
raisePerché questa struttura
Perché requests è la scelta giusta oggi
- Zero Photta-specific dependencies — `requests` is already in most Python projects
- Works anywhere Python runs: Django, FastAPI, Flask, Celery workers, Lambda, scripts
- The client wrapper is ~30 lines — paste it into `photta.py` and move on
- Pairs naturally with asyncio via `httpx` if you need parallel submission
Cosa non fa
Honest caveats
- No official @photta/python SDK yet — REST + requests is the documented pattern
- No async fetch helper shipped; swap `requests` for `httpx` when you need concurrency
- Bearer token auth only — no OAuth client credentials yet
Domande frequenti degli sviluppatori
Questions other developers ask
Esiste un SDK Python ufficiale di Photta?+
Non ancora. La roadmap di Photta prioritizza l'SDK Python una volta raggiunti i dieci clienti API paganti. Fino ad allora, il percorso supportato è la libreria requests (sincrona) o httpx (asincrona) — entrambe documentate e compatibili con il wrapper in questa pagina.
Quali versioni di Python sono supportate?+
Python 3.9 e successivi. Il wrapper usa type hints, f-strings e la sintassi str | None, corretta su 3.10+. Su 3.9 sostituisci str | None con Optional[str]. requests supporta ufficialmente 3.8+, ma 3.9+ è il minimo pratico per progetti Photta moderni.
Dovrei usare requests o httpx?+
requests se effettui poche chiamate sequenziali — è più semplice e già presente in molti progetti. httpx se hai bisogno di concorrenza asincrona (invii paralleli, backfill massivi) o HTTP/2. Il wrapper è simile; sostituisci requests.request con httpx.Client().request e il resto del codice rimane identico.
Posso chiamarla da Django?+
Sì. Inserisci il wrapper in services/photta.py, importalo in una view o un task Celery. Non chiamare l'API dentro un handler di richiesta sincrono se il job è lungo — invia dalla view, restituisci l'ID generazione e gestisci il polling in background via task o consumer Channels.
Come effettuo il polling da un worker Celery?+
Invia il job da un task, poi pianifica un task successivo (via apply_async(countdown=3)) che controlla lo stato una volta e si ripianifica finché il job non è completato o raggiunge il limite di tentativi. Questo mantiene i worker liberi ed evita task a lunga esecuzione che disturbano l'autoscaling.
Come vengono segnalati gli errori dall'API?+
Le risposte non-2xx includono un body JSON con un oggetto error: type, code, message, oltre a param per i 400 e retry_after per i 429. Il wrapper in questa pagina solleva una PhottaError con questi dati per permetterti di gestire i vari codici di stato senza parsare il body manualmente.
Python · Virtual Try-On API
Crea un account e ottieni una API key
Installa requests, carica PHOTTA_API_KEY da env, scrivi un wrapper photta_request() che invia Authorization: Bearer photta_live_xxx e solleva una PhottaError tipizzata per risposte non-2xx, quindi POST su /tryon/apparel e polling di /tryon/apparel/:id ogni 3 secondi finché data.status == 'completed' — solitamente tra 1.5 e 4 minuti.