Node.js · 虚拟 try-on API

虚拟 try-on API Node.js 环境

一句话总结

在环境变量中设置 PHOTTA_API_KEY,为 https://api.photta.app/api/v1 编写一个带有 Bearer 认证的简易 fetch 辅助函数,POST 到 /api/v1/tryon/apparel,随后每 3 秒轮询一次 /api/v1/tryon/apparel/{id} 直到状态变为 completed。

  • 常规耗时: 1.5–4 min
  • Credits: 2K 分辨率 5 credits · 4K 分辨率 6 credits
  • 处理方式: 异步,轮询
  • 限制: 600 次请求/分钟
  • 身份验证: Bearer key

本页所有数据均来自 Photta API 文档 · 已验证

POST/api/v1/tryon/apparel
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

async function waitFor(id) {
  for (let attempt = 0; attempt < 120; attempt++) {
    const res = await fetch(`https://api.photta.app/api/v1/tryon/apparel/${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");
}

概览

概览

端点
POST /api/v1/tryon/apparel
身份验证
Bearer API 密钥
处理方式
异步 — 轮询状态端点
常规耗时
1.5–4 min
Credits
2K 分辨率 5 credits · 4K 分辨率 6 credits
宽高比
3:4 · 1:1 · 4:3 · 9:16 · 16:9
输入限制
单张图片最大 10 MB;支持 JPEG, PNG, WebP
幂等性
否

工作原理

从注册到输出第一张图片,只需五步,大约五分钟。

  1. 步骤 1

    注册并生成 key

    在 ai.photta.app 创建账号。打开控制台的 Developers 区域,点击 Generate API key,获取正式环境 key。它以 `photta_live_` 开头,后接 32 位十六进制字符。

  2. 步骤 2

    将 key 存入环境变量,切勿写入源码

    将 `PHOTTA_API_KEY=...` 添加到 `.env`(或你平台的密钥管理服务中),并通过 `process.env` 读取。切勿将 key 提交到版本库;切勿将其导入带有 `'use client'` 标记的文件——打包工具会将其暴露到浏览器端。

    node --version   # 18 or later ships fetch
    echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env
  3. 步骤 3

    编写一个微型 fetch 辅助函数

    一个 20 行左右的 `fetch()` 包装函数即可处理 Base URL、Authorization 请求头、JSON 请求体和错误规范化。在官方 SDK 发布之前,这是你唯一需要的抽象层。

    // 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;
    }
  4. 步骤 4

    提交 try-on 任务并轮询

    使用文档示例中的请求体向 `/api/v1/tryon/apparel` 发送 POST 请求——下方的代码包含了所有字段。API 会立即返回一个生成 ID。每隔 3 秒轮询一次 `/api/v1/tryon/apparel/{id}`,直到 `status === 'completed'`。

    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
    
    async function waitFor(id) {
      for (let attempt = 0; attempt < 120; attempt++) {
        const res = await fetch(`https://api.photta.app/api/v1/tryon/apparel/${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");
    }
  5. 步骤 5

    持久化存储结果

    完成状态的 payload 包含 `output_url` 和 `thumbnail_url`。拉取一次字节流并存入你自己的对象存储中——这些 URL 虽是长期有效的,但你的产品不应依赖 Photta 的 CDN 来进行渲染展示。

错误

400invalid_request_error
The request is malformed or contains invalid parameters.
401authentication_error
The API key is missing, invalid, or expired.
402insufficient_credits_error
Your account does not have enough credits.
404not_found_error
The requested resource does not exist.
409conflict_error
The request conflicts with current state — e.g. your concurrent-batch cap is reached.
429rate_limit_error
Too many requests. Slow down and retry.Retry-After: 30
500api_error
An internal server error occurred. Retry later.
try {
  await photta("/tryon/apparel", { method: "POST", 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."
  }) });
} 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;
}

限制

  • 每个 API 密钥每分钟 600 次请求 (固定窗口;各套餐限制相同)
  • 429 响应包含 Retry-After: 30 秒
  • 单张图片最大 10 MB
  • 格式:: JPEG, PNG, WebP
  • 各套餐并发批处理数:: Free 1 · Hobby 2 · Seller 3 · Brand 4 · Studio 6
  • 仅支持轮询 — API 不发送 Webhook。

为什么辅助函数目前优于客户端 SDK

  • Node 18+ 内置原生 fetch——零运行时依赖
  • 同一个辅助函数可在 Next.js 路由处理程序、Server Actions 以及任何 Worker 中直接运行
  • 将 API Key 保留在环境变量中;切勿在 'use client' 模块中导入该辅助函数,否则打包器会将其泄露
  • 兼容任何队列系统或定时任务:BullMQ、Inngest、Trigger.dev、Vercel Cron、Cloudflare Queues

暂不支持的功能

  • 尚无官方 @photta/node 包——目前 REST 是唯一的接入方式
  • 轮询是唯一的完成信号;API 不发送 Webhook
  • 仅支持 Bearer Key;没有 OAuth 客户端凭据流程

开发者常见问题

是否有官方的 Photta Node.js SDK?

暂无。文档推荐的做法是通过 Node 原生 fetch 调用底层 REST API——本页提供的辅助函数就是完整的集成实现,且适用于所有功能特性。

支持哪些 Node.js 版本?

任何支持原生 `fetch` 的版本——即 Node 18 及更高版本。在 Node 16 上,你需要使用 `node-fetch` 打 polyfill 或直接升级环境。其余代码均为纯 ECMAScript 2020(async/await、模板字符串、动态导入),无其他运行时要求。

如何从 Node 进行身份验证?

在每个请求中携带 `Authorization: Bearer photta_live_xxx`。将密钥存入环境变量并通过 `process.env` 读取;切勿在浏览器端运行的文件中导入它。

如何处理生成等待窗口?

生成 endpoint 完全采用异步设计。POST 请求会立即返回一个带有 `status: 'processing'` 的生成 ID。每隔 3–5 秒轮询一次 `GET /api/v1/tryon/apparel/{id}`,直到 `status` 变为 `completed` 或 `failed`,并设置最大重试次数以防卡住的任务导致请求无限挂起。

我可以在 Next.js 内部调用此 API 吗?

可以——在路由处理程序(`app/**/route.ts`)、Server Action(`'use server'`)或中间件中调用。务必将 API Key 保留在服务端;切勿在 `'use client'` 文件中导入该辅助函数。对于执行时间超过 Vercel 函数超时的长任务,可将轮询交由队列系统(Inngest、Trigger.dev、BullMQ)处理,并将生成 ID 返回给浏览器,让前端轮询你自己的状态 endpoint。

API 如何返回错误信号?

非 2xx 响应会返回一个包含 `error` 对象的 JSON 请求体:`type`、`code`、`message` 以及用于支持排查的请求 ID。常见情况:400 invalid_request_error,附带指向错误字段的 `param`;402 insufficient_credits,附带 `required` 和 `available` 计数;429 rate_limit_exceeded,附带以秒为单位的 `retry_after` 及对应的 Retry-After 标头。5xx 错误可安全使用指数退避策略重试。

相关页面

本页所有数据均来自 Photta API 文档 · 已验证

五分钟内上手试用 API

生成 Photta API key,粘贴上方的 cURL 代码片段,咖啡还没煮好,你的第一张模特实穿图就已经生成完毕。

  • 1.5–4 min
  • 2K 分辨率 5 credits · 4K 分辨率 6 credits
  • 异步,轮询
  • 600 次请求/分钟
  • Bearer key