API - 概览

API - 3D模型生成器

导入模型和模板、启动生成器,并处理消息通信和项目保存。

端点概览

方法端点说明访问权限
GET/public-api/v1/model-generator/catalog列出可见的生成器商品、配置和模板修订版本。embed:session:create
GET/public-api/v1/model-generator/models列出可导入的模型,包含其固定的生成器源描述符。embed:session:create
GET/public-api/v1/model-generator/designer-catalog返回 Designer 使用的生成器模型目录。embed:session:create
GET/public-api/v1/model-generator/projects列出所有者的生成器项目以及全局可用的生成器项目。embed:session:create
GET/public-api/v1/model-generator/projects/:projectId返回项目的最新或指定修订版本、模板和文件清单。embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/revisions/:revision返回项目的最新或指定修订版本、模板和文件清单。embed:session:create
GET/public-api/v1/model-generator/projects/:projectId/artifacts/:artifactId检查项目访问权限后下载其产物。embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/template返回所选配置修订版本中有权访问的模板文档。embed:session:create
GET/public-api/v1/model-generator/configurations/:configurationId/revisions/:revision/import返回包含依赖文件的模板导入包。embed:session:create
GET/public-api/v1/model-generator/mannequins返回两个人体模型及其资源描述符。embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assets列出纹理库或背景库中的资源及其可导入文件。embed:session:create
GET/public-api/v1/model-generator/image-libraries/:kind/assets/:assetId返回单个纹理或背景资源及其可导入文件。embed:session:create
GET/public-api/v1/model-generator/public-files/:key下载获准访问的生成器依赖文件。embed:session:create

3D 模型生成器

生成器导入端点接受只读的服务器间请求。这些请求需要标准 API 请求头、embed:session:create 权限范围以及有效的订阅方案。导入授权不会创建编辑器会话,也不会消耗该会话的月度配额。打开编辑器时使用的 monthlyEmbedTokenLimit 计数器与其他嵌入式工具共用。

查找并导入生成器模型

使用 /model-generator/models 列出可用的、附带生成器的模型。generator 描述符固定指定 projectId、revision、configurationId、templateRevision、productId 和 productModel3dId。按其 importPath 获取对应的确切源修订版本。商品资源清单也会提供 generators 以及各个模型的 generator 描述符。模板可按配置和修订版本单独导入。

目录筛选条件

端点详情
/model-generator/models模型列表:name(或 q)、categoryId、scope(all、own、global)、limit(1-50)和 offset。
/model-generator/catalog模板目录:generatorType、productId、audience、q、templateKey、configurationId、limit 和 offset。
/model-generator/projects项目列表:configurationId、q、scope(all、own、global)、limit 和 offset。公共代理默认将 scope 设为 all。
/model-generator/image-libraries/:kind/assets纹理/背景库:kind 为 texture 或 background;使用 q、category 和 mapType 筛选可用资源。

项目导入包包含 document、revision、template 和 files 清单。每个文件都提供一个位于 /v1/model-generator/ 下的 path;从 Alter Product 下载时,在其前面加上 /public-api。将所需文件复制到自己的存储空间,并用本地引用替换源引用。通过各自的目录端点导入人体模型和纹理库;public-files 仅允许访问获准的资源路径,模板也必须通过相应配置和修订版本的访问权限检查。

请求示例(fetch)

// Server-side: uses alterFetch and authHeaders from the API connection guide.
const catalog = await alterFetch('/model-generator/models?' + new URLSearchParams({
  scope: 'all', limit: '24', offset: '0'
}));

const selected = catalog.items[0];
if (!selected?.generator) throw new Error('Select an available generator model');

const importPath = selected.generator.importPath;
if (!importPath.startsWith('/v1/model-generator/projects/')) {
  throw new Error('Invalid generator import path');
}
const bundle = await alterFetch(importPath.slice('/v1'.length));

for (const file of bundle.files) {
  if (!file.path.startsWith('/v1/model-generator/')) {
    throw new Error('Invalid generator file path');
  }
  const response = await fetch('https://alterproduct.com/public-api' + file.path, {
    headers: authHeaders,
    redirect: 'error'
  });
  if (!response.ok) throw new Error(`File download failed: ${response.status}`);
  const bytes = new Uint8Array(await response.arrayBuffer());
  // Persist bytes in your local storage; record the mapping from
  // file.sourceHref / file.href to the resulting local file reference.
}
// Persist bundle.document, bundle.template and revision metadata locally.
// Import the related product asset and its textures/mockups as needed:
const product = await alterFetch('/assets/products/' + selected.generator.productId);
const mannequins = await alterFetch('/model-generator/mannequins');
console.log({ product, mannequins });

编辑器会话与本地存储

创建编辑器会话时,传入 tool: model-generator、标识本地生成器项目的正数 toolId(不是项目 UUID 或 WooCommerce 商品 ID),以及允许的店面 origin。此工具不应传入 designId、orderId、runtimeBindingId 或购物车字段。生成器项目的 UUID 是独立的标识符。通过 iframe 握手传递返回的 token;运行时初始化会返回包含 storageMode: wordpress_local 的生成器上下文。

