Node.js · 幽灵模特 API
幽灵模特 API Node.js 环境
一句话总结
在环境变量中设置 PHOTTA_API_KEY,为 https://api.photta.app/api/v1 编写一个带有 Bearer 认证的简易 fetch 辅助函数,POST 到 /api/v1/ghost-mannequin,随后每 3 秒轮询一次 /api/v1/ghost-mannequin/{id} 直到状态变为 completed。
- 常规耗时: 1.5–4 min
- Credits: 2K 分辨率 4 credits · 4K 分辨率 5 credits
- 处理方式: 异步,轮询
- 限制: 600 次请求/分钟
- 身份验证: Bearer key
本页所有数据均来自 Photta API 文档 · 已验证
RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/ghost-mannequin \
-H "Authorization: Bearer $PHOTTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')
# $ID is data.id from the POST response. Poll every 3 seconds until status is "completed" or "failed".
for i in $(seq 1 120); do
RESULT=$(curl -s "https://api.photta.app/api/v1/ghost-mannequin/$ID" -H "Authorization: Bearer $PHOTTA_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.data.status')
[ "$STATUS" = "completed" ] && break
[ "$STATUS" = "failed" ] && echo "generation failed" && exit 1
sleep 3
done
echo "$RESULT" | jq -r '.data.output_url'const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
}),
});
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/ghost-mannequin/${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");
}import os, requests
res = requests.post(
"https://api.photta.app/api/v1/ghost-mannequin",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
},
)
data = res.json()["data"] # data["id"], data["status"]
import time
def wait_for(job_id):
for _ in range(120):
res = requests.get(f"https://api.photta.app/api/v1/ghost-mannequin/{job_id}", headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"})
data = res.json()["data"]
if data["status"] == "completed":
return data["output_url"]
if data["status"] == "failed":
raise RuntimeError(data.get("error_message", "generation failed"))
time.sleep(3)
raise TimeoutError("timed out after 6 minutes")概览
概览
- 端点
- POST /api/v1/ghost-mannequin
- 身份验证
- Bearer API 密钥
- 处理方式
- 异步 — 轮询状态端点
- 常规耗时
- 1.5–4 min
- Credits
- 2K 分辨率 4 credits · 4K 分辨率 5 credits
- 宽高比
- 3:4 · 1:1 · 4:3 · 9:16 · 16:9
- 输入限制
- 单张图片最大 10 MB;支持 JPEG, PNG, WebP
- 幂等性
- 否
工作原理
从注册到输出第一张图片,只需五步,大约五分钟。
步骤 1
注册并生成 key
在 ai.photta.app 创建账号。打开控制台的 Developers 区域,点击 Generate API key,获取正式环境 key。它以 `photta_live_` 开头,后接 32 位十六进制字符。
步骤 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
编写一个微型 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
提交 try-on 任务并轮询
使用文档示例中的请求体向 `/api/v1/ghost-mannequin` 发送 POST 请求——下方的代码包含了所有字段。API 会立即返回一个生成 ID。每隔 3 秒轮询一次 `/api/v1/ghost-mannequin/{id}`,直到 `status === 'completed'`。
const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", { method: "POST", headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg", "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg", "image_side": "front", "angle": "side", "style": "3d", "background_color": "white", "resolution": "2K", "aspect_ratio": "3:4", "user_instruction": "closed front, cream interior lining", "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67" }), }); 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/ghost-mannequin/${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
持久化存储结果
完成状态的 payload 包含 `output_url` 和 `thumbnail_url`。拉取一次字节流并存入你自己的对象存储中——这些 URL 虽是长期有效的,但你的产品不应依赖 Photta 的 CDN 来进行渲染展示。
错误
- 400
invalid_request_error - The request is malformed or contains invalid parameters.
- 401
authentication_error - The API key is missing, invalid, or expired.
- 402
insufficient_credits_error - Your account does not have enough credits.
- 404
not_found_error - The requested resource does not exist.
- 409
conflict_error - The request conflicts with current state — e.g. your concurrent-batch cap is reached.
- 429
rate_limit_error - Too many requests. Slow down and retry.Retry-After: 30
- 500
api_error - An internal server error occurred. Retry later.
try {
await photta("/ghost-mannequin", { method: "POST", body: JSON.stringify({
"product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
"back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
"image_side": "front",
"angle": "side",
"style": "3d",
"background_color": "white",
"resolution": "2K",
"aspect_ratio": "3:4",
"user_instruction": "closed front, cream interior lining",
"brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
}) });
} 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/ghost-mannequin/{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 错误可安全使用指数退避策略重试。
相关页面
Python
Python 中的 幽灵模特 API
在 Python 中使用 requests 库调用 Photta 的 幽灵模特 API。三十行包装函数,通过 httpx 具备异步亲和性,可在 Django、FastAPI 和 Celery 中开箱即用。
阅读cURL
通过 cURL 调用 幽灵模特 API
直接在终端中使用 cURL 调用 Photta 的 幽灵模特 API。提交、轮询、下载——每个代码片段均可搭配 jq 用于自动化流水线脚本。
阅读功能特性
幽灵模特 API 适用于镂空模特商品图
AI 幽灵模特 endpoint。从服装照片中移除模特,完整保留内部细节。支持 3D 或平铺效果,支持批量处理,2K 分辨率 4 credits。
阅读构建
为您的商品目录实现隐形模特自动提取
每晚目录自动化配方:拉取昨天的商品更新,批量提交至 Photta 的隐形模特 API,轮询父批次,持久化存储到您的数据库。
阅读快速开始
5 分钟内生成第一张 Photta 图像。
注册、生成 API 密钥、运行第一个 cURL 调用、轮询直至完成、持久化保存结果。共五个步骤,端到端完整记录。
阅读参考
Photta API 定价
Photta API 各个 endpoint 在 2K 和 4K 分辨率下的 credits 成本、扣费与退款机制,以及哪些 endpoint 是免费的。没有按单张图片收取的货币价格。
阅读
本页所有数据均来自 Photta API 文档 · 已验证
五分钟内上手试用 API
生成 Photta API key,粘贴上方的 cURL 代码片段,咖啡还没煮好,你的第一张模特实穿图就已经生成完毕。
- 1.5–4 min
- 2K 分辨率 4 credits · 4K 分辨率 5 credits
- 异步,轮询
- 600 次请求/分钟
- Bearer key