Alter Product Public API 集成

Public API 用于与店铺、电商后端、WordPress/WooCommerce 插件和外部生产工作流程进行服务器之间的集成。

身份验证与基础 URL

https://alterproduct.com/public-api/v1

在电商设置面板中创建 API 凭据。Access Token 仅显示一次,请立即将其存储到后端的密钥存储中。

将 Access Key 和 Access Token 保存在你的服务器上。需要身份验证的端点会拒绝包含 Origin 或 Referer 请求头的浏览器来源调用。

凭据可以设置权限范围。使用 GET /auth/check 验证当前店铺、套餐功能以及凭据返回的权限范围。

x-alter-access-key: YOUR_API_KEY
x-alter-access-token: YOUR_API_TOKEN
参数必填详情
x-alter-access-key公开的凭据标识符。
x-alter-access-token与访问密钥配对的秘密令牌。
x-alter-client-fingerprint可选的稳定指纹,用于限制嵌入会话请求频率。
Authorization仅限运行时由 POST /embed/session 返回的 Bearer 令牌,供 /runtime/bootstrap 使用。

连接测试

在正式集成中启用同步或嵌入功能之前,请使用身份验证检查端点。

GET https://alterproduct.com/public-api/v1/auth/check

请求示例(fetch)

const response = await fetch('https://alterproduct.com/public-api/v1/auth/check', {
  method: 'GET',
  headers: {
    'x-alter-access-key': process.env.ALTER_ACCESS_KEY,
    'x-alter-access-token': process.env.ALTER_ACCESS_TOKEN
  }
});

const payload = await response.json();

if (!response.ok) {
  throw new Error(payload?.code || payload?.error || `Alter API ${response.status}`);
}

console.log(payload);

响应示例

{
  "ok": true,
  "message": "success",
  "storefrontId": 12,
  "userOwnerId": 34,
  "credentialId": 56,
  "scopes": ["orders:read", "orders:write", "products:read"],
  "plan": {
    "requiredPlan": "Business",
    "currentPlanName": "Business",
    "eligible": true,
    "runtimeFlags": {
      "viewer": true,
      "configurator": true,
      "customizer": true
    },
    "limits": {
      "activeRuntimeBindingsLimit": 100,
      "monthlyReassignmentLimit": 1000,
      "monthlyEmbedTokenLimit": 50000
    }
  }
}

下面的辅助函数供后续示例使用。它基于原生 fetch,可在 Node.js 18+ 或任何提供 fetch 的服务器运行时中运行。

const ALTER_API_BASE = 'https://alterproduct.com/public-api/v1';

const authHeaders = {
  'x-alter-access-key': process.env.ALTER_ACCESS_KEY,
  'x-alter-access-token': process.env.ALTER_ACCESS_TOKEN
};

async function alterFetch(path, options = {}) {
  const response = await fetch(`${ALTER_API_BASE}${path}`, {
    ...options,
    headers: {
      ...authHeaders,
      ...(options.body ? { 'Content-Type': 'application/json' } : {}),
      ...options.headers
    }
  });

  const payload = await response.json().catch(() => null);

  if (!response.ok) {
    throw new Error(payload?.code || payload?.error || `Alter API ${response.status}`);
  }

  return payload;
}

端点概览

下表对应 backend-public-api/app.js 中挂载的公共路由。所列路径包含供外部集成使用的公共代理前缀。

