Python · API de Try-On Virtual

API de Try-On Virtual en Python

No hace falta un pip install photta — la documentación oficial de Photta recomienda la librería requests. Un wrapper de treinta líneas se integra en Django, FastAPI, workers de Celery y handlers de Lambda sin más ceremonia.

En una frase

Instala `requests`, carga `PHOTTA_API_KEY` desde env, escribe un wrapper `photta_request()` que envíe `Authorization: Bearer photta_live_xxx` y lance un `PhottaError` tipado en respuestas no-2xx, luego haz un POST a `/tryon/apparel` y sondea `/tryon/apparel/:id` cada 3 segundos hasta que `data.status == 'completed'` — típicamente en 1.5 a 4 minutos.

Actualizado · 2026-04-19

Tu primera solicitud

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)

Qué esperar

Typical completion

1.5–4min

2K / 4K credits

5 / 7

Jewelry types

4

Close-up mannequins

built-in

Cómo funciona

API de Try-On Virtual en Python

Cinco pasos, cero dependencias específicas de Photta — requests cubre todo.

  1. 01

    Paso 1

    Regístrate y genera una clave

    La misma ruta que para cualquier otro lenguaje: ai.photta.app → Desarrolladores → Generar API key. Las claves comienzan con `photta_live_` y funcionan en todas las capacidades de Photta.

  2. 02

    Paso 2

    Carga la clave desde env

    Configura `PHOTTA_API_KEY` en el entorno y léela mediante `os.environ`. En FastAPI o Django, cárgala una vez al inicio en un módulo de configuración. No incrustes la clave en el código fuente ni en el historial público de Git.

  3. 03

    Paso 3

    Escribe un wrapper de requests

    Una función `photta_request()` de treinta líneas gestiona la URL base, el header Authorization, la serialización JSON y la traducción de errores. Esa es la única abstracción que necesitas hasta que llegue el SDK de Python.

  4. 04

    Paso 4

    Enviar y sondear

    POST a `/tryon/apparel` para obtener un ID de generación, luego sondea `/tryon/apparel/:id` en un intervalo de 3 segundos. En Celery o RQ, rompe el bucle de sondeo entre tareas para que un trabajo de 4 minutos no bloquee a un worker.

  5. 05

    Paso 5

    Persistir el resultado

    El payload completado incluye `output_url` y `thumbnail_url`. Descarga los bytes en tu propio almacenamiento de objetos — S3, GCS, Cloudflare R2 — para que tu producto no esté atado al CDN de Photta para el renderizado a largo plazo.

Código, de punta a punta

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

Por qué esta estructura

Por qué requests es la elección correcta hoy

  • 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

Qué no hace

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

Preguntas de otros desarrolladores

Questions other developers ask

¿Existe un SDK oficial de Photta para Python?+

Aún no. El roadmap de Photta prioriza el SDK de Python una vez que haya diez clientes de pago de la API activos. Hasta entonces, la ruta de integración soportada es la librería requests (síncrona) o httpx (asíncrona) — ambas están documentadas en la documentación oficial y funcionan con el wrapper de treinta líneas de esta página.

¿Qué versiones de Python están soportadas?+

Python 3.9 y posteriores. El wrapper usa sugerencias de tipo (type hints), f-strings y sintaxis `str | None`, que funciona bien en 3.10+. En 3.9 cambia `str | None` por `Optional[str]`. requests soporta oficialmente 3.8+, pero 3.9+ es el mínimo práctico para proyectos modernos de Photta.

¿Debo usar requests o httpx?+

requests si vas a realizar unas pocas llamadas secuenciales — es más simple y ya está en la mayoría de los proyectos. httpx si necesitas concurrencia asíncrona (envíos paralelos, cargas masivas) o HTTP/2. El wrapper es pequeño de cualquier forma; cambia `requests.request` por `httpx.Client().request` y el resto del código se mantiene idéntico.

¿Puedo llamarlo desde Django?+

Sí. Pon el wrapper en `services/photta.py`, impórtalo desde una vista o una tarea de Celery. No llames a la API dentro de un handler de solicitud síncrono si el trabajo es largo — envíalo desde la vista, devuelve el ID de generación y sondea desde una tarea en segundo plano o un consumidor de Channels.

¿Cómo realizo el polling desde un worker de Celery?+

Envía el trabajo desde una tarea y luego programa una tarea de seguimiento (vía `apply_async(countdown=3)`) que sondee una vez y se reprograme a sí misma hasta que el trabajo se complete o alcance un límite de reintentos. Esto mantiene a los workers libres y evita tareas de larga duración que afecten a los autoescaladores.

¿Cómo señala los errores la API?+

Las respuestas que no son 2xx llevan un cuerpo JSON con un objeto `error`: `type`, `code`, `message`, además de `param` en los 400 y `retry_after` en los 429. El wrapper de esta página lanza un `PhottaError` que contiene todo esto para que tus llamadores puedan decidir según el status code sin analizar el cuerpo ellos mismos.

Python · API de Try-On Virtual

Crea una cuenta y obtén una API key

Instala `requests`, carga `PHOTTA_API_KEY` desde env, escribe un wrapper `photta_request()` que envíe `Authorization: Bearer photta_live_xxx` y lance un `PhottaError` tipado en respuestas no-2xx, luego haz un POST a `/tryon/apparel` y sondea `/tryon/apparel/:id` cada 3 segundos hasta que `data.status == 'completed'` — típicamente en 1.5 a 4 minutos.

API de Try-On Virtual para Python — Photta | Photta