构建 · Shopify

构建 Shopify 试穿应用

一句话总结

Shopify 试穿应用从 Admin API 读取商品图片,将其 POST 至 Photta,在后台 worker 中轮询作业,然后通过 productCreateMedia 将生成完成的 URL 传给 Shopify。

  • Credits: 2K 分辨率 5 credits · 4K 分辨率 6 credits
  • 常规耗时: 1.5–4 min
  • 处理方式: 异步,轮询

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

从 Admin API 读取商品图片,通过 Photta 渲染试穿效果,再将结果推回作为商品媒体资源。只需 4 次调用,无需自行处理图片。

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

工作原理

从商品页面到试穿图片

配置应用权限、读取图片、提交任务、在请求主路径外轮询、附加媒体资源。

  1. 步骤 1

    配置应用权限

    试穿应用需要读取商品并写入媒体资源。仅申请应用实际使用的商品权限范围,切勿多要——商家会查看授权界面。

  2. 步骤 2

    获取 Photta API key

    每个环境配置一个 key,保存在应用的服务器端配置中。切勿将其暴露给在线商店(storefront)或商家的浏览器。

  3. 步骤 3

    读取商品图片

    查询商品以获取其首张图片。该 URL 是公开的,正好符合 Photta endpoint 的需求——无需重新上传,也无需管理签名 URL。

  4. 步骤 4

    提交试穿任务

    POST 图片以及模特和姿势参数。响应是即时的,并返回 generation id;此时尚未开始渲染。

  5. 步骤 5

    在后台作业中轮询

    Shopify 要求 webhook 处理程序在数秒内响应,而生成耗时会超过这个时间。立即返回确认,加入队列,并在 worker 中每 3 秒轮询一次。

  6. 步骤 6

    附加媒体资源

    将生成完成的 URL 传给 Shopify,Shopify 会自行下载文件。建议你也在己方持久化保存该图片,以便画廊能够独立保留。

端到端的 4 次调用

Photta 的请求与轮询逻辑直接取自 API 文档;Shopify 调用则使用 Admin API 原生接口。

// Shopify Admin GraphQL — the product's first image is your source photo
const query = `query($id: ID!) {
  product(id: $id) { title images(first: 1) { nodes { url } } }
}`;

const res = await admin.graphql(query, { variables: { id: productGid } });
const { data } = await res.json();
const productImage = data.product.images.nodes[0].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
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");
}
// Shopify downloads the URL itself, so hand it the Photta output_url
const mutation = `mutation($id: ID!, $media: [CreateMediaInput!]!) {
  productCreateMedia(productId: $id, media: $media) {
    mediaUserErrors { field message }
  }
}`;

await admin.graphql(mutation, {
  variables: {
    id: productGid,
    media: [{ originalSource: outputUrl, mediaContentType: "IMAGE", alt: "Virtual try-on" }],
  },
});

开发者常见问题

Shopify 开发者常见问题

Photta key 应该存放在 Shopify 应用的什么位置?

存放在应用服务器的环境变量中,切勿放在主题、app block 或 app proxy 响应中。凡是在线商店可读取的内容,顾客也同样能读取。

这需要哪些 Shopify 权限范围(scopes)?

读取商品图片和写入商品媒体资源的权限。Photta 完全不需要任何 Shopify 访问权限——你的应用是唯一同时与两端通信的主体。

如何确保 webhook 保持快速响应?

立即返回确认,将任务加入队列,并在 worker 中轮询。生成耗时超过了 webhook 处理程序应有的时长,因此任何等待生成的操作都不应放在处理程序中。

我可以按图片向商家收费吗?

这完全取决于你的定价策略。Photta 按每次调用从你的账户扣除 credits,因此每张图片的成本在渲染前即可明确;在此基础上加收多少由你决定。

如果商品没有图片怎么办?

直接跳过,切勿发送占位图。该 endpoint 需要真实的服装照片,使用占位图只会白白消耗 credits 生成无人会发布的图片。

专注交付应用,远离繁琐底层

本页中的 Photta 调用均直接源自 API 文档。获取 key,几分钟内即可完成首次渲染。