方法端点说明访问权限
GET/public-api/healthz服务健康检查。公开
GET/public-api/v1/auth/check验证凭据并返回店铺、权限范围和套餐功能。任何已验证身份的凭据
GET/public-api/v1/customer-orders返回可分页和筛选的客户订单列表。orders:read
GET/public-api/v1/customer-orders/:id返回包含已配置产品条目的单个客户订单。orders:read
POST/public-api/v1/customer-orders/batch按 ID 返回最多 100 个订单。orders:read
PATCH/public-api/v1/customer-orders/:id/status更新订单状态。orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantity更新所选订单明细的数量。orders:write
PATCH/public-api/v1/customer-orders/:orderId/quantity/all为订单中的每个条目设置相同数量。orders:write
DELETE/public-api/v1/customer-orders/:id删除属于店铺所有者的客户订单。orders:write
GET/public-api/v1/products返回店铺产品/设计,包含嵌入可用性和媒体 URL。products:read
GET/public-api/v1/products/:id返回一个店铺产品/设计。products:read
POST/public-api/v1/embed/session为嵌入式工具(包括模型生成器)签发短期有效的 JWT。embed:session:create
GET/public-api/v1/runtime/bootstrap根据嵌入 JWT 解析运行时上下文。Bearer 嵌入令牌
GET/public-api/v1/assets列出所请求类型的素材目录条目。任何已验证身份的凭据
GET/public-api/v1/assets/:type/:assetId返回包含可下载文件用途的素材清单。任何已验证身份的凭据
GET/public-api/v1/assets/:type/:assetId/files/:role按用途下载素材文件。任何已验证身份的凭据
GET/public-api/v1/design-imports列出托管在 Alter 上的可导入设计。已验证身份的凭据,需要 Business 套餐
GET/public-api/v1/design-imports/:id返回设计导入数据载荷和文件描述信息。已验证身份的凭据,需要 Business 套餐
GET/public-api/v1/design-imports/:id/files/:fileId从设计导入描述信息下载文件。已验证身份的凭据,需要 Business 套餐
GET/public-api/v1/file/public/products/:productId/:size返回公共产品预览。尺寸必须为 small.png、medium.png 或 big.png。公开
GET/public-api/v1/file/protected/:key按存储键返回受保护文件。签名 URL 或 files:read
GET/public-api/v1/fonts返回所有可用字体。公开
GET/public-api/v1/currencies返回所有货币。公开
POST/public-api/v1/runtime-bindings/sync-from-wordpress根据 WordPress 产品映射创建或更新运行时绑定。任何已验证身份的凭据
PATCH/public-api/v1/runtime-bindings/:id部分更新运行时绑定。任何已验证身份的凭据
POST/public-api/v1/runtime-bindings/:id/activate激活运行时绑定。任何已验证身份的凭据
POST/public-api/v1/runtime-bindings/:id/deactivate停用运行时绑定。任何已验证身份的凭据
POST/public-api/v1/wp-connect/exchange将 WordPress 自动连接交接代码交换为 API 凭据。一次性交接代码
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

客户订单

客户订单端点允许外部店铺读取已配置的行条目、更新数量、推进订单履约状态,以及移除废弃订单。

参数必填详情
name搜索设计名称和数字订单 ID。
category_id按产品类别 ID 筛选。
order_status允许的订单状态之一。
offset默认为 0,必须 >= 0。
limit此控制器默认为 9,最大为 50。
order_byid、created_at 或 design_name。
directionASC 或 DESC。

请求示例(fetch)

const params = new URLSearchParams({
  limit: '20',
  offset: '0',
  order_status: 'shopping_cart',
  order_by: 'created_at',
  direction: 'DESC'
});

const orders = await alterFetch(`/customer-orders?${params.toString()}`);

const order = await alterFetch('/customer-orders/123');

const batch = await alterFetch('/customer-orders/batch', {
  method: 'POST',
  body: JSON.stringify({
    customerOrderIds: [123, 124, 125]
  })
});

允许的值

状态说明
shopping_cart购物车流程;客户仍可编辑配置。
editable客户仍可编辑订单。
paid订单已付款,可以开始履约。
processing订单正在履约。
completed订单已履约。
cancelled订单已取消。

请求示例(fetch)

await alterFetch('/customer-orders/123/status', {
  method: 'PATCH',
  body: JSON.stringify({
    status: 'processing'
  })
});

await alterFetch('/customer-orders/123/quantity', {
  method: 'PATCH',
  body: JSON.stringify({
    items: [
      { orderDetailId: 987, quantity: 3 }
    ]
  })
});

await alterFetch('/customer-orders/123/quantity/all', {
  method: 'PATCH',
  body: JSON.stringify({
    quantity: 2
  })
});

await alterFetch('/customer-orders/123', {
  method: 'DELETE'
});

响应示例

{
  "order": {
    "id": 123,
    "customizerId": 381,
    "orderStatus": "shopping_cart",
    "createdAt": "2026-05-28T10:15:00.000Z",
    "customizerOrderURL": "https://alterproduct.com/app/customizer/381/123",
    "productItems": [
      {
        "id": 987,
        "model3d": { "id": 381 },
        "size": {
          "id": 395,
          "name": { "pl": "M", "en": "M" },
          "measureSize": null
        },
        "material": {
          "id": 2,
          "name": { "pl": "Bawełna", "en": "Cotton" }
        },
        "printType": {
          "id": 1,
          "name": { "pl": "DTG", "en": "DTG" }
        },
        "color": {
          "id": 418,
          "name": { "pl": "Domyślny", "en": "Default" },
          "hex": "#ffffff"
        },
        "variant": {
          "id": 531,
          "metadata": null,
          "stockQuantity": 25
        },
        "unitPrice": { "value": 12.5, "currency": "EUR" },
        "totalPrice": { "value": 37.5, "currency": "EUR" },
        "quantity": 3
      }
    ],
    "customizerName": "Men's T-Shirt",
    "productGroup": {
      "id": 4,
      "name": { "pl": "Koszulka", "en": "T-Shirt" }
    },
    "totalPrice": { "value": 37.5, "currency": "EUR" }
  }
}

