Node.js · API de Provador Virtual

API de Provador Virtual em Node.js

Ainda não há um pacote @photta/node — e você não precisa de um. O Node 18+ traz o `fetch` nativamente, e um helper de 20 linhas leva você à sua primeira imagem com modelo em cerca de cinco minutos.

Em uma frase

Defina `PHOTTA_API_KEY` no ambiente, escreva um pequeno helper `phottaFetch()` que chama `https://ai.photta.app/api/v1` com `Authorization: Bearer photta_live_xxx`, envie um POST para `/tryon/apparel` com a URL da imagem do produto, ID do manequim e ID da pose, e então faça poll em `/tryon/apparel/:id` a cada 3 segundos até que `status === 'completed'` — tipicamente dentro de 1.5–4 minutos.

Atualizado · 2026-04-19

Sua primeira requisição

Node.jsPythoncURLcURL
import { phottaFetch } from "./photta.js";

// 1. Submit the job — returns a generation ID immediately.
const created = await phottaFetch("/tryon/apparel", {
  method: "POST",
  body: JSON.stringify({
    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",
  }),
});
const generationId = created.data.id;

// 2. Poll every 3 seconds until processing completes. Typical
// completion is 1.5–4 minutes; put an upper bound so a stuck
// job can't hang your request forever.
const pollInterval = 3000;
const maxAttempts = 120;     // 120 × 3s = 6 minutes
let result;

for (let i = 0; i < maxAttempts; i++) {
  result = await phottaFetch(`/tryon/apparel/${generationId}`);
  if (result.data.status === "completed") break;
  if (result.data.status === "failed") {
    throw new Error(result.data.error_message);
  }
  await new Promise((r) => setTimeout(r, pollInterval));
}

console.log("Result:", result.data.output_url);

O que esperar

Typical completion

1.5–4min

2K / 4K credits

5 / 7

Aspect ratios

5

Product types

6

Como funciona

API de Provador Virtual em Node.js

Cinco passos, cerca de cinco minutos do cadastro à primeira imagem.

  1. 01

    Passo 1

    Cadastre-se e gere uma chave

    Crie uma conta em ai.photta.app. Abra a seção de Desenvolvedores no dashboard, clique em Gerar chave de API e copie a chave live. Ela começa com `photta_live_` seguido por 32 caracteres hexadecimais.

  2. 02

    Passo 2

    Armazene a chave no env, não no código

    Adicione `PHOTTA_API_KEY=...` ao `.env` (ou ao cofre de segredos da sua plataforma) e carregue-o via `process.env`. Nunca envie a chave para o repositório; nunca a importe em um arquivo marcado com `'use client'` — o bundler a levará para o navegador.

  3. 03

    Passo 3

    Escreva um pequeno helper de fetch

    Um wrapper de 20 linhas em torno do `fetch()` gerencia a URL base, o header Authorization, o corpo JSON e a normalização de erros. Esta é a única abstração necessária até que um SDK oficial seja lançado.

  4. 04

    Passo 4

    Envie um provador virtual e faça poll

    Envie um POST para `/tryon/apparel` com `product_type`, `product_images`, `mannequin_id`, `pose_id`, `resolution` e `aspect_ratio`. A API retorna um ID de geração imediatamente. Faça poll em `/tryon/apparel/:id` a cada 3 segundos até que `status === 'completed'`.

  5. 05

    Passo 5

    Persista o resultado

    O payload final inclui `output_url` e `thumbnail_url`. Busque os bytes uma vez e armazene-os em seu próprio storage de objetos — as URLs são estáveis, mas seu produto não deve depender do CDN da Photta para renderização.

Código, ponta a ponta

Copy, paste, done.

Four snippets — install prerequisites, wrap the REST call, submit + poll, then handle the errors that actually happen in production.

01No SDK required — use native fetch in Node 18+
bash
# Node 18+ ships fetch natively. No install step needed.
node --version   # ensure v18 or later

# Optional: keep your API key out of source control
echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env
02Wrap the REST call in a tiny client helper
javascript
// photta.js — a 20-line wrapper you can reuse across your app.
const PHOTTA_BASE_URL = "https://ai.photta.app/api/v1";

export async function phottaFetch(path, init = {}) {
  const res = await fetch(`${PHOTTA_BASE_URL}${path}`, {
    ...init,
    headers: {
      "Authorization": `Bearer ${process.env.PHOTTA_API_KEY}`,
      "Content-Type": "application/json",
      ...init.headers,
    },
  });
  const body = await res.json();
  if (!res.ok) {
    const err = new Error(body?.error?.message ?? res.statusText);
    err.status = res.status;
    err.code = body?.error?.code;
    throw err;
  }
  return body;
}
03Submit a try-on job and poll until it lands
javascript
import { phottaFetch } from "./photta.js";

// 1. Submit the job — returns a generation ID immediately.
const created = await phottaFetch("/tryon/apparel", {
  method: "POST",
  body: JSON.stringify({
    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",
  }),
});
const generationId = created.data.id;