// Server-side, after authorizing the merchant's access to this local project.
const localProjectId = 42; // Local generator project ID, not its UUID or WC product ID.
const session = await alterFetch('/embed/session', {
  method: 'POST',
  body: JSON.stringify({
    tool: 'model-generator',
    toolId: localProjectId,
    origin: 'https://yourstore.com'
  })
});

// The iframe receives session.token through ALTER_CUSTOMIZER_SESSION_READY.
// Do not put API credentials or the token in the iframe URL.
const bootstrapResponse = await fetch('https://alterproduct.com/public-api/v1/runtime/bootstrap', {
  headers: { Authorization: `Bearer ${session.token}` }
});
if (!bootstrapResponse.ok) throw new Error('Generator bootstrap failed');
const context = await bootstrapResponse.json();
console.log(context);

响应示例

{
  "runtimeBindingId": null,
  "designId": null,
  "productId": 42,
  "toolId": 42,
  "runtimeType": "model-generator",
  "storageMode": "wordpress_local",
  "parentOrigin": "https://yourstore.com"
}
// Host page: WordPress returns a numeric toolId and a UUID in id.
const url = new URL('https://alterproduct.com/app/model-generator');
url.search = new URLSearchParams({
  embedded: '1',
  lng: 'en',
  parentOrigin: window.location.origin,
  toolId: String(localProject.toolId),
  serverProjectId: localProject.id
}).toString();
// Optional: serverProjectRevision pins an existing saved revision.
iframe.src = url.toString();
// Install the authenticated handshake and storage bridge described below.
// Setting iframe.src alone does not authorize the editor or provide storage.

WordPress 桥接使用的 iframe 消息

WordPress 插件承载存储桥接功能,并检查管理员或 WooCommerce 店铺管理员权限。它会验证 iframe 的 origin、源窗口、nonce、请求 ID 以及允许的项目路径。桥接功能将本地读写请求发送到 /wp-json/alter-wc/v1/model-generator。API 凭据保留在服务器端。自定义集成必须实现同等的、经过身份验证的存储处理机制;公共生成器 API 不会将项目保存到 Alter Product。

类型说明
ALTER_CHILD_HELLO / ALTER_PARENT_ACK子窗口使用 nonce 发起握手;父窗口确认同一个 nonce。
ALTER_CUSTOMIZER_INIT_SESSION / ALTER_CUSTOMIZER_SESSION_READY子窗口请求 model-generator 编辑会话;父窗口返回已授权的 token。
ALTER_MODEL_GENERATOR_REQUEST子窗口发送 requestId、nonce 和 request,其中 request 包含 method、path、data 和 responseType。
ALTER_MODEL_GENERATOR_RESPONSE父窗口返回相同的 requestId 和 nonce,以及 status、data、headers 和任何 error。
// Messages after ALTER_CHILD_HELLO / ALTER_PARENT_ACK agree on the nonce.
// Iframe -> parent:
const sessionRequest = {
  type: 'ALTER_CUSTOMIZER_INIT_SESSION',
  nonce: handshakeNonce,
  payload: {
    tool: 'model-generator', alterProductId: localProject.toolId, mode: 'edit'
  }
};

// Parent -> iframe, after the server authorizes the merchant and issues a token:
const sessionReady = {
  type: 'ALTER_CUSTOMIZER_SESSION_READY',
  nonce: handshakeNonce,
  token: session.token,
  tool: 'model-generator',
  cartKey: `model-generator:${localProject.id}`,
  mode: 'edit',
  localSession: false,
  adminSession: true
};
// Send only to the validated iframe's exact origin and source window.
// An authorized token and successful bootstrap are still required.

保存时提供 expectedRevision、templateRevision、document 和产物引用。每次保存都会创建一个不可变的修订版本;如果 expectedRevision 已过期,则返回 HTTP 409。WordPress 将元数据存储在数据库中,将文件存储在 uploads 目录中。JSON 会经过精简,并且仅在压缩能够减小体积时使用 gzip 压缩。

// Example message from the iframe; savedSnapshot and artifact IDs come
// from the generator. The host checks origin/source/nonce/project permissions.
const message = {
  type: 'ALTER_MODEL_GENERATOR_REQUEST',
  requestId: crypto.randomUUID(),
  nonce: handshakeNonce,
  request: {
    method: 'POST',
    path: `/pattern-generator/projects/${projectUuid}/revisions`,
    data: {
      expectedRevision: loadedRevision,
      name: projectName,
      templateRevision,
      document: savedSnapshot,
      references: { artifactIds: savedArtifactIds }
    },
    responseType: 'json'
  }
};

“在设计中使用已保存的模型”会将完整的已保存修订版本发布到关联设计。之后,顾客可以通过现有的 Customizer、Configurator 或 Viewer 查看它,同时仍遵循常规的商品绑定和订阅检查。生成器编辑器仍仅供商家使用。订单关联会保留已保存的项目及其修订版本,因此后续编辑不会在无提示的情况下改变以往订单。