店铺产品

产品端点返回可作为 Viewer、Configurator 或 Customizer 体验嵌入的店铺设计。

参数必填详情
name搜索产品/设计名称。
customizertrue 或 false。
offset默认为 0,必须 >= 0。
limit默认为 9,最大为 50。
order_byid、name 或 created_at。
directionASC 或 DESC。

请求示例(fetch)

const params = new URLSearchParams({
  limit: '20',
  offset: '0',
  name: 't-shirt',
  customizer: 'true',
  order_by: 'created_at',
  direction: 'DESC'
});

const products = await alterFetch(`/products?${params.toString()}`);
const product = await alterFetch('/products/381');

响应示例

{
  "products": {
    "items": [
      {
        "id": 381,
        "name": "Men's T-Shirt",
        "createdAt": "2026-01-03T23:55:05.000Z",
        "productId": 4,
        "media": {
          "img": {
            "big": "https://alterproduct.com/public-api/v1/file/public/products/4/big.png",
            "medium": "https://alterproduct.com/public-api/v1/file/public/products/4/medium.png",
            "small": "https://alterproduct.com/public-api/v1/file/public/products/4/small.png"
          },
          "mockups": []
        },
        "storefrontProduct": {
          "id": 89,
          "idUserDesign": 381,
          "shareAccess": "public",
          "isCustomizer": 1
        },
        "runtimeBindings": [
          {
            "id": 42,
            "runtimeType": "customizer",
            "status": "active",
            "externalProductId": "wc_123"
          }
        ],
        "embeddable": {
          "viewer": true,
          "configurator": true,
          "customizer": true
        }
      }
    ],
    "total": 1
  }
}

嵌入会话与运行时初始化

在服务器上创建短期嵌入令牌,传递给 iframe/运行时,然后让运行时使用 Bearer 令牌调用 bootstrap。

参数必填详情
runtimeBindingId推荐活动运行时绑定的首选标识符。
tool没有 runtimeBindingId 时必填designer | viewer | configurator | customizer | model-generator
toolIdtool: model-generator本地生成器项目的正整数 ID,不是其 UUID 或 WooCommerce 产品 ID。
origin呈现嵌入内容的源,例如 https://yourstore.com.
designId一个标识符Alter Product 设计 ID。不要与 orderId 同时使用。
orderId一个标识符Customizer 订单 ID。仅对 customizer 有效。
cartKey + cartMode仅供 Customizer 使用的购物车上下文。cartMode 为 view 或 edit。

请求示例(fetch)

const session = await alterFetch('/embed/session', {
  method: 'POST',
  headers: {
    'x-alter-client-fingerprint': '9f1b7a5e4b3c2d1f9f1b7a5e4b3c2d1f'
  },
  body: JSON.stringify({
    runtimeBindingId: 42,
    origin: 'https://yourstore.com'
  })
});

