Python · Ghost mannequin API

Ghost mannequin API in Python

In één zin

Installeer requests, laad PHOTTA_API_KEY vanuit env, schrijf een photta()-wrapper die de Bearer-sleutel verstuurt en een getypeerde PhottaError opwerpt bij niet-2xx-antwoorden, voer vervolgens een POST uit naar /api/v1/ghost-mannequin en voer elke 3 seconden polling uit op /api/v1/ghost-mannequin/{id} totdat de status completed is.

  • Typische duur: 1.5–4 min
  • Credits: 4 credits bij 2K · 5 credits bij 4K
  • Verwerking: async, polling
  • Limieten: 600 requests/min
  • Authenticatie: Bearer key

Elk getal op deze pagina is afkomstig uit de Photta-API-documentatie · gecontroleerd

POST/api/v1/ghost-mannequin
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")

In één oogopslag

In één oogopslag

Endpoint
POST /api/v1/ghost-mannequin
Authenticatie
Bearer API key
Verwerking
Asynchroon — poll het status-endpoint
Typische duur
1.5–4 min
Credits
4 credits bij 2K · 5 credits bij 4K
Beeldverhoudingen
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Invoerlimieten
Tot 10 MB per afbeelding; JPEG, PNG, WebP
Idempotent
Nee

Hoe het werkt

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

  1. Stap 1

    Meld je aan en genereer een sleutel

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

  2. Stap 2

    Laad de sleutel vanuit env

    Stel `PHOTTA_API_KEY` in binnen de omgeving en lees deze uit via `os.environ`. Laad deze in FastAPI of Django eenmalig bij het opstarten in een settings-module. Neem de sleutel niet op in de broncode of in de openbare Git-geschiedenis.

    python3 -m pip install requests
    export PHOTTA_API_KEY="photta_live_xxxxx"
  3. Stap 3

    Schrijf een requests-wrapper

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

    # 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 body
  4. Stap 4

    Verzenden en pollen

    POST naar `/api/v1/ghost-mannequin` om een generatie-ID op te halen en poll vervolgens `/api/v1/ghost-mannequin/{id}` met een interval van 3 seconden. Splits in Celery of RQ de poll-lus op over meerdere taken, zodat een taak van meerdere minuten geen worker bezet houdt.

    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")
  5. Stap 5

    Sla het resultaat op

    De voltooide payload bevat `output_url` en `thumbnail_url`. Download de bytes naar je eigen objectopslag — S3, GCS, Cloudflare R2 — zodat je product voor weergave op lange termijn niet afhankelijk is van het CDN van Photta.

Errors

400invalid_request_error
The request is malformed or contains invalid parameters.
401authentication_error
The API key is missing, invalid, or expired.
402insufficient_credits_error
Your account does not have enough credits.
404not_found_error
The requested resource does not exist.
409conflict_error
The request conflicts with current state — e.g. your concurrent-batch cap is reached.
429rate_limit_error
Too many requests. Slow down and retry.Retry-After: 30
500api_error
An internal server error occurred. Retry later.
try:
    photta("POST", "/ghost-mannequin", 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"
    })
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:
        raise

Limieten

  • 600 verzoeken per minuut per API key (Vast venster; de limiet is identiek op elk abonnement)
  • Een 429 bevat Retry-After: 30 seconden
  • Tot 10 MB per afbeelding
  • Formaten: JPEG, PNG, WebP
  • Gelijktijdige batches per abonnement: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Uitsluitend polling — de API stuurt geen webhooks.

Waarom requests vandaag de juiste keuze is

  • Geen Photta-specifieke afhankelijkheid — requests zit al in de meeste Python-projecten
  • Werkt overal waar Python draait: Django, FastAPI, Flask, Celery-workers, Lambda, scripts
  • De client-wrapper telt ongeveer dertig regels — plak hem in photta.py en ga door
  • Combineert via httpx met asyncio wanneer je parallelle verzoeken moet indienen

Wat het niet doet

  • Nog geen officieel Photta Python-package — REST met requests is het gedocumenteerde patroon
  • Polling is het enige signaal voor voltooiing; de API verstuurt geen webhooks
  • Uitsluitend Bearer-sleutel; er is geen OAuth client-credentials-flow

Veelgestelde vragen van developers

Is er een officiële Photta Python SDK?

Nog niet. Het ondersteunde integratiepad is de requests-library (synchroon) of httpx (asynchroon) — voor beide volstaat een minimale wrapper, en de wrapper op deze pagina werkt voor elke capability.

Welke Python-versies worden ondersteund?

Python 3.9 en hoger. De wrapper gebruikt type hints, f-strings en `str | None`-syntaxis, wat prima werkt op 3.10+. Vervang op 3.9 `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 sequentiële aanroepen doet — het is eenvoudiger en zit al in de meeste codebases. httpx als je asynchrone gelijktijdigheid nodig hebt (parallel verzenden, bulk-backfills) of HTTP/2. De wrapper is in beide gevallen minuscuul; 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` en importeer deze vanuit een view of een Celery-taak. Roep de API niet aan binnen een synchrone request-handler als de taak lang duurt — dien de aanvraag 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 één worker-taak en plan vervolgens een vervolgtaak in (via `apply_async(countdown=3)`) die één keer pollt en zichzelf opnieuw inplant totdat de taak voltooid is of de drempelwaarde voor maximale pogingen wordt bereikt. Dit houdt workers vrij en voorkomt langdurige taken die autoscalers verstoren.

Hoe geeft de API fouten aan?

Niet-2xx-antwoorden bevatten een JSON-body met een `error`-object: `type`, `code`, `message`, plus `param` bij 400's en `retry_after` bij 429's. De wrapper op deze pagina genereert een `PhottaError` die al deze gegevens bevat, zodat je aanroepende code kan vertakken op basis van de statuscode zonder zelf de body te hoeven parsen.

Probeer de API in vijf minuten

Genereer een Photta API-sleutel, plak het bovenstaande cURL-fragment en je hebt je eerste afbeelding op een model voordat de koffie klaar is.

  • 1.5–4 min
  • 4 credits bij 2K · 5 credits bij 4K
  • async, polling
  • 600 requests/min
  • Bearer key