Node.js · Virtual Try-On API

Virtual Try-On API trong Node.js

Hiện chưa có package @photta/node — và bạn cũng không cần đến nó. Node 18+ tích hợp sẵn `fetch`, và một helper 20 dòng sẽ giúp bạn có hình ảnh người mẫu đầu tiên trong khoảng năm phút.

Tóm tắt trong một câu

Thiết lập `PHOTTA_API_KEY` trong môi trường, viết một helper `phottaFetch()` nhỏ để gọi `https://ai.photta.app/api/v1` với `Authorization: Bearer photta_live_xxx`, POST tới `/tryon/apparel` với URL ảnh sản phẩm, ID ma-nơ-canh và ID tư thế, sau đó poll `/tryon/apparel/:id` mỗi 3 giây cho đến khi `status === 'completed'` — thường trong vòng 1.5–4 phút.

Đã cập nhật · 2026-04-19

Yêu cầu đầu tiên của bạn

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

Kỳ vọng gì

Typical completion

1–3min

2K / 4K credits

4 / 6

Styles

2

Batch-ready

yes

Cách hoạt động

Virtual Try-On API trong Node.js

Năm bước, khoảng năm phút từ lúc đăng ký đến hình ảnh đầu tiên.

  1. 01

    Bước 1

    Đăng ký và tạo key

    Tạo tài khoản tại ai.photta.app. Mở phần Nhà phát triển trên dashboard, nhấp Tạo API key và lấy live key. Nó bắt đầu bằng `photta_live_` theo sau là 32 ký tự hex.

  2. 02

    Bước 2

    Lưu key trong env, không lưu trong mã nguồn

    Thêm `PHOTTA_API_KEY=...` vào `.env` (hoặc kho lưu trữ bí mật của nền tảng bạn dùng) và tải nó qua `process.env`. Đừng bao giờ commit key; đừng bao giờ import nó vào file được đánh dấu `'use client'` — trình đóng gói (bundler) sẽ đưa nó vào trình duyệt.

  3. 03

    Bước 3

    Viết một fetch helper nhỏ

    Một wrapper khoảng 20 dòng quanh `fetch()` để xử lý base URL, Authorization header, JSON body và chuẩn hóa lỗi. Đây là lớp trừu tượng duy nhất bạn cần cho đến khi có SDK chính thức.

  4. 04

    Bước 4

    Gửi yêu cầu thử đồ và poll

    POST tới `/tryon/apparel` với `product_type`, `product_images`, `mannequin_id`, `pose_id`, `resolution` và `aspect_ratio`. API trả về ID tạo ảnh ngay lập tức. Poll `/tryon/apparel/:id` mỗi 3 giây cho đến khi `status === 'completed'`.

  5. 05

    Bước 5

    Lưu trữ kết quả

    Payload hoàn tất bao gồm `output_url` và `thumbnail_url`. Hãy tải dữ liệu một lần và lưu trữ trong kho lưu trữ đối tượng của riêng bạn — các URL này ổn định nhưng sản phẩm của bạn không nên phụ thuộc vào CDN của Photta để hiển thị.

Code toàn quy trình

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;
}

Tại sao lại có cấu trúc này

Tại sao dùng helper lại tốt hơn thư viện client — ở thời điểm hiện tại

  • 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

Những gì nó không làm

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

Câu hỏi từ các nhà phát triển khác

Questions other developers ask

Có SDK Photta Node.js chính thức không?+

Chưa có. Tài liệu Photta dự kiến phát triển SDK sau khi đạt các mốc áp dụng: Python khi có mười người dùng API, Node.js khi đạt hai mươi. Cho đến lúc đó, lộ trình được hỗ trợ là REST thô qua cURL, native fetch của Node hoặc thư viện requests của Python. Helper 20 dòng trên trang này tương đương với một client cho các endpoint bạn sẽ dùng nhiều nhất.

Những phiên bản Node.js nào được hỗ trợ?+

Bất kỳ phiên bản nào hỗ trợ `fetch` gốc — nghĩa là Node 18 trở lên. Trên Node 16, bạn có thể dùng polyfill với `node-fetch` hoặc nâng cấp phiên bản. Phần mã còn lại là ECMAScript 2020 thuần túy (async/await, template literals, dynamic imports) nên không có yêu cầu runtime nào khác.

Làm thế nào để xác thực từ Node?+

Gửi `Authorization: Bearer photta_live_xxx` trong mỗi yêu cầu. Key bắt đầu bằng `photta_live_` trong môi trường production, `photta_test_` khi chế độ sandbox ra mắt. Đặt nó vào biến môi trường và tải qua `process.env.PHOTTA_API_KEY`. API chưa hỗ trợ OAuth client credentials hoặc xác thực dựa trên session.

Làm thế nào để xử lý khoảng thời gian tạo ảnh 1.5–4 phút?+

Endpoint thử đồ hoàn toàn bất đồng bộ. Lệnh POST trả về ID tạo ảnh ngay lập tức với `status: 'processing'`. Poll `GET /tryon/apparel/:id` mỗi 3–5 giây cho đến khi `status` chuyển sang `completed` hoặc `failed`. Hãy giới hạn số lần thử để tác vụ bị kẹt không làm treo yêu cầu mãi mãi — 120 lần thử mỗi 3 giây là đủ an toàn.

Tôi có thể gọi API bên trong Next.js không?+

Có — từ route handler (`app/**/route.ts`), server action (`'use server'`), hoặc middleware. Hãy giữ API key ở phía server; đừng bao giờ import helper từ file `'use client'`. Đối với các tác vụ chạy lâu vượt quá giới hạn timeout của Vercel function, hãy chuyển việc polling sang một hàng đợi (Inngest, Trigger.dev, BullMQ) và trả về ID tạo ảnh cho trình duyệt để nó có thể poll webhook hoặc endpoint trạng thái của riêng bạn.

API báo lỗi như thế nào?+

Các phản hồi không phải 2xx sẽ mang theo JSON body với đối tượng `error`: `type`, `code`, `message` và một request ID để hỗ trợ. Các trường hợp phổ biến: 400 invalid_request_error với `param` chỉ ra trường dữ liệu sai; 402 insufficient_credits với số lượng `required` và `available`; 429 rate_limit_exceeded với `retry_after` tính bằng giây và một Retry-After header tương ứng. Các lỗi 5xx có thể thử lại an toàn với exponential backoff.

Node.js · Virtual Try-On API

Tạo tài khoản và lấy API key

Thiết lập `PHOTTA_API_KEY` trong môi trường, viết một helper `phottaFetch()` nhỏ để gọi `https://ai.photta.app/api/v1` với `Authorization: Bearer photta_live_xxx`, POST tới `/tryon/apparel` với URL ảnh sản phẩm, ID ma-nơ-canh và ID tư thế, sau đó poll `/tryon/apparel/:id` mỗi 3 giây cho đến khi `status === 'completed'` — thường trong vòng 1.5–4 phút.

Virtual Try-On API cho Node.js — Photta | Photta