const bootstrapResponse = await fetch('https://alterproduct.com/public-api/v1/runtime/bootstrap', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${session.token}`
  }
});

const bootstrap = await bootstrapResponse.json();
console.log({ session, bootstrap });

说明

await alterFetch('/embed/session', {
  method: 'POST',
  body: JSON.stringify({
    tool: 'customizer',
    origin: 'https://yourstore.com',
    orderId: 123
  })
});

await alterFetch('/embed/session', {
  method: 'POST',
  body: JSON.stringify({
    tool: 'viewer',
    origin: 'https://yourstore.com',
    designId: 381
  })
});

响应示例

{
  "token": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjEifQ...",
  "expiresIn": 900,
  "kid": "1",
  "mode": "design",
  "runtimeBindingId": 42,
  "runtimeType": "customizer"
}

Runtime bootstrap

{
  "runtimeBindingId": 42,
  "designId": 381,
  "productId": "wc_123",
  "runtimeType": "customizer",
  "storageMode": "wordpress_local",
  "manifestUrl": "https://yourstore.com/wp-content/uploads/alter/381/manifest.json",
  "assetBaseUrl": "https://yourstore.com/wp-content/uploads/alter/381/",
  "manifestHash": "a3b1...",
  "planCapabilities": {
    "viewer": true,
    "configurator": true,
    "customizer": true
  },
  "cartKey": null,
  "cartMode": null,
  "orderId": null
}

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 the alterFetch helper and authHeaders defined above.
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 查看它,同时仍遵循常规的商品绑定和订阅检查。生成器编辑器仍仅供商家使用。订单关联会保留已保存的项目及其修订版本,因此后续编辑不会在无提示的情况下改变以往订单。

素材目录

素材目录提供产品源素材、背景、环境、图形库条目、设计模板和样机素材。列表端点返回精简的描述信息,详情端点包含文件清单。

类型说明
products基础产品素材、预览、3D 模型、材质和纹理描述信息。
backgroundsViewer 静态背景。
environments环境贴图和预览图像。
image_library图形库素材,包括店铺范围内的图形。
design_templates设计模板预览和图层文件引用。支持 product_id 筛选。
mockups样机生成器素材、背景和叠加贴图。支持 product_id 筛选。

请求示例(fetch)

const assets = await alterFetch('/assets?' + new URLSearchParams({
  type: 'products',
  limit: '20',
  offset: '0',
  search: 'mug'
}));

const details = await alterFetch('/assets/products/4');

const fileResponse = await fetch(
  'https://alterproduct.com/public-api/v1/assets/products/4/files/preview_medium',
  {
    headers: authHeaders
  }
);

const fileBlob = await fileResponse.blob();

响应示例

{
  "type": "products",
  "items": [
    {
      "assetType": "products",
      "assetId": "4",
      "title": "Mug 450ml",
      "slug": "product-4",
      "description": "Base product 4",
      "primaryRole": "preview_big",
      "fileCount": 8,
      "remoteVersion": "1.0",
      "thumbnail": {
        "role": "preview_small",
        "fileName": "product-4-preview-small.png",
        "mime": "image/png",
        "downloadPath": "/v1/assets/products/4/files/preview_small"
      },
      "metadata": {
        "productCategoryId": 2,
        "productModelCount": 1,
        "isDedicated": false
      }
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

设计导入

设计导入提供托管在 Alter 上的设计及其文件,供外部生产或迁移流程使用。API 会检查是否符合 Business 套餐条件。

参数必填详情
search搜索设计标题或 ID。
offset默认为 0。
limit默认为 20,最大为 100。

请求示例(fetch)

const imports = await alterFetch('/design-imports?' + new URLSearchParams({
  limit: '20',
  offset: '0',
  search: 'mug'
}));

const details = await alterFetch('/design-imports/381');

const fileId = details.files[0].id;
const fileResponse = await fetch(
  `https://alterproduct.com/public-api/v1/design-imports/381/files/${fileId}`,
  {
    headers: authHeaders
  }
);

const fileBlob = await fileResponse.blob();

响应示例

{
  "eligible": true,
  "requiredPlan": "Business",
  "currentPlanName": "Business",
  "designs": [
    {
      "id": 381,
      "title": "Men's T-Shirt",
      "createdAt": "2026-01-03T23:55:05.000Z",
      "sourceStorefrontId": 12,
      "productId": 4,
      "productName": {
        "pl": "Koszulka",
        "en": "T-Shirt"
      },
      "storageMode": "alter",
      "runtimeStatus": {
        "designer": true,
        "viewer": true,
        "configurator": true,
        "customizer": true
      },
      "thumbnail": {
        "kind": "design-mockup",
        "fileId": "7df7...",
        "downloadPath": "/v1/design-imports/381/files/7df7..."
      }
    }
  ],
  "total": 1
}

文件、字体和货币

公共预览文件适合在浏览器中使用。受保护文件需要签名 URL 或具有 files:read 权限的 API 凭据。字体和货币是公共读取端点。

端点访问权限详情
/file/public/products/:productId/small.png公开小型产品预览。
/file/public/products/:productId/medium.png公开中型产品预览。
/file/public/products/:productId/big.png公开大型产品预览。
/file/protected/:key签名 URL 或 files:read受保护的对象存储文件。
/fonts公开字体记录数组。
/currencies公开货币记录数组。

请求示例(fetch)

const publicPreview = await fetch(
  'https://alterproduct.com/public-api/v1/file/public/products/4/medium.png'
);

const protectedFile = await fetch(
  'https://alterproduct.com/public-api/v1/file/protected/user_34/381/design/mockup-large.webp',
  {
    headers: authHeaders
  }
);

