Python · Virtual Try-On API

Virtual Try-On API in Python

Er is geen pip install photta nodig — de Photta-documentatie beveelt officieel de requests-bibliotheek aan. Een wrapper van dertig regels sluit zonder gedoe aan op Django, FastAPI, Celery-workers en Lambda-handlers.

In één zin

Installeer `requests`, laad `PHOTTA_API_KEY` vanuit env, schrijf een `photta_request()` wrapper die `Authorization: Bearer photta_live_xxx` stuurt en een getypeerde `PhottaError` genereert bij niet-2xx responses. Doe vervolgens een POST naar `/tryon/apparel` en poll `/tryon/apparel/:id` elke 3 seconden totdat `data.status == 'completed'` — meestal binnen 1.5 tot 4 minuten.

Bijgewerkt · 2026-04-19

Je eerste verzoek

PythonNode.jscURLcURL
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)

Wat je kunt verwachten

Typical completion

1.5–4min

2K / 4K credits

5 / 7

Jewelry types

4

Close-up mannequins

built-in

Hoe het werkt

Virtual Try-On API in Python

Vijf stappen, nul Photta-specifieke dependencies — requests dekt alles.

  1. 01

    Stap 1

    Meld je aan en genereer een sleutel

    Zelfde pad als elke andere taal: ai.photta.app → Developers → Generate API key. Sleutels beginnen met `photta_live_` en werken voor elke Photta-mogelijkheid.

  2. 02

    Stap 2

    Laad de sleutel vanuit env

    Stel `PHOTTA_API_KEY` in in de omgeving en lees deze uit via `os.environ`. In FastAPI of Django laad je dit eenmalig bij het opstarten in een settings-module. Plaats de sleutel niet in de broncode of publieke Git-geschiedenis.

  3. 03

    Stap 3

    Schrijf een requests-wrapper

    Een `photta_request()` functie van dertig regels handelt de basis-URL, de Authorization header, JSON-serialisatie en fout-vertaling af. Dat is de enige abstractie die je nodig hebt totdat de Python SDK verschijnt.

  4. 04

    Stap 4

    Indienen en pollen

    POST naar `/tryon/apparel` om een generatie-ID te krijgen, en poll vervolgens `/tryon/apparel/:id` met een interval van 3 seconden. In Celery of RQ breek je de poll-loop op over verschillende taken, zodat een taak van 4 minuten geen worker bezet houdt.

  5. 05

    Stap 5

    Sla het resultaat op

    De voltooid-payload bevat `output_url` en `thumbnail_url`. Download de bytes naar je eigen object storage — S3, GCS, Cloudflare R2 — zodat je product niet afhankelijk is van Photta's CDN voor langdurige weergave.

Code, van begin tot eind

Copy, paste, done.

Four snippets — install prerequisites, wrap the REST call, submit + poll, then handle the errors that actually happen in production.

01Use the battle-tested requests library
bash
# 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
02A 30-line client wrapper you can drop into any project
python
# 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 body
03Submit a try-on and poll until the result is ready
python
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)
04Handle 402 credit exhaustion and 429 rate limits
python
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:
        raise

Waarom deze vorm

Waarom requests vandaag de juiste keuze is

  • 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

Wat het niet doet

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

Vragen die andere developers stellen

Questions other developers ask

Is er een officiële Photta Python SDK?+

Nog niet. De Photta-roadmap geeft prioriteit aan de Python SDK zodra er tien betalende API-klanten live zijn. Tot die tijd is het ondersteunde integratiepad de requests-bibliotheek (synchroon) of httpx (asynchroon) — beide worden beschreven in de officiële documentatie en beide werken met de wrapper van dertig regels op deze pagina.

Welke Python versies worden ondersteund?+

Python 3.9 en later. De wrapper gebruikt type hints, f-strings en de `str | None` syntaxis, wat prima werkt op 3.10+. Op 3.9 vervang je `str | None` door `Optional[str]`. requests zelf ondersteunt officieel 3.8+, maar 3.9+ is het praktische minimum voor moderne Photta-projecten.

Moet ik requests of httpx gebruiken?+

requests als je een handvol opeenvolgende calls doet — het is eenvoudiger en zit al in de meeste codebases. httpx als je asynchrone gelijktijdigheid nodig hebt (parallelle indieningen, bulk-backfills) of HTTP/2. De wrapper is in beide gevallen klein; vervang `requests.request` door `httpx.Client().request` en de rest van de code blijft identiek.

Kan ik dit aanroepen vanuit Django?+

Ja. Plaats de wrapper in `services/photta.py`, importeer deze vanuit een view of een Celery-task. Roep de API niet aan binnen een synchrone request handler als de taak lang duurt — dien in vanuit de view, retourneer het generatie-ID en poll vanuit een achtergrondtaak of een Channels-consumer.

Hoe poll ik vanuit een Celery worker?+

Dien de taak in vanuit de ene task en plan vervolgens een vervolg-task in (via `apply_async(countdown=3)`) die eenmalig pollt en zichzelf opnieuw inplant totdat de taak is voltooid of een maximum aantal pogingen is bereikt. Dit houdt workers vrij en voorkomt langlopende taken die autoscalers verstoren.

Hoe signaleert de API fouten?+

Niet-2xx responses bevatten een JSON-body met een `error`-object: `type`, `code`, `message`, plus `param` bij 400s en `retry_after` bij 429s. De wrapper op deze pagina genereert een `PhottaError` die dit allemaal bevat, zodat je callers kunnen differentiëren op statuscode zonder de body zelf te hoeven parsen.

Python · Virtual Try-On API

Maak een account aan en ontvang een API-sleutel

Installeer `requests`, laad `PHOTTA_API_KEY` vanuit env, schrijf een `photta_request()` wrapper die `Authorization: Bearer photta_live_xxx` stuurt en een getypeerde `PhottaError` genereert bij niet-2xx responses. Doe vervolgens een POST naar `/tryon/apparel` en poll `/tryon/apparel/:id` elke 3 seconden totdat `data.status == 'completed'` — meestal binnen 1.5 tot 4 minuten.

Virtual Try-On API voor Python — Photta | Photta