Python · API mannequin fantôme

API mannequin fantôme en Python

En une phrase

Installez requests, chargez PHOTTA_API_KEY depuis l'environnement, écrivez un wrapper photta() qui transmet la clé Bearer et lève une exception typée PhottaError sur les réponses non-2xx, puis faites un POST vers /api/v1/ghost-mannequin et effectuez un polling sur /api/v1/ghost-mannequin/{id} toutes les 3 secondes jusqu'à ce que status passe à completed.

  • Délai typique: 1.5–4 min
  • Crédits: 4 crédits en 2K · 5 crédits en 4K
  • Traitement: asynchrone, polling
  • Limites: 600 requêtes/min
  • Authentification: Clé Bearer

Chaque chiffre sur cette page provient de la documentation de l'API Photta · vérifié

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

En un coup d'œil

En un coup d'œil

Endpoint
POST /api/v1/ghost-mannequin
Authentification
Clé API Bearer
Traitement
Asynchrone — interrogez l'endpoint de statut par polling
Délai typique
1.5–4 min
Crédits
4 crédits en 2K · 5 crédits en 4K
Rapports d'aspect
3:4 · 1:1 · 4:3 · 9:16 · 16:9
Limites d'entrée
Jusqu'à 10 Mo par image ; JPEG, PNG, WebP
Idempotent
Non

Comment ça fonctionne

Cinq étapes, zéro dépendance spécifique à Photta — requests couvre l'ensemble des besoins.

  1. Étape 1

    Créer un compte et générer une clé

    Même parcours que pour tous les autres langages : ai.photta.app → Developers → Generate API key. Les clés commencent par `photta_live_` et fonctionnent sur l'ensemble des fonctionnalités de Photta.

  2. Étape 2

    Charger la clé depuis l'environnement

    Définissez `PHOTTA_API_KEY` dans l'environnement et lisez-la via `os.environ`. Dans FastAPI ou Django, chargez-la une seule fois au démarrage dans un module de configuration. N'intégrez pas la clé dans le code source ou dans l'historique Git public.

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

    Écrire un wrapper requests

    Une fonction `photta_request()` de trente lignes gère l'URL de base, l'en-tête Authorization, la sérialisation JSON et la conversion des erreurs. C'est la seule abstraction dont vous avez besoin en attendant l'arrivée du 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 body
  4. Étape 4

    Soumettre et effectuer le polling

    Envoyez un POST à `/api/v1/ghost-mannequin` pour obtenir un ID de génération, puis effectuez un polling sur `/api/v1/ghost-mannequin/{id}` avec un intervalle de 3 secondes. Dans Celery ou RQ, répartissez la boucle de polling sur plusieurs tâches afin qu'un traitement de plusieurs minutes ne bloque pas un 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. Étape 5

    Persister le résultat

    Le payload complété inclut `output_url` et `thumbnail_url`. Téléchargez les octets dans votre propre stockage objet — S3, GCS, Cloudflare R2 — pour que votre produit ne dépende pas du CDN de Photta pour le rendu à long terme.

Erreurs

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

Limites

  • 600 requêtes par minute par clé API (Fenêtre fixe ; la limite est identique sur tous les forfaits)
  • Une 429 renvoie Retry-After: 30 secondes
  • Jusqu'à 10 Mo par image
  • Formats: JPEG, PNG, WebP
  • Lots simultanés par forfait: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • Polling uniquement — l'API n'envoie aucun webhook.

Pourquoi requests est le bon choix aujourd'hui

  • Aucune dépendance spécifique à Photta — requests est déjà présent dans la plupart des projets Python
  • Fonctionne partout où Python s'exécute : Django, FastAPI, Flask, workers Celery, Lambda, scripts
  • Le wrapper client fait une trentaine de lignes — collez-le dans photta.py et passez à la suite
  • S'associe à asyncio via httpx lorsque vous avez besoin de soumissions parallèles

Ce qu'il ne fait pas

  • Aucun package Python Photta officiel pour l'instant — l'utilisation de REST avec requests constitue l'approche documentée
  • Le polling est le seul signal d'achèvement ; l'API n'envoie pas de webhooks
  • Clé Bearer uniquement ; il n'y a pas de flux client-credentials OAuth

Questions fréquentes des développeurs

Existe-t-il un SDK Python officiel pour Photta ?

Pas encore. La méthode d'intégration prise en charge repose sur la bibliothèque requests (synchrone) ou httpx (asynchrone) — toutes deux ne nécessitent qu'un léger wrapper, et celui présent sur cette page fonctionne pour chaque capability.

Quelles versions de Python sont prises en charge ?

Python 3.9 et versions ultérieures. Le wrapper utilise le typage statique, les f-strings et la syntaxe `str | None`, qui fonctionne parfaitement sur 3.10+. Sur 3.9, remplacez `str | None` par `Optional[str]`. requests prend officiellement en charge 3.8+, mais 3.9+ constitue le minimum pratique pour les projets Photta modernes.

Dois-je utiliser requests ou httpx ?

requests si vous effectuez une poignée d'appels séquentiels — c'est plus simple et déjà intégré dans la plupart des bases de code. httpx si vous avez besoin de concurrence asynchrone (soumissions en parallèle, réexécutions en masse) ou de HTTP/2. Le wrapper reste minimal dans les deux cas ; remplacez `requests.request` par `httpx.Client().request` et le reste du code demeure identique.

Puis-je l'appeler depuis Django ?

Oui. Placez le wrapper dans `services/photta.py`, importez-le depuis une vue ou une tâche Celery. N'appelez pas l'API au sein d'un gestionnaire de requêtes synchrone si le traitement est long — effectuez la soumission depuis la vue, renvoyez l'ID de génération, puis effectuez le polling depuis une tâche en arrière-plan ou un consommateur Channels.

Comment effectuer le polling depuis un worker Celery ?

Soumettez la tâche depuis un premier worker, puis planifiez une tâche de suivi (via `apply_async(countdown=3)`) qui effectue un polling unique et se reprogramme jusqu'à ce que le traitement soit completed ou qu'un seuil de tentatives maximales soit atteint. Cela permet de libérer les workers et d'éviter les tâches à longue durée qui perturbent les mécanismes d'autoscaling.

Comment l'API signale-t-elle les erreurs ?

Les réponses autres que 2xx contiennent un corps JSON avec un objet `error` : `type`, `code`, `message`, ainsi que `param` pour les erreurs 400 et `retry_after` pour les erreurs 429. Le wrapper présenté sur cette page lève une exception `PhottaError` contenant l'ensemble de ces champs, afin que vos appelants puissent gérer les embranchements selon le code de statut sans avoir à analyser le corps eux-mêmes.

Pages associées

Chaque chiffre sur cette page provient de la documentation de l'API Photta · vérifié

Testez l'API en cinq minutes

Générez une clé d'API Photta, collez le snippet cURL ci-dessus, et vous obtiendrez votre première photo portée sur modèle avant même que le café ait fini de couler.

  • 1.5–4 min
  • 4 crédits en 2K · 5 crédits en 4K
  • asynchrone, polling
  • 600 requêtes/min
  • Clé Bearer