const fonts = await fetch('https://alterproduct.com/public-api/v1/fonts').then((res) => res.json());
const currencies = await fetch('https://alterproduct.com/public-api/v1/currencies').then((res) => res.json());

响应示例

[
  {
    "id": 1,
    "family": "Inter",
    "source": "google",
    "category": "sans-serif",
    "variants": ["regular", "600", "700"],
    "subsets": ["latin"],
    "version": "v19",
    "menu": "Inter",
    "files": {
      "regular": "https://..."
    }
  }
]
[
  {
    "id": 1,
    "code": "EUR",
    "name": "Euro",
    "symbol": "€",
    "decimalPlaces": 2
  }
]

运行时绑定

运行时绑定将外部电商产品与 Alter Product 设计及运行时类型连接,主要用于 WordPress/WooCommerce 集成和高级店铺后端。

参数必填详情
designId店铺拥有的 Alter Product 设计 ID。
externalProductId同步时必填外部产品 ID,例如 WooCommerce 产品 ID。
runtimeType同步时必填viewer、configurator 或 customizer。
statusdraft、active、inactive、archived 或 legacy_active。
legacyStorefrontProductId可选的旧版映射 ID。
legacyBindingMeta可选的 JSON 元数据,例如 manifestHash。

请求示例(fetch)

await alterFetch('/runtime-bindings/sync-from-wordpress', {
  method: 'POST',
  body: JSON.stringify({
    bindings: [
      {
        externalProductId: 'wc_123',
        runtimeType: 'customizer',
        status: 'active',
        designId: 381,
        legacyBindingMeta: {
          manifestHash: 'a3b1...'
        }
      }
    ]
  })
});

await alterFetch('/runtime-bindings/42', {
  method: 'PATCH',
  body: JSON.stringify({
    status: 'inactive'
  })
});

await alterFetch('/runtime-bindings/42/activate', { method: 'POST' });
await alterFetch('/runtime-bindings/42/deactivate', { method: 'POST' });

wordpress_local

await alterFetch('/runtime-bindings/sync-from-wordpress', {
  method: 'POST',
  body: JSON.stringify({
    bindings: [
      {
        externalProductId: 'wc_123',
        runtimeType: 'viewer',
        status: 'active',
        externalDesign: {
          externalDesignKey: 'wp-design-381',
          productId: 4,
          title: 'WooCommerce local design',
          manifestUrl: 'https://yourstore.com/wp-content/uploads/alter/381/manifest.json',
          assetBaseUrl: 'https://yourstore.com/wp-content/uploads/alter/381/',
          manifestHash: 'a3b1...',
          sourceMeta: {
            pluginVersion: '1.2.0'
          }
        }
      }
    ]
  })
});

响应示例

{
  "message": "runtimeBinding.syncCompleted",
  "runtimeBindings": [
    {
      "id": 42,
      "designId": 381,
      "externalProductId": "wc_123",
      "runtimeType": "customizer",
      "status": "active"
    }
  ]
}

WordPress 连接交换

WordPress 连接交换端点消耗一次性交接代码,并向插件返回 API 凭据。它不是通用的凭据创建端点。

请求示例(fetch)

const response = await fetch('https://alterproduct.com/public-api/v1/wp-connect/exchange', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    code: 'ONE_TIME_HANDOFF_CODE',
    storeUrl: 'https://yourstore.com/',
    siteOrigin: 'https://yourstore.com',
    codeVerifier: 'PKCE_CODE_VERIFIER_32_TO_128_CHARS'
  })
});

const credentials = await response.json();

响应示例

{
  "message": "wpConnect.exchange.ok",
  "accessKey": "generated-access-key",
  "accessToken": "generated-access-token",
  "storefrontId": 12
}

错误与请求频率限制

大多数控制器错误会标准化为 code 响应。身份验证中间件和请求频率限制器可能改为返回 error 响应。

// Controller error
{
  "code": "assetCatalog.invalidType"
}

// Auth middleware or rate limit
{
  "error": "Unauthorized"
}

{
  "error": "Too Many Requests"
}
类型限额时间窗口
全局600 次请求60 秒
GET /auth/check60 次请求60 秒
订单读取/产品读取300 次请求60 秒
订单写入/嵌入会话/运行时绑定120 次请求60 秒
素材/设计导入读取180 次请求60 秒
字体300 次请求60 秒
WP 连接交换30 次请求60 秒
GET /model-generator/*600 次请求60 秒