// 2. Poll every 3 seconds until processing completes. Typical
// completion is 1.5–4 minutes; put an upper bound so a stuck
// job can't hang your request forever.
const pollInterval = 3000;
const maxAttempts = 120;     // 120 × 3s = 6 minutes
let result;

for (let i = 0; i < maxAttempts; i++) {
  result = await phottaFetch(`/tryon/apparel/${generationId}`);
  if (result.data.status === "completed") break;
  if (result.data.status === "failed") {
    throw new Error(result.data.error_message);
  }
  await new Promise((r) => setTimeout(r, pollInterval));
}

console.log("Result:", result.data.output_url);
04Handle 402 credit exhaustion and 429 rate limits
javascript
try {
  await phottaFetch("/tryon/apparel", {
    method: "POST",
    body: JSON.stringify({ /* … */ }),
  });
} catch (err) {
  if (err.status === 402) {
    // Out of credits — surface a top-up CTA to the user.
    // err.code === "insufficient_credits"
  } else if (err.status === 429) {
    // Rate-limited. Honour the Retry-After header.
    const retryAfter = err.retryAfter ?? 30;
    await new Promise((r) => setTimeout(r, retryAfter * 1000));
    // Then retry…
  } else if (err.status >= 500) {
    // Server-side issue — backoff + retry.
  }
  throw err;
}

Por que esse formato

Por que um helper é melhor que uma biblioteca cliente — por enquanto

  • Node 18+ ships native fetch — no runtime deps required
  • Same helper works inside Next.js route handlers, API routes, server actions and edge functions
  • Keep API keys in env; never import the helper from a 'use client' module or the bundler will leak them
  • Works with any queue/cron: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues

O que não faz

Honest caveats

  • No official @photta/node SDK yet — REST is the only path today
  • No built-in webhook delivery; polling is the documented pattern (3–5s interval)
  • Bearer token lives in env; the API doesn't support OAuth client credentials yet

Perguntas que outros desenvolvedores fazem

Questions other developers ask

Existe um SDK oficial da Photta para Node.js?+

Ainda não. A documentação da Photta planeja SDKs explicitamente após atingir metas de adoção: Python quando houver dez usuários da API, Node.js aos vinte. Até lá, o caminho documentado é REST puro via cURL, fetch nativo do Node ou a biblioteca requests do Python. O helper de 20 linhas nesta página equivale a um cliente para os endpoints que você mais usará.

Quais versões do Node.js são suportadas?+

Qualquer uma que suporte `fetch` nativo — o que significa Node 18 ou posterior. No Node 16, você deve usar um polyfill como `node-fetch` ou atualizar. O restante do código é ECMAScript 2020 puro (async/await, template literals, dynamic imports), sem outros requisitos de runtime.

Como autentico via Node?+

Envie `Authorization: Bearer photta_live_xxx` em cada requisição. A chave começa com `photta_live_` em produção e `photta_test_` quando o modo sandbox for lançado. Coloque-a em uma variável de ambiente e carregue-a via `process.env.PHOTTA_API_KEY`. A API ainda não suporta credenciais de cliente OAuth ou autenticação baseada em sessão.

Como gerencio a janela de geração de 1.5–4 minutos?+

O endpoint de provador virtual é totalmente assíncrono. O POST retorna um ID de geração imediatamente com `status: 'processing'`. Faça o poll em `GET /tryon/apparel/:id` a cada 3–5 segundos até que o `status` mude para `completed` ou `failed`. Defina um limite máximo de tentativas para que um job travado não prenda sua requisição para sempre — 120 tentativas a cada 3 segundos cobrem a janela documentada com margem.

Posso chamar a API dentro do Next.js?+

Sim — a partir de um route handler (`app/**/route.ts`), uma server action (`'use server'`) ou middleware. Mantenha a chave da API no servidor; nunca importe o helper de um arquivo `'use client'`. Para jobs de longa duração que excedam o tempo limite de função da Vercel, delegue o polling para uma fila (Inngest, Trigger.dev, BullMQ) e retorne o ID de geração ao navegador para que ele possa consultar um webhook ou seu próprio endpoint de status.

Como a API sinaliza erros?+

Respostas não-2xx trazem um corpo JSON com um objeto `error`: `type`, `code`, `message` e um ID de requisição para suporte. Casos comuns: 400 invalid_request_error com `param` apontando para o campo inválido; 402 insufficient_credits com as contagens `required` e `available`; 429 rate_limit_exceeded com `retry_after` em segundos e um header Retry-After correspondente. Erros 5xx podem ser tentados novamente com backoff exponencial.

Node.js · API de Provador Virtual

Criar conta e obter chave de API

Defina `PHOTTA_API_KEY` no ambiente, escreva um pequeno helper `phottaFetch()` que chama `https://ai.photta.app/api/v1` com `Authorization: Bearer photta_live_xxx`, envie um POST para `/tryon/apparel` com a URL da imagem do produto, ID do manequim e ID da pose, e então faça poll em `/tryon/apparel/:id` a cada 3 segundos até que `status === 'completed'` — tipicamente dentro de 1.5–4 minutos.

API de Provador Virtual para Node.js — Photta | Photta