Python · Ghost mannequin API

Ghost mannequin API i Python

I én sætning

Installer requests, indlæs PHOTTA_API_KEY fra env, skriv en photta()-wrapper, der sender Bearer-nøglen og kaster en typet PhottaError ved ikke-2xx-svar, lav derefter POST til /api/v1/ghost-mannequin og poll /api/v1/ghost-mannequin/{id} hvert 3. sekund, indtil status er completed.

  • Typisk tid: 1.5–4 min
  • Credits: 4 credits ved 2K · 5 credits ved 4K
  • Behandling: async, polling
  • Grænser: 600 requests/min
  • Autentifikation: Bearer key

Hvert tal på denne side stammer fra Photta API-dokumentationen · tjekket

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")

Kort fortalt

Kort fortalt

Endpoint
POST /api/v1/ghost-mannequin
Autentifikation
Bearer API-nøgle
Behandling
Asynkron — poll status-endpointet
Typisk tid
1.5–4 min
Credits
4 credits ved 2K · 5 credits ved 4K
Billedformater
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Inputgrænser
Op til 10 MB pr. billede; JPEG, PNG, WebP
Idempotent
Nej

Sådan virker det

Fem trin, nul Photta-specifikke afhængigheder — requests dækker det hele.

  1. Trin 1

    Tilmeld dig og generer en nøgle

    Samme fremgangsmåde som for alle andre sprog: ai.photta.app → Developers → Generate API key. Nøgler starter med `photta_live_` og fungerer på tværs af alle Photta-capabilities.

  2. Trin 2

    Indlæs nøglen fra env

    Sæt `PHOTTA_API_KEY` i miljøet og læs den via `os.environ`. I FastAPI eller Django indlæses den én gang ved opstart i et settings-modul. Undgå at indlejre nøglen i kildekode eller offentlig Git-historik.

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

    Skriv en requests-wrapper

    En tredive linjers `photta_request()`-funktion håndterer base-URL'en, Authorization-headeren, JSON-serialisering og fejloversættelse. Det er den eneste abstraktion, du har brug for, indtil Python SDK'et udgives.

    # 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. Trin 4

    Indsend og poll

    Lav en POST til `/api/v1/ghost-mannequin` for at få et genererings-ID, og poll derefter `/api/v1/ghost-mannequin/{id}` med et interval på 3 sekunder. I Celery eller RQ bør du fordele poll-loopet over flere tasks, så et job på flere minutter ikke blokerer en worker.

    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. Trin 5

    Gem resultatet

    Det færdige payload indeholder `output_url` og `thumbnail_url`. Download bytes til dit eget objektlager — S3, GCS, Cloudflare R2 — så dit produkt ikke er afhængigt af Phottas CDN til langsigtet rendering.

Fejl

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

Grænser

  • 600 anmodninger i minuttet pr. API-nøgle (Fast vindue; grænsen er den samme på alle planer)
  • En 429 indeholder Retry-After: 30 sekunder
  • Op til 10 MB pr. billede
  • Formater: JPEG, PNG, WebP
  • Samtidige batches pr. plan: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Kun polling — API'et sender ingen webhooks.

Hvorfor requests er det rigtige valg i dag

  • Ingen Photta-specifik afhængighed — requests findes allerede i de fleste Python-projekter
  • Kører overalt, hvor Python kører: Django, FastAPI, Flask, Celery-workers, Lambda, scripts
  • Klient-wrapperen er på omkring tredive linjer — indsæt den i photta.py, og kom videre
  • Spiller sammen med asyncio via httpx, når du har brug for parallel indsendelse

Hvad den ikke gør

  • Ingen officiel Photta Python-pakke endnu — REST med requests er det dokumenterede mønster
  • Polling er det eneste signal om fuldførelse; API'et sender ingen webhooks
  • Kun Bearer-nøgle; der findes intet OAuth client-credentials flow

Spørgsmål udviklere stiller

Findes der et officielt Photta Python SDK?

Ikke endnu. Den understøttede integrationsvej er requests-biblioteket (synkront) eller httpx (asynkront) — begge kræver kun en tynd wrapper, og wrapperen på denne side fungerer til enhver capability.

Hvilke Python-versioner understøttes?

Python 3.9 og nyere. Wrapperen bruger type hints, f-strings og `str | None`-syntaks, hvilket fungerer fint på 3.10+. På 3.9 udskiftes `str | None` med `Optional[str]`. requests understøtter officielt 3.8+, men 3.9+ er det praktiske minimum for moderne Photta-projekter.

Bør jeg bruge requests eller httpx?

requests hvis du foretager en håndfuld sekventielle kald — det er simplere og findes allerede i de fleste kodebaser. httpx hvis du har brug for async concurrency (parallelle indsendelser, bulk backfills) eller HTTP/2. Wrapperen er minimal i begge tilfælde; udskift `requests.request` med `httpx.Client().request`, og resten af koden forbliver identisk.

Kan jeg kalde den fra Django?

Ja. Placer wrapperen i `services/photta.py`, importér den fra et view eller en Celery-task. Kald ikke API'et inde i en synkron request-handler, hvis jobbet tager lang tid — indsend fra viewet, returnér genererings-ID'et, og poll fra en baggrundstask eller en Channels-consumer.

Hvordan poller jeg fra en Celery-worker?

Indsend jobbet fra én task, og planlæg derefter en opfølgende task (via `apply_async(countdown=3)`), der poller én gang og genplanlægger sig selv, indtil jobbet er færdigt, eller en grænse for max-retries nås. Dette holder workers ledige og undgår langvarige tasks, der forstyrrer autoscalers.

Hvordan signalerer API'et fejl?

Ikke-2xx-svar indeholder en JSON-body med et `error`-objekt: `type`, `code`, `message`, samt `param` ved 400-fejl og `retry_after` ved 429-fejl. Wrapperen på denne side kaster en `PhottaError`, der indeholder alle disse, så dine kaldere kan forgrene på statuskode uden selv at skulle parse bodyen.

Prøv API'et på fem minutter

Generér en Photta API-nøgle, indsæt cURL-kodestykket ovenfor, og du har dit første billede på en model, før kaffen er færdigbrygget.

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