Build · Virtual Try-On
Crie um recurso de virtual try-on para sua aplicação
Em uma frase
Receba a foto do produto no seu backend, faça um POST para /api/v1/tryon/apparel com um ID de manequim, faça o polling do ID de geração retornado a partir de um background worker (nunca na thread da requisição HTTP) até que o status mude para completed, depois persista a output_url no seu próprio object storage e renderize-a na interface.
- Credits: 5 credits em 2K · 6 credits em 4K
- Tempo típico: 1.5–4 min
- Processamento: assíncrono, polling
Todos os números nesta página vêm de a documentação da API da Photta · verificado
Uma receita pronta para produção: o cliente faz upload da foto do produto, seu backend enfileira um job de try-on na Photta, um worker faz o polling até concluir, e o frontend exibe o resultado no modelo. Sem requisições bloqueantes, sem vazamento de chaves de API, sem SDK fake.
RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}),
});
const { data } = await res.json(); // data.id, data.statusimport os, requests
res = requests.post(
"https://api.photta.app/api/v1/tryon/apparel",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": True,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
},
)
data = res.json()["data"] # data["id"], data["status"]Como funciona
Do upload à imagem no modelo
Seis etapas concretas. Espere de dez a quinze minutos de trabalho de integração na primeira vez.
Passo 1
Desenhe o fluxo de dados
Dispositivo do cliente → seu backend (upload) → Photta API (submissão) → Photta API (polling) → seu banco de dados (espelho de status) → dispositivo do cliente (renderização). Desenhe isso no papel antes de escrever a primeira linha — a fronteira entre o seu backend e o da Photta é a única coisa que realmente importa.
Passo 2
Gere e armazene uma chave de API
Chaves de produção começam com photta_live_. Coloque-a em uma variável de ambiente. Nunca a envie para o navegador. Uma única chave cobre todas as capacidades da Photta, portanto você não precisa de chaves separadas para try-on, jewelry ou ghost mannequin.
Passo 3
Configure o endpoint de upload
Receba primeiro a foto do produto enviada pelo cliente no seu object storage. Enviar uma URL pública para a Photta é mais simples que base64 e garante uma trilha de auditoria para cada requisição.
Passo 4
Submeta o job a partir do servidor
Faça um POST para /api/v1/tryon/apparel com a URL do produto, mannequin_id, resolution e aspect_ratio. A API retorna 202 Accepted + um ID de geração. Armazene esse ID no seu banco de dados para que o cliente consulte seu próprio endpoint, e não o da Photta.
Passo 5
Faça o polling a partir de um background worker
Não faça o polling dentro da requisição HTTP — o job leva de 1.5 a 4 minutos, o que excede os timeouts da maioria dos ambientes serverless. Use Trigger.dev, Inngest, BullMQ, Vercel Cron ou sua própria fila para reagendar uma consulta a cada 3 segundos até que o job termine.
Passo 6
Renderize o resultado
Quando o status mudar para completed, copie data.output_url para o seu banco de dados e emita um evento em tempo real (websocket, SSE ou long-poll) para o dispositivo do cliente. A interface substitui o skeleton de carregamento pela imagem finalizada. Pronto.
Três exemplos de código, de ponta a ponta
Handler de upload, disparador de jobs, poller no worker — cada componente necessário para colocar o recurso em produção.
// POST /app/try-on → your backend upload handler
import { put } from "@vercel/blob";
export async function uploadProduct(file: File) {
const { url } = await put(`products/${crypto.randomUUID()}.jpg`, file, {
access: "public",
});
return url;
}const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"product_type": "top",
"product_images": [
"https://cdn.yourstore.com/products/shirt-front.jpg"
],
"product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
"product_category": "t_shirt",
"mannequin_id": "mnk_f3a9b1",
"pose_id": "pose_c2d4e5",
"background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
"lock_background": true,
"resolution": "2K",
"aspect_ratio": "3:4",
"body_size": "M",
"expression": "neutral",
"user_instruction": "Keep the collar pattern crisp and centered."
}),
});
const { data } = await res.json(); // data.id, data.status// Trigger.dev / Inngest / BullMQ task
const BASE = "https://api.photta.app/api/v1";
export const pollTryOnTask = task({
id: "poll-try-on",
run: async ({ generationId, attempt = 0 }) => {
const res = await fetch(`${BASE}/tryon/apparel/${generationId}`, {
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);
if (attempt >= 120) throw new Error("try-on timed out");
// Re-schedule this same task after 3 seconds.
return ctx.retry.after(3000, { generationId, attempt: attempt + 1 });
},
});Dúvidas frequentes de desenvolvedores
Dúvidas antes de colocar em produção
Posso fazer isso sem um backend?
Não. Sua chave de API da Photta deve permanecer no lado do servidor. Mesmo um route handler simples do Next.js ou um Cloudflare Worker já conta como um backend para essa finalidade — a chave só precisa ficar em um lugar onde um user-agent não consiga lê-la.
Como eu evito requisições HTTP travadas?
Nunca faça polling dentro de um manipulador de requisições. Envie o job de forma síncrona, retorne o ID da geração para o cliente e faça o polling a partir de um background worker. O cliente faz polling no SEU endpoint de status, não no da Photta — assim, gerenciar rate limits vira problema seu, não de cada usuário.
O que acontece se um job falhar no meio do processo?
A Photta estorna os credits automaticamente em caso de falha, e a resposta traz data.error_code + data.error_message. Exiba uma mensagem amigável para o usuário e ofereça um botão de repetição que dispara um novo job.
Posso exibir o progresso real?
A Photta não emite progresso intermediário — o status é processing, completed ou failed. O que funciona bem é uma barra de progresso temporizada calibrada para a janela de 1.5–4 minutos, ou um skeleton loader simples. Não minta sobre porcentagens.
A URL de resultado é permanente?
A URL da CDN é estável, mas seu produto não deve depender dela para renderização a longo prazo. Faça o download dos bytes uma vez e armazene-os no seu próprio bucket S3/GCS/R2 — assim, sua PDP continua funcionando mesmo se a CDN da Photta mudar.
Páginas relacionadas
Referência
Recursos
API de try-on virtual para roupas
API REST que veste roupas em manequins de IA. Assíncrona, geração em 1.5–4 minutos, 5 credits em 2K, 6 em 4K. Exemplos em cURL, Node.js e Python.
LerInício rápido
Primeira imagem no Photta em menos de cinco minutos.
Cadastre-se, gere uma chave de API, execute sua primeira chamada cURL, faça polling até a conclusão, persista o resultado. Cinco etapas, documentadas de ponta a ponta.
LerLinguagens
Node.js walkthrough
LerLinguagens
Python walkthrough
Ler
Todos os números nesta página vêm de a documentação da API da Photta · verificado
Entregue virtual try-on em uma tarde
Cada exemplo de código nesta página corresponde à documentação oficial da Photta. Obtenha uma chave de API e você terá um protótipo funcional antes de o café terminar de passar.