Python · API de maniquí invisible
API de maniquí invisible en Python
En una frase
Instala requests, carga PHOTTA_API_KEY desde las variables de entorno, escribe un wrapper photta() que envíe la clave Bearer y lance un PhottaError tipado en respuestas no 2xx, luego haz POST a /api/v1/ghost-mannequin y polling a /api/v1/ghost-mannequin/{id} cada 3 segundos hasta que status sea completed.
- Tiempo típico: 1.5–4 min
- Credits: 4 credits a 2K · 5 credits a 4K
- Procesamiento: asíncrono, polling
- Límites: 600 requests/min
- Autenticación: Bearer key
Cada cifra de esta página proviene de la documentación de la API de Photta · verificado
RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/ghost-mannequin \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"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"
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')
# $ID is data.id from the POST response. Poll every 3 seconds until status is "completed" or "failed".
for i in $(seq 1 120); do
RESULT=$(curl -s "https://api.photta.app/api/v1/ghost-mannequin/$ID" -H "Authorization: Bearer $PHOTTA_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.data.status')
[ "$STATUS" = "completed" ] && break
[ "$STATUS" = "failed" ] && echo "generation failed" && exit 1
sleep 3
done
echo "$RESULT" | jq -r '.data.output_url'const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"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"
}),
});
const { data } = await res.json(); // data.id, data.status
async function waitFor(id) {
for (let attempt = 0; attempt < 120; attempt++) {
const res = await fetch(`https://api.photta.app/api/v1/ghost-mannequin/${id}`, { headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}` } });
const { data } = await res.json();
if (data.status === "completed") return data.output_url;
if (data.status === "failed") throw new Error(data.error_message ?? "generation failed");
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error("timed out after 6 minutes");
}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")De un vistazo
De un vistazo
- Endpoint
- POST /api/v1/ghost-mannequin
- Autenticación
- Bearer API key
- Procesamiento
- Asíncrono — realiza polling al endpoint de estado
- Tiempo típico
- 1.5–4 min
- Credits
- 4 credits a 2K · 5 credits a 4K
- Relaciones de aspecto
- 3:4 · 1:1 · 4:3 · 9:16 · 16:9
- Límites de entrada
- Hasta 10 MB por imagen; JPEG, PNG, WebP
- Idempotente
- No
Cómo funciona
Cinco pasos, cero dependencias específicas de Photta — requests cubre todo.
Paso 1
Regístrate y genera una clave
El mismo proceso que en cualquier otro lenguaje: ai.photta.app → Developers → Generate API key. Las claves empiezan por `photta_live_` y funcionan en todas las capabilities de Photta.
Paso 2
Carga la clave desde el entorno
Configura `PHOTTA_API_KEY` en el entorno y léela mediante `os.environ`. En FastAPI o Django, cárgala una vez al arrancar en un módulo de configuración. No insertes la clave en el código fuente ni en el historial público de Git.
python3 -m pip install requests export PHOTTA_API_KEY="photta_live_xxxxx"Paso 3
Escribe un wrapper con requests
Una función `photta_request()` de treinta líneas gestiona la URL base, el encabezado Authorization, la serialización JSON y la traducción de errores. Es la única abstracción que necesitas hasta que llegue el SDK de 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 bodyPaso 4
Enviar y hacer polling
Haz un POST a `/api/v1/ghost-mannequin` para obtener un ID de generación, luego haz polling a `/api/v1/ghost-mannequin/{id}` en un intervalo de 3 segundos. En Celery o RQ, divide el bucle de polling entre tareas para que un trabajo de varios minutos no bloquee a 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")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 dependa de la CDN de Photta para el renderizado a largo plazo.
Errores
- 400
invalid_request_error - The request is malformed or contains invalid parameters.
- 401
authentication_error - The API key is missing, invalid, or expired.
- 402
insufficient_credits_error - Your account does not have enough credits.
- 404
not_found_error - The requested resource does not exist.
- 409
conflict_error - The request conflicts with current state — e.g. your concurrent-batch cap is reached.
- 429
rate_limit_error - Too many requests. Slow down and retry.Retry-After: 30
- 500
api_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:
raiseLímites
- 600 solicitudes por minuto por API key (Ventana fija; el límite es el mismo en todos los planes)
- Un 429 incluye Retry-After: 30 segundos
- Hasta 10 MB por imagen
- Formatos: JPEG, PNG, WebP
- Lotes simultáneos por plan: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
- Solo polling — la API no envía webhooks.
Por qué requests es la opción correcta hoy
- Sin dependencias específicas de Photta: requests ya está en la mayoría de los proyectos de Python
- Funciona donde sea que se ejecute Python: Django, FastAPI, Flask, workers de Celery, Lambda, scripts
- El wrapper del cliente tiene unas treinta líneas: pégalo en photta.py y continúa
- Se combina con asyncio mediante httpx cuando necesitas envíos paralelos
Lo que no hace
- Todavía no hay un paquete oficial de Python para Photta: REST con requests es el patrón documentado
- El polling es la única señal de finalización; la API no envía webhooks
- Solo clave Bearer; no hay flujo de credenciales de cliente OAuth
Preguntas frecuentes de desarrolladores
¿Existe un SDK oficial de Python para Photta?
Aún no. La vía de integración admitida es la biblioteca requests (síncrona) o httpx (asíncrona); ambas están a solo un delgado wrapper de distancia, y el wrapper de esta página funciona para cada capacidad.
¿Qué versiones de Python son compatibles?
Python 3.9 y posteriores. El wrapper usa type hints, f-strings y la sintaxis `str | None`, lo cual funciona bien en 3.10+. En 3.9 cambia `str | None` por `Optional[str]`. requests admite oficialmente 3.8+, pero 3.9+ es el mínimo práctico para proyectos modernos de Photta.
¿Debería usar requests o httpx?
requests si estás realizando un puñado de llamadas secuenciales: es más simple y ya se encuentra en la mayoría de las bases de código. httpx si necesitas concurrencia asíncrona (envíos en paralelo, backfills por lotes) o HTTP/2. El wrapper es mínimo en ambos casos; reemplaza `requests.request` por `httpx.Client().request` y el resto del código se mantendrá idéntico.
¿Puedo llamarlo desde Django?
Sí. Coloca el wrapper en `services/photta.py`, impórtalo desde una vista o una tarea de Celery. No llames a la API dentro de un manejador de solicitudes síncrono si el trabajo toma tiempo: haz el submit desde la vista, devuelve el ID de generación y haz polling desde una tarea en segundo plano o un consumidor de Channels.
¿Cómo hago polling desde un worker de Celery?
Envía el trabajo desde una tarea y luego programa una tarea de seguimiento (mediante `apply_async(countdown=3)`) que haga polling una vez y se vuelva a programar a sí misma hasta que el trabajo se complete o se alcance un límite de reintentos máximos. Esto mantiene libres a los workers y evita tareas de larga duración que alteren los autoscalers.
¿Cómo señala los errores la API?
Las respuestas que no son 2xx incluyen un cuerpo JSON con un objeto `error`: `type`, `code`, `message`, además de `param` en respuestas 400 y `retry_after` en respuestas 429. El wrapper de esta página lanza un `PhottaError` que incluye todos estos datos para que tus llamadas puedan bifurcar por código de estado sin tener que parsear el cuerpo directamente.
Páginas relacionadas
Node.js
API de maniquí invisible en Node.js
Llama a aPI de maniquí invisible de Photta desde un backend de Node.js con fetch nativo. Sin SDKs: guarda tu key, envía el trabajo y haz polling para obtener el resultado.
LeercURL
API de maniquí invisible con cURL
Llama a aPI de maniquí invisible de Photta directamente desde la terminal con cURL. Envía, haz polling, descarga: cada fragmento de código se combina con jq para pipelines automatizados.
LeerCapacidades
API de maniquí invisible para fotos de producto con efecto maniquí invisible
Endpoint de maniquí invisible con IA. Elimina el maniquí de una foto de la prenda y preserva el detalle interior. 3D o flat-lay, procesamiento por lotes, 4 credits a 2K.
LeerConstruir
Automatiza la extracción de ghost mannequin para tu catálogo
Receta de automatización nocturna de catálogo: extrae las actualizaciones de productos de ayer, envíalas por lotes a la API de ghost-mannequin de Photta, haz polling del lote principal y persiste los datos en tu base de datos.
LeerGuía rápida
Tu primera imagen de Photta en menos de cinco minutos.
Regístrate, genera una API key, ejecuta tu primera llamada cURL, haz polling hasta que se complete y guarda el resultado. Cinco pasos, documentados de principio a fin.
LeerReferencia
Precios de la API de Photta
Cuánto cuesta en credits cada endpoint de Photta API a 2K y 4K, cómo funcionan los cobros y reembolsos, y qué endpoints son gratuitos. Sin precio monetario por imagen.
Leer
Cada cifra de esta página proviene de la documentación de la API de Photta · verificado
Prueba la API en cinco minutos
Genera una API key de Photta, pega el snippet de cURL de arriba y tendrás tu primera imagen con modelo antes de que termine de prepararse el café.
- 1.5–4 min
- 4 credits a 2K · 5 credits a 4K
- asíncrono, polling
- 600 requests/min
- Bearer key