Node.js · API de try-on de joyas
API de try-on de joyas en Node.js
En una frase
Configura PHOTTA_API_KEY en env, escribe un pequeño helper con fetch para https://api.photta.app/api/v1 con un token Bearer, haz POST a /api/v1/tryon/jewelry y luego haz polling a /api/v1/tryon/jewelry/{id} cada 3 segundos hasta que el estado sea completed.
- Tiempo típico: 1.5–4 min
- Credits: 5 credits a 2K · 6 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/tryon/jewelry \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg",
"jewelry_type": "necklace",
"mannequin_id": "mnk_j9k1l2",
"background": "soft window light on dark velvet",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "Make the pendant 10% smaller."
}')
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/tryon/jewelry/$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/tryon/jewelry", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg",
"jewelry_type": "necklace",
"mannequin_id": "mnk_j9k1l2",
"background": "soft window light on dark velvet",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "Make the pendant 10% smaller."
}),
});
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/tryon/jewelry/${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/tryon/jewelry",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg",
"jewelry_type": "necklace",
"mannequin_id": "mnk_j9k1l2",
"background": "soft window light on dark velvet",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "Make the pendant 10% smaller."
},
)
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/tryon/jewelry/{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/tryon/jewelry
- Autenticación
- Bearer API key
- Procesamiento
- Asíncrono — realiza polling al endpoint de estado
- Tiempo típico
- 1.5–4 min
- Credits
- 5 credits a 2K · 6 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, unos cinco minutos desde el registro hasta la primera imagen.
Paso 1
Regístrate y genera una key
Crea una cuenta en ai.photta.app. Abre la sección Developers del dashboard, haz clic en Generate API key y copia la key en vivo. Empieza por `photta_live_` seguido de 32 caracteres hexadecimales.
Paso 2
Guarda la key en env, no en el código fuente
Añade `PHOTTA_API_KEY=...` a `.env` (o al gestor de secretos de tu plataforma) y cárgala mediante `process.env`. Nunca hagas commit de la key; nunca la importes en un archivo marcado con `'use client'`, ya que el empaquetador la expondrá en el navegador.
node --version # 18 or later ships fetch echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .envPaso 3
Escribe un pequeño helper con fetch
Un wrapper de 20 líneas alrededor de `fetch()` gestiona la URL base, la cabecera Authorization, el cuerpo JSON y la normalización de errores. Esta es la única abstracción que necesitas hasta que se publique un SDK oficial.
// photta.js — one helper for every endpoint const BASE = "https://api.photta.app/api/v1"; export async function photta(path, init = {}) { const res = await fetch(BASE + path, { ...init, headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json", ...(init.headers ?? {}) } }); const body = await res.json(); if (!res.ok) throw Object.assign(new Error(body.error?.message ?? res.statusText), { status: res.status, retryAfter: res.headers.get("Retry-After"), body }); return body; }Paso 4
Envía un try-on y haz polling
Haz un POST a `/api/v1/tryon/jewelry` con el cuerpo de ejemplo documentado — el código siguiente incluye todos los campos. La API devuelve un ID de generación de inmediato. Haz polling a `/api/v1/tryon/jewelry/{id}` cada 3 segundos hasta que `status === 'completed'`.
const res = await fetch("https://api.photta.app/api/v1/tryon/jewelry", { method: "POST", headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg", "jewelry_type": "necklace", "mannequin_id": "mnk_j9k1l2", "background": "soft window light on dark velvet", "resolution": "2K", "aspect_ratio": "3:4", "user_instruction": "Make the pendant 10% smaller." }), }); 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/tryon/jewelry/${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"); }Paso 5
Persiste el resultado
El payload completado incluye `output_url` y `thumbnail_url`. Haz fetch de los bytes una vez y almacénalos en tu propio almacenamiento de objetos — las URLs son estables, pero tu producto no debería depender de la CDN de Photta para el renderizado.
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 {
await photta("/tryon/jewelry", { method: "POST", body: JSON.stringify({
"jewelry_image": "https://cdn.yourstore.com/products/gold-necklace.jpg",
"jewelry_type": "necklace",
"mannequin_id": "mnk_j9k1l2",
"background": "soft window light on dark velvet",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "Make the pendant 10% smaller."
}) });
} catch (err) {
if (err.status === 402) console.error("insufficient_credits_error: top up before retrying");
else if (err.status === 429) await new Promise((r) => setTimeout(r, Number(err.retryAfter ?? 30) * 1000));
else throw err;
}Lí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é un helper supera a una biblioteca de cliente — por ahora
- Node 18+ incluye fetch nativo — sin dependencias en tiempo de ejecución
- El mismo helper funciona dentro de route handlers de Next.js, server actions y cualquier worker
- Mantén la clave de API en variables de entorno; nunca importes el helper desde un módulo 'use client' o el empaquetador la filtrará
- Funciona con cualquier cola o cron: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues
Lo que no hace
- Todavía no hay un paquete oficial @photta/node — REST es la única vía actualmente
- El polling es la única señal de finalización; la API no envía webhooks
- Solo clave Bearer; no hay flujo OAuth client-credentials
Preguntas frecuentes de desarrolladores
¿Existe un SDK oficial de Photta para Node.js?
Todavía no. La vía documentada es REST directo mediante el fetch nativo de Node — el helper de esta página cubre toda la superficie de integración y funciona igual para cada capability.
¿Qué versiones de Node.js son compatibles?
Cualquiera compatible con `fetch` nativo — lo que implica Node 18 y versiones posteriores. En Node 16 puedes usar un polyfill con `node-fetch` o actualizar. El resto del código es ECMAScript 2020 estándar (async/await, template literals, imports dinámicos), por lo que no hay otros requisitos de entorno.
¿Cómo me autentico desde Node?
Envía `Authorization: Bearer photta_live_xxx` en cada petición. Guarda la clave en una variable de entorno y cárgala mediante `process.env`; nunca la importes desde un archivo que se ejecute en el navegador.
¿Cómo gestiono la ventana de generación?
El endpoint de generación es completamente asíncrono. El POST devuelve un ID de generación de inmediato con `status: 'processing'`. Haz polling con `GET /api/v1/tryon/jewelry/{id}` cada 3–5 segundos hasta que el `status` cambie a `completed` o `failed`, y limita los intentos para que un trabajo atascado no bloquee una petición.
¿Puedo llamar a la API dentro de Next.js?
Sí — desde un route handler (`app/**/route.ts`), una server action (`'use server'`) o middleware. Mantén la clave de API en el servidor; nunca importes el helper desde un archivo `'use client'`. Para tareas de larga duración que superen el tiempo de espera de función de Vercel, delega el polling a una cola (Inngest, Trigger.dev, BullMQ) y devuelve el ID de generación al navegador para que haga polling a tu propio status endpoint.
¿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` y un ID de petición para soporte. Casos habituales: 400 invalid_request_error con `param` apuntando al campo incorrecto; 402 insufficient_credits con los totales de `required` y `available`; 429 rate_limit_exceeded con `retry_after` en segundos y una cabecera Retry-After coincidente. Es seguro reintentar los errores 5xx con retroceso exponencial.
Páginas relacionadas
Python
API de try-on de joyas en Python
Llama a aPI de try-on de joyas de Photta en Python con la biblioteca requests. Wrapper de treinta líneas, compatible con async mediante httpx, funciona en Django, FastAPI y Celery.
LeercURL
API de try-on de joyas con cURL
Llama a aPI de try-on de joyas 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 try-on de joyas para collares, anillos, pulseras y pendientes
Coloca collares, anillos, pulseras y pendientes en modelos de IA mediante REST. 5 credits en 2K, maniquíes en primer plano integrados y renderizado optimizado para reflejos según la documentación de Photta.
LeerConstruir
Crea un servicio de fotografía de producto con IA
Un manual para fundadores sobre cómo revender la API de virtual try-on de Photta como un SaaS de marca blanca: claves por tenant, fanout por lotes, facturación por credit y la realidad del SLA.
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
- 5 credits a 2K · 6 credits a 4K
- asíncrono, polling
- 600 requests/min
- Bearer key