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

Como funciona

Do upload à imagem no modelo

Seis etapas concretas. Espere de dez a quinze minutos de trabalho de integração na primeira vez.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

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.