Appearance
V1 Products API
商品管理模块提供商品查询、有序分步创建、整合数据创建、审核提交和上下架能力。V1 商品固定使用多规格模式,每个商品至少包含一个 SKU。
已上架商品需要直接修改 SKU 售价、库存、启用状态或卖家自有料号时,使用独立的 SKU 更新 API。该模块提供状态/料号、价格、库存三个拆分接口,并继续支持合并更新接口。
概述
- 所有接口需要 Access Token,通过
Authorization: Bearer <access_token>传递。 - 数据按 Token 绑定的卖家租户隔离。
- V1 商品默认且固定为多规格,调用方只需提交 SKU;内部规格结构由服务端自动生成。
spec_name表示第一规格值,可选的item_name表示第二规格值。 - 商品售价固定为 TWD 主单位;请求和响应均使用 decimal string。
- 海关资料由平台根据商品类目维护。
- 商品提交审核前,必须完成基本信息、媒体和完整 SKU 配置。
Base Path: /openapi/v1/products
商品创建流程
V1 提供两种商品创建方案。两种方案都会先保留可继续编辑的商品草稿,且都不会自动提交审核。
方案一:有序分步创建
- 创建基本信息:创建商品草稿,取得商品 ID。
- 上传媒体:取得预签名上传 URL,将文件上传到对象存储。
- 配置 SKU 与详情:设置商品图片、详情图片和 SKU。
- 提交审核:校验完整资料并进入
pending_review。
[Step 1] POST /openapi/v1/products → product
[Step 2] POST /openapi/v1/products/{id}/media/upload → upload_url + file_url
[Step 3] POST /openapi/v1/products/{id} → product
[Step 4] POST /openapi/v1/products/{id}/submit → pending_review方案二:整合数据创建
调用方可以通过异步整合接口一次提交基本资料、媒体来源和 SKU。平台会立即建立商品草稿并返回商品 ID 与任务 ID,再由后台下载并归档媒体。任务结束后,调用方可检查任务状态或继续通过方案一的接口补充资料,资料完整后仍需显式提交审核。
POST /openapi/v1/product-create-tasks → product_id + task_id
GET /openapi/v1/product-create-tasks/{task_id} → task + resources商品列表
GET /openapi/v1/products
Authentication: Required (Access Token)
返回当前租户的商品摘要,固定按 created_at DESC, id DESC 排列。id 是创建时间相同时的稳定第二排序键;V1 不提供自定义排序参数。
Query Parameters
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
limit | number | 否 | 每页数量,默认 20,最大 100 |
offset | number | 否 | 偏移量,默认 0 |
q | string | 否 | 搜索商品名称、露天商品编号、SKU 或卖家自定义编号 |
status | string | 否 | 商品状态,见V1 状态附录 |
review_status | string | 否 | 审核状态:draft、pending、approved、rejected |
min_price | string | 否 | SKU 最低售价,TWD 主单位 decimal string,必须大于 0 |
max_price | string | 否 | SKU 最高售价,TWD 主单位 decimal string,必须大于 0 |
min_qty | number | 否 | 最低总库存,非负整数 |
max_qty | number | 否 | 最高总库存,非负整数 |
Response
| 字段 | 类型 | 说明 |
|---|---|---|
products | ProductSummary[] | 当前页商品摘要 |
count | number | 符合条件的商品总数 |
limit | number | 分页大小 |
offset | number | 偏移量 |
Response Example
json
{
"success": true,
"data": {
"products": [
{
"id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "migrated",
"review_status": "approved",
"name": "轻量防泼水通勤背包",
"class_id": "00110001",
"images": [
"https://static.sugumart.com/products/backpack-front.jpg"
],
"sku_count": 4,
"active_sku_count": 4,
"total_quantity": 75,
"ruten_item_id": "22408041234567",
"created_at": "2026-08-01T03:00:00.000Z",
"updated_at": "2026-08-04T07:20:00.000Z"
}
],
"count": 1,
"limit": 20,
"offset": 0
}
}Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Invalid query parameters | validation_error | 查询参数格式或范围错误 |
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
商品详情
GET /openapi/v1/products/{id}
Authentication: Required (Access Token)
Path Parameters
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string(uuid) | 是 | 商品 ID |
Response
| 字段 | 类型 | 说明 |
|---|---|---|
product | Product | 商品完整详情,包含 SKU |
Response Example
json
{
"success": true,
"data": {
"product": {
"id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "approved",
"review_status": "approved",
"rejected_reason": null,
"name": "轻量防泼水通勤背包",
"description": "<p>适合日常通勤使用的轻量背包。</p>",
"class_id": "00110001",
"store_class_id": "sc_1024",
"stock_status": "3DAY",
"sale_start_time": 1788192000,
"sale_end_time": 1790783999,
"images": [
"https://static.sugumart.com/products/backpack-front.jpg"
],
"content_images": [
"https://static.sugumart.com/products/backpack-detail-1.jpg"
],
"skus": [
{
"id": "0e95a8db-9161-4b39-b77a-2bd796f27715",
"sku": "BAG-BLK-20",
"spec_name": "黑色",
"item_name": "20L",
"taiwan_sale_price": "1280.00",
"ruten_managed_distribution": true,
"supply_price": "900.00",
"qty": 30,
"status": true,
"image": "https://static.sugumart.com/products/backpack-black-20l.jpg",
"weight": "650.00"
}
],
"sku_count": 4,
"active_sku_count": 4,
"total_quantity": 75,
"ruten_item_id": null,
"created_at": "2026-08-01T03:00:00.000Z",
"updated_at": "2026-08-04T07:20:00.000Z"
}
}
}Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
| 404 | Product not found | not_found | 商品不存在或不属于当前租户 |
创建商品(第一步:基本信息)
POST /openapi/v1/products
Authentication: Required (Access Token)
创建多规格商品草稿。本接口不接收媒体和 SKU;成功后使用返回的商品 ID继续后续步骤。
Request Body
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 商品名称,1-130 字符,不得包含反斜线 |
description | string | 是 | 商品详情 HTML,最长 60,000 字符 |
class_id | string | 是 | 平台类目代码,必须来自 GET /openapi/v1/categories |
store_class_id | string | 否 | 店铺商品分类 ID,必须来自当前店铺的商品分类列表 |
stock_status | string | 否 | 3DAY 或 PRE_ORDER;默认 3DAY |
pre_order_ship_date | string | 条件必填 | stock_status=PRE_ORDER 时必填,格式 YYMMDD |
sale_start_time | number | 否 | 指定销售开始时间,Unix 时间戳(秒,UTC 时间点);必须与 sale_end_time 一起提交 |
sale_end_time | number | 否 | 指定销售结束时间,Unix 时间戳(秒,UTC 时间点),必须晚于 sale_start_time;必须与开始时间一起提交 |
Request Example
json
{
"name": "轻量防泼水通勤背包",
"description": "<p>适合日常通勤使用的轻量背包。</p>",
"class_id": "00110001",
"store_class_id": "sc_1024",
"stock_status": "3DAY",
"sale_start_time": 1788192000,
"sale_end_time": 1790783999
}sale_start_time 和 sale_end_time 均省略时,商品不指定销售时间。提交任一销售时间时必须同时提交另一字段,服务端会同步开启商品的指定销售时间状态。
Response (201 Created)
| 字段 | 类型 | 说明 |
|---|---|---|
product | Product | 创建后的商品草稿,status=draft、skus=[] |
Response Example
json
{
"success": true,
"data": {
"product": {
"id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "draft",
"review_status": "draft",
"name": "轻量防泼水通勤背包",
"class_id": "00110001",
"store_class_id": "sc_1024",
"skus": [],
"created_at": "2026-08-04T08:30:00.000Z",
"updated_at": "2026-08-04T08:30:00.000Z"
}
}
}Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Invalid request body | validation_error | 字段格式、长度或预购日期校验失败 |
| 400 | Category is not selectable | category_not_selectable | class_id 是中间类目或仍有启用子节点,不能用于商品发布 |
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
| 404 | Product category not found | category_not_found | class_id 不存在或已停用 |
| 404 | Store class not found | store_class_not_found | store_class_id 不属于当前店铺 |
上传商品媒体(第二步)
POST /openapi/v1/products/{id}/media/upload
Authentication: Required (Access Token)
取得一个图片预签名上传 URL。调用方随后使用返回的上传方法和 Headers 将文件直接传至对象存储;对象存储请求不属于 V1 API。上传完成后,将 file_url 写入第三步对应的主图、详情图、海报图或 SKU 图片字段。
商品视频不使用本接口上传;video_link 只接受平台支持的视频页面 URL。
Path Parameters
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string(uuid) | 是 | 商品 ID |
Request Body
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file_name | string | 是 | 原始文件名,1-255 字符 |
content_type | string | 是 | 图片 MIME type,必须符合对应 purpose 的格式限制 |
purpose | string | 是 | 图片用途:main、detail、poster 或 sku |
file_size | number | 是 | 文件大小,单位 byte,正整数且不得超过对应用途上限 |
width | number | 是 | 原始图片宽度,单位 px,正整数 |
height | number | 是 | 原始图片高度,单位 px,正整数 |
Request Example
json
{
"file_name": "backpack-front.jpg",
"content_type": "image/jpeg",
"purpose": "main",
"file_size": 1536000,
"width": 1200,
"height": 1200
}图片限制
| 用途 | 数量限制 | 格式 | 单张大小 | 原始尺寸 | 建议尺寸 |
|---|---|---|---|---|---|
主图 main | 提交审核时至少 1 张,最多 9 张 | JPEG、PNG | 最大 5 MiB(5,242,880 bytes) | 宽、高均为 300-6000 px | 800 × 800 px;平台发布到露天前会将最长边超过 800 px 的图片等比缩小 |
详情图 detail | 最多 30 张,可为空 | JPEG、PNG、WebP | 最大 5 MiB(5,242,880 bytes) | 宽 600-2000 px,高 600-10000 px | 宽 1000 px,高度按内容决定 |
海报图 poster | 最多 3 张,可为空 | JPEG、PNG、WebP | 最大 5 MiB(5,242,880 bytes) | 宽、高均为 600-3000 px | 1200 × 1200 px |
SKU 图 sku | 每个 SKU 最多 1 张,可为空 | JPEG、PNG | 最大 5 MiB(5,242,880 bytes) | 宽、高均为 300-6000 px | 800 × 800 px |
补充规则:
content_type必须与实际文件内容一致,不能只修改扩展名或请求 Header。- GIF、SVG、AVIF、HEIC 和动画图片不属于 V1 支持格式。
- 平台会在商品保存或提交审核时验证对象存储中的实际文件;实际格式、大小或尺寸与声明不一致时拒绝保存或送审。
- 图片不得包含外部跳转、脚本或非图片内容;图片 URL 必须来自本接口返回的
file_url。 - 主图按数组顺序展示,第 1 张为商品封面图;详情图和海报图同样保留请求顺序。
- 已完成上传的图片通常会长期保留,平台不会因为图片尚未关联商品、后来从商品移除或商品下架而自动清理。V1 不提供图片删除接口;调用方应只为确定需要使用的文件申请上传并完成 PUT,避免上传无用或重复文件。
Response
| 字段 | 类型 | 说明 |
|---|---|---|
upload_url | string | 临时对象存储上传 URL |
file_url | string | 上传完成后的公开文件 URL |
upload_method | string | 固定为 PUT |
upload_headers | object | 上传对象存储时必须原样携带的 Headers |
expires_at | string | 上传 URL 过期时间,ISO 8601 UTC |
Response Example
json
{
"success": true,
"data": {
"upload_url": "https://upload.sugumart.com/presigned/products/backpack-front.jpg?signature=example",
"file_url": "https://static.sugumart.com/products/backpack-front.jpg",
"upload_method": "PUT",
"upload_headers": {
"Content-Type": "image/jpeg"
},
"expires_at": "2026-08-04T08:45:00.000Z"
}
}调用方必须在 expires_at 前完成 PUT,请求体为原始文件二进制,并原样携带 upload_headers。对象存储返回 200 或 204 才表示上传成功;取得预签名 URL 本身不代表文件已上传。
Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Invalid media type | invalid_media_type | content_type 不是对应用途允许的图片类型 |
| 400 | Image file is too large | image_file_too_large | file_size 超过对应用途限制 |
| 400 | Invalid image dimensions | invalid_image_dimensions | width 或 height 不符合对应用途限制 |
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
| 404 | Product not found | not_found | 商品不存在或不属于当前租户 |
| 503 | Upload service unavailable | upload_service_unavailable | 对象存储暂时不可用 |
更新商品(第三步:配置 SKU 与详情)
POST /openapi/v1/products/{id}
Authentication: Required (Access Token)
更新商品公开资料、媒体和 SKU。请求体只需传需要变更的商品字段;传入 skus 时必须提交更新后的完整 SKU 列表。spec_name 表示第一规格值,可选的 item_name 表示第二规格值;调用方不需要提交规格组或映射字段。
SKU 更新以 SKU UUID id 为准,不以 SKU 编号 sku 定位。新 SKU 省略 id;已有 SKU 必须提交商品详情返回的 id。SKU 编号由平台生成并维护,即使请求中提交 sku,服务端也会忽略该值:新 SKU 生成新编号,已有 SKU 保留平台当前编号。
更新字段采用以下语义:
- 请求体省略普通字段时保持当前值不变。
- 对允许为空的字段提交
null时清空当前值;各字段是否接受null以 Request Body 表为准。 poster_images、images、content_images和skus只要出现在请求中,就会完整替换对应当前列表;调用方应先读取商品详情并提交需要保留的完整内容。- 空图片数组表示清空对应图片列表;
skus至少保留一个项目,不接受空数组。
Path Parameters
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string(uuid) | 是 | 商品 ID |
Request Body
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 否 | 商品名称,1-130 字符 |
description | string | 否 | 商品详情 HTML,最长 60,000 字符 |
class_id | string | 否 | 平台类目代码 |
store_class_id | string | null | 否 | 店铺商品分类 ID;null 表示移出商品分类 |
stock_status | string | 否 | 3DAY 或 PRE_ORDER |
pre_order_ship_date | string | null | 条件必填 | 预购时为 YYMMDD;取消预购时传 null 或省略 |
sale_start_time | number | null | 否 | 指定销售开始时间,Unix 时间戳(秒,UTC 时间点);与结束时间一起传 null 可取消指定销售时间 |
sale_end_time | number | null | 否 | 指定销售结束时间,Unix 时间戳(秒,UTC 时间点),必须晚于开始时间;与开始时间一起传 null 可取消指定销售时间 |
poster_images | string[] | 否 | 商品海报图 URL,最多 3 张;传入时替换当前完整海报图列表,限制见“图片限制” |
images | string[] | 否 | 商品主图 URL,1-9 张;传入时替换当前完整主图列表,限制见“图片限制” |
content_images | string[] | 否 | 商品详情图 URL,最多 30 张;传入时替换当前完整详情图列表,限制见“图片限制” |
video_link | string | null | 否 | 商品视频 URL,露天用youtube url link |
skus | SkuInput[] | 否 | 完整 SKU 列表,1-450 项;双规格最多由 30 个第一规格值 × 15 个第二规格值组成 |
SkuInput
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string(uuid) | 条件必填 | 更新已有 SKU 时必填;创建新 SKU 时省略。必须属于当前商品且不得重复 |
spec_name | string | 是 | 第一规格值,去除首尾空白后 1-20 个字符;可完整填写 20 个繁体中文字;同一商品最多 30 个不同值,服务端据此生成第一规格组 |
item_name | string | null | 否 | 第二规格值,非空时 1-20 字符;每个 spec_name 最多对应 15 个不同值;使用双规格时每个 SKU 都必须提供非空值,服务端据此生成第二规格组 |
sku | string | null | 否 | 兼容输入字段,服务端忽略。SKU 编号始终由平台生成;调用方不得依赖请求中的值 |
custom_no | string | null | 否 | 露天卖家料号;非空时须为 1–100 个 ASCII 可见字符(U+0021–U+007E);null 表示清空,可按商品详情响应原样回传 |
taiwan_sale_price | string | 是 | TWD 主单位 decimal string,固定 2 位小数且必须为正整数金额,例如 1280.00 |
ruten_managed_distribution | boolean | 否 | 是否支持露天全托管,默认 false |
supply_price | string | null | 否 | 全托管供货价,TWD 主单位 decimal string,固定 2 位小数。开启全托管但省略或传 null 时,平台按售价的 65% 计算并四舍五入到 2 位;关闭全托管时固定为 null |
qty | number | 是 | 可售库存,0-99,999 的整数 |
status | boolean | 否 | 是否启用,默认 true |
image | string | null | 否 | SKU 图片 URL;每个 SKU 最多 1 张,限制见“图片限制” |
length | string | null | 否 | 包裹长度,单位 cm,正数 decimal string,最多 2 位小数 |
width | string | null | 否 | 包裹宽度,单位 cm,正数 decimal string,最多 2 位小数 |
height | string | null | 否 | 包裹高度,单位 cm,正数 decimal string,最多 2 位小数 |
weight | string | 是 | 单件包裹重量,单位 g,正数 decimal string,最多 2 位小数 |
规格组由服务端固定自动映射:spec_name 的去重值组成第一规格组“规格”,item_name 的去重值组成第二规格组“款式”。调用方不得把两个规格拼接进单个字段,也不需要提交 spec_groups。
SKU 名称长度:
spec_name的 20 字符上限按文字字符计算,不按 UTF-8 字节数计算,因此 20 个繁体中文字是合法值,第 21 个字符会返回 HTTP 400、code=validation_error。该长度上限与“最多 30 个不同spec_name”的数量上限是两项不同规则。
custom_no字符限制: 只允许正则/^[\x21-\x7e]{1,100}$/覆盖的 1–100 个 ASCII 可见字符。不得使用此范围外的字符;尤其不得使用看似规格写法、实际属于 Unicode 的分数字符(例如⅓、⅔),也不得包含中文、emoji 或空格。请改用 ASCII 表达,例如以2/3代替⅔。
EUR40/US8/25cm合法;EUR40⅔/US7.5/25.5cm、中文料号、SKU 001均非法。格式错误返回 HTTP 400、code=validation_error,data.issues[].path会指出对应的skus索引和custom_no字段。
- 单规格商品应省略
item_name或统一提交null,此时同一商品内spec_name不得重复。 - 双规格商品只要任一 SKU 提交非空
item_name,所有 SKU 都必须提交非空item_name。 - 双规格商品内
(spec_name, item_name)组合不得重复,并且必须提交两个规格值集合的完整笛卡尔积;例如 2 种颜色和 2 种容量必须提交 4 个 SKU。 - 同一商品的
spec_name去重后最多 30 个;每个spec_name对应的item_name去重后最多 15 个,因此完整双规格列表最多 450 个 SKU。 - 数量限制统计完整 SKU 列表,
status=false的停用 SKU 仍会提交给露天并计入限制。
ruten_managed_distribution 按 SKU 独立配置,同一商品可以只有部分 SKU 开启全托管。开启全托管的 SKU 未提供供货价时,服务端按该 SKU 的售价自动计算;更新已有 SKU 时,如果本次提交了新售价但省略供货价,也会按该 SKU 的新售价重新计算。Backend 会维护商品级内部聚合标记以兼容商品处理流程,但该标记不是 OpenAPI 的商品级配置项,调用方无需提交。
skus 是完整替换列表,处理规则如下:
- 带
id的项目更新对应已有 SKU;id不存在、不属于当前商品或在列表中重复时请求失败。 - 不带
id的项目创建新 SKU,并由平台生成 SKU 编号。 - 商品详情返回的
skus[].spec_id是露天规格 ID:spec_id !== null表示该 SKU 已经真实创建并上架到露天;尚未上架到露天时为null。 spec_id !== null的 SKU 均不得删除,即使商品或 SKU 当前已经下架。调用方必须继续在完整列表中提交其平台 SKU UUIDid;不再销售时将status设置为false。spec_id仅用于判断露天上架历史,更新 SKU 时仍以平台 SKU UUIDid定位,不得使用spec_id替代id。spec_id === null且没有历史发布记录的已有 SKU,未出现在完整列表中时会被删除。最终是否允许删除由服务端结合spec_id和历史发布记录校验,不能仅根据当前status或商品当前上下架状态判断。
Request Example
json
{
"poster_images": [
"https://static.sugumart.com/products/backpack-poster.jpg"
],
"images": [
"https://static.sugumart.com/products/backpack-front.jpg",
"https://static.sugumart.com/products/backpack-side.jpg"
],
"content_images": [
"https://static.sugumart.com/products/backpack-detail-1.jpg"
],
"skus": [
{
"spec_name": "黑色",
"item_name": "20L",
"taiwan_sale_price": "1280.00",
"ruten_managed_distribution": true,
"supply_price": "900.00",
"qty": 30,
"status": true,
"weight": "650.00"
},
{
"spec_name": "黑色",
"item_name": "28L",
"taiwan_sale_price": "1580.00",
"ruten_managed_distribution": true,
"supply_price": "1100.00",
"qty": 20,
"status": true,
"weight": "780.00"
},
{
"spec_name": "卡其色",
"item_name": "20L",
"taiwan_sale_price": "1280.00",
"ruten_managed_distribution": false,
"qty": 15,
"status": true,
"weight": "650.00"
},
{
"spec_name": "卡其色",
"item_name": "28L",
"taiwan_sale_price": "1580.00",
"ruten_managed_distribution": false,
"qty": 10,
"status": true,
"weight": "780.00"
}
]
}上例为首次配置 SKU,因此各项均省略 id。修改已有 SKU 时应使用商品详情返回的 UUID;例如将一个曾经上架的 SKU 停用:
json
{
"skus": [
{
"id": "0e95a8db-9161-4b39-b77a-2bd796f27715",
"spec_name": "黑色",
"taiwan_sale_price": "1280.00",
"ruten_managed_distribution": true,
"supply_price": "900.00",
"qty": 30,
"status": false,
"weight": "650.00"
}
]
}示例为简化展示。实际请求的
skus必须包含商品更新后需要保留的全部 SKU;不得遗漏任何曾经上架过的 SKU。
Response
| 字段 | 类型 | 说明 |
|---|---|---|
product | Product | 更新后的商品 |
Response Example
json
{
"success": true,
"data": {
"product": {
"id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "draft",
"review_status": "draft",
"name": "轻量防泼水通勤背包",
"images": [
"https://static.sugumart.com/products/backpack-front.jpg"
],
"content_images": [
"https://static.sugumart.com/products/backpack-detail-1.jpg"
],
"skus": [
{
"id": "0e95a8db-9161-4b39-b77a-2bd796f27715",
"sku": "BAG-BLK-20",
"spec_name": "黑色",
"taiwan_sale_price": "1280.00",
"ruten_managed_distribution": true,
"supply_price": "900.00",
"qty": 30,
"status": true,
"weight": "650.00"
}
],
"updated_at": "2026-08-04T08:40:00.000Z"
}
}
}Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Invalid product or SKU data | validation_error | 字段、规格名称、价格、库存或尺寸校验失败 |
| 400 | Category is not selectable | category_not_selectable | class_id 是中间类目或仍有启用子节点,不能用于商品发布 |
| 400 | SKU structure is locked | sku_structure_locked | 已发布商品不允许破坏已有露天规格结构 |
| 400 | Published SKU cannot be deleted | cannot_delete_published_sku | 尝试删除任何曾经上架过的 SKU;应保留其 id 并将 status 设置为 false |
| 400 | Invalid SKU ID | invalid_sku_id | SKU id 不存在、不属于当前商品或在请求列表中重复 |
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
| 404 | Product not found | not_found | 商品不存在或不属于当前租户 |
| 409 | Product review state changed | product_review_state_changed | 保存期间审核状态已变化,应重新查询后再提交 |
提交商品审核(第四步)
POST /openapi/v1/products/{id}/submit
Authentication: Required (Access Token)
提交商品进入平台审核。服务端会校验基本信息、类目、媒体、SKU、价格、库存和重量。内部发布字段由平台补齐,不要求调用方提交。
商品审核事件的回调投递尚未开放。调用方应通过商品详情接口查询最新审核状态;回调投递、签名与重试能力以后续发布公告为准。
Path Parameters
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string(uuid) | 是 | 商品 ID |
Request Body
无。
Response
| 字段 | 类型 | 说明 |
|---|---|---|
product | Product | 已提交审核的商品,status=pending_review、review_status=pending |
submitted_at | string | 提交审核时间,ISO 8601 UTC |
Response Example
json
{
"success": true,
"data": {
"product": {
"id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "pending_review",
"review_status": "pending",
"name": "轻量防泼水通勤背包"
},
"submitted_at": "2026-08-04T08:45:00.000Z"
}
}Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Product information is incomplete | product_incomplete | 基本信息、媒体、规格或 SKU 不完整 |
| 400 | Product main images cannot exceed 9 | product_main_image_limit_exceeded | 商品主图超过 9 张;删除多余主图后再提交 |
| 400 | Product cannot be submitted | invalid_state | 当前商品状态不允许提交 |
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
| 404 | Product not found | not_found | 商品不存在或不属于当前租户 |
上架商品
POST /openapi/v1/products/{id}/online
Authentication: Required (Access Token)
将审核通过的商品恢复至线上销售。
Path Parameters
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string(uuid) | 是 | 商品 ID |
Response
| 字段 | 类型 | 说明 |
|---|---|---|
product | Product | 上架后的商品,status=migrated |
Response Example
json
{
"success": true,
"data": {
"product": {
"id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "migrated",
"review_status": "approved",
"ruten_item_id": "22408041234567",
"updated_at": "2026-08-05T02:10:00.000Z"
}
}
}Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Product is not approved | invalid_state | 商品尚未审核通过或当前状态不可上架 |
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
| 404 | Product not found | not_found | 商品不存在 |
| 502 | Ruten publish failed | ruten_provider_error | 露天拒绝发布或响应不可用 |
下架商品
POST /openapi/v1/products/{id}/offline
Authentication: Required (Access Token)
将线上商品下架。
Path Parameters
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string(uuid) | 是 | 商品 ID |
Response
| 字段 | 类型 | 说明 |
|---|---|---|
product | Product | 下架后的商品,status=offline |
Response Example
json
{
"success": true,
"data": {
"product": {
"id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "offline",
"review_status": "approved",
"ruten_item_id": "22408041234567",
"updated_at": "2026-08-06T04:30:00.000Z"
}
}
}Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Product is not online | invalid_state | 商品当前不在线 |
| 401 | Invalid or expired token | unauthorized | Access Token 无效或已过期 |
| 404 | Product not found | not_found | 商品不存在 |
| 502 | Ruten offline request failed | ruten_provider_error | 露天拒绝下架或响应不可用 |
异步整合创建商品
POST /openapi/v1/product-create-tasks
Authentication: Required (Access Token)
一次提交第一步基本资料与第三步媒体、SKU 资料。接口在同一事务中创建商品草稿和异步任务,并立即返回商品 ID 与任务 ID。商品固定保持 draft;任务成功后仍需显式调用提交审核接口。
图片 URL 可以来自当前平台 CDN、其他商品的公开 S3 路径或外部 HTTP/HTTPS 服务。后台会验证、下载图片,并归档到当前商品专属 S3 路径。description 内的 HTML 图片和 video_link 不会被下载或重写。不支持为来源 URL 提供自定义鉴权 Header。
Headers
| Header | 必填 | 说明 |
|---|---|---|
Idempotency-Key | 否 | 1-255 字符。同一租户使用相同键和相同请求时返回原任务;相同键对应不同请求时返回 409 idempotency_conflict |
Request Body
基本资料字段与“创建商品(第一步)”相同;媒体与 SKU 字段沿用“更新商品(第三步)”的格式和金额、单位规则,区别如下:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 商品名称,1-130 字符 |
description | string | 是 | 商品详情 HTML,最长 60,000 字符 |
class_id | string | 是 | 可发布的平台类目代码 |
store_class_id | string | null | 否 | 店铺商品分类 ID |
stock_status | string | 否 | 3DAY 或 PRE_ORDER,默认 3DAY |
pre_order_ship_date | string | null | 条件必填 | 预购时格式为 YYMMDD |
sale_start_time | number | null | 否 | Unix 时间戳(秒),必须与结束时间一起提交 |
sale_end_time | number | null | 否 | Unix 时间戳(秒),必须晚于开始时间 |
poster_images | string[] | 否 | 0-3 个 HTTP/HTTPS 图片 URL |
images | string[] | 是 | 1-9 个 HTTP/HTTPS 主图 URL |
content_images | string[] | 否 | 0-30 个 HTTP/HTTPS 详情图 URL |
video_link | string | null | 否 | 原值保存,不执行下载 |
skus | SkuInput[] | 是 | 完整 SKU 列表,1-450 项;遵循 30 个 spec_name、每个 spec_name 最多 15 个 item_name 的限制;新建任务不接受 SKU id |
json
{
"name": "轻量防泼水通勤背包",
"description": "<p>适合日常通勤使用的轻量背包。</p>",
"class_id": "00110001",
"stock_status": "3DAY",
"images": [
"https://supplier.example.com/backpack/front.jpg"
],
"content_images": [],
"skus": [
{
"spec_name": "黑色",
"item_name": "20L",
"taiwan_sale_price": "1280.00",
"qty": 30,
"status": true,
"weight": "650.00",
"image": "http://supplier.example.com/backpack/black.jpg"
}
]
}Response (202 Accepted)
json
{
"success": true,
"data": {
"product_id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"task_id": "3ea50b94-13e3-468a-a68b-f0ac12ecfb73",
"status": "queued",
"created_at": "2026-08-17T08:30:00.000Z"
}
}任务入队失败时商品草稿仍会保留,响应中的状态可以直接为 failed。调用方随后可使用商品详情、媒体上传和商品更新接口补充资料。
Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Invalid product creation task | validation_error | 请求字段、图片数量、SKU 或幂等键格式错误 |
| 400 | Category is not selectable | category_not_selectable | 类目不可发布 |
| 401 | Invalid or expired token | invalid_token | Access Token 无效或过期 |
| 404 | Product category not found | category_not_found | 类目不存在或已停用 |
| 404 | Store class not found | store_class_not_found | 店铺分类不属于当前租户 |
| 409 | Idempotency key conflicts with another request | idempotency_conflict | 相同幂等键已用于不同请求 |
查询异步创建任务
GET /openapi/v1/product-create-tasks/{task_id}
Authentication: Required (Access Token)
任务只能由所属租户查询。任务状态为:
| 状态 | 说明 |
|---|---|
queued | 已建立商品草稿,等待后台处理 |
processing | 正在验证、下载或归档资源 |
succeeded | 所有资源归档成功,资料已写入商品草稿 |
partially_succeeded | 部分资源失败,其余资料和成功资源已写入商品草稿 |
failed | 队列、商品并发修改或最终保存失败;商品草稿仍然保留 |
json
{
"success": true,
"data": {
"task": {
"id": "3ea50b94-13e3-468a-a68b-f0ac12ecfb73",
"product_id": "a7b3c8df-bb08-46f0-9ca2-5597a32e0404",
"status": "partially_succeeded",
"total_resource_count": 2,
"succeeded_resource_count": 1,
"failed_resource_count": 1,
"error_code": null,
"error_message": null,
"created_at": "2026-08-17T08:30:00.000Z",
"started_at": "2026-08-17T08:30:01.000Z",
"completed_at": "2026-08-17T08:30:04.000Z",
"updated_at": "2026-08-17T08:30:04.000Z"
},
"resources": [
{
"id": "125b1d3c-b53d-4a15-9522-b0d14d411e99",
"field_path": "images[0]",
"purpose": "main",
"source_url": "https://supplier.example.com/backpack/front.jpg",
"result_url": "https://static.sugumart.com/public/openapi/products/example/main/result.jpg",
"status": "succeeded",
"error_code": null,
"error_message": null
}
]
}
}资源失败不会回写原始外链。成功资源使用 result_url;失败的列表图片会被移除,失败的 SKU 图片保存为空。若商品在任务处理期间已通过普通接口修改,任务以 product_changed 失败且不会覆盖新资料。任务不提供重试或取消接口。
Error Responses
| Status | message | code | 说明 |
|---|---|---|---|
| 400 | Invalid task ID | validation_error | 任务 ID 不是 UUID |
| 401 | Invalid or expired token | invalid_token | Access Token 无效或过期 |
| 404 | Product creation task not found | not_found | 任务不存在或不属于当前租户 |
公共响应字段
ProductSummary
商品列表返回摘要对象,不包含 description、完整媒体列表和 skus。需要完整资料时调用商品详情接口。
| 字段 | 类型 | 说明 |
|---|---|---|
id | string(uuid) | 商品 ID |
status | string | V1 商品生命周期状态 |
review_status | string | 审核状态:draft、pending、approved、rejected |
name | string | 商品名称 |
class_id | string | 平台类目代码 |
images | string[] | 商品主图;列表响应只保证包含首张主图,暂无图片时为空数组 |
sku_count | number | 未删除 SKU 总数,非负整数 |
active_sku_count | number | 已启用 SKU 数量,非负整数 |
total_quantity | number | 已启用 SKU 的可售库存合计,非负整数 |
ruten_item_id | string | null | 露天商品编号;尚未发布时为 null |
created_at | string | 创建时间,ISO 8601 UTC |
updated_at | string | 更新时间,ISO 8601 UTC |
Product
| 字段 | 类型 | 说明 |
|---|---|---|
id | string(uuid) | 商品 ID |
status | string | V1 商品生命周期状态 |
review_status | string | 审核状态:draft、pending、approved、rejected |
rejected_reason | string | null | 审核拒绝原因 |
name | string | 商品名称 |
description | string | null | 商品详情 HTML |
class_id | string | 平台类目代码 |
store_class_id | string | null | 店铺商品分类 ID |
stock_status | string | 3DAY 或 PRE_ORDER |
pre_order_ship_date | string | null | 预购出货日期,格式 YYMMDD |
sale_start_time | number | null | 指定销售开始时间,Unix 时间戳(秒,UTC 时间点);未指定时为 null |
sale_end_time | number | null | 指定销售结束时间,Unix 时间戳(秒,UTC 时间点);未指定时为 null |
poster_images | string[] | 商品海报图,最多 3 张;格式、大小和尺寸限制见“图片限制” |
images | string[] | 商品主图,最多 9 张;提交审核时至少 1 张 |
content_images | string[] | 商品详情图,最多 30 张;格式、大小和尺寸限制见“图片限制” |
video_link | string | null | 商品视频 URL |
skus | Sku[] | SKU 列表 |
sku_count | number | 未删除 SKU 总数 |
active_sku_count | number | 已启用 SKU 数量 |
total_quantity | number | 已启用 SKU 的可售库存合计 |
ruten_item_id | string | null | 露天商品编号;尚未发布时为 null |
submitted_at | string | null | 最近提交审核时间,ISO 8601 UTC |
approved_at | string | null | 最近审核通过时间,ISO 8601 UTC |
created_at | string | 创建时间,ISO 8601 UTC |
updated_at | string | 更新时间,ISO 8601 UTC |
Sku
| 字段 | 类型 | 说明 |
|---|---|---|
id | string(uuid) | SKU ID;更新已有 SKU 时使用的唯一定位依据 |
sku | string | 平台生成的只读 SKU 编号;不接受调用方修改 |
custom_no | string | null | 露天卖家料号;非空时为 1–100 个 ASCII 可见字符(U+0021–U+007E) |
spec_id | string | null | 露天规格 ID;尚未发布时为 null |
spec_name | string | 第一规格值 |
item_name | string | null | 第二规格值;单规格商品为 null |
taiwan_sale_price | string | null | TWD 主单位正整数金额,以固定 2 位小数字符串返回;尚未完成 SKU 配置的草稿可能为 null,提交 SKU 更新时仍为必填 |
ruten_managed_distribution | boolean | 是否支持露天全托管 |
supply_price | string | null | 全托管供货价;TWD 主单位 decimal string,固定 2 位小数;未提交时按售价的 65% 计算,不支持全托管时为 null |
qty | number | 可售库存,0-99,999 |
status | boolean | SKU 是否启用 |
image | string | null | SKU 图片 URL;格式、大小和尺寸限制见“图片限制” |
length | string | null | 包裹长度,单位 cm,最多 2 位小数 |
width | string | null | 包裹宽度,单位 cm,最多 2 位小数 |
height | string | null | 包裹高度,单位 cm,最多 2 位小数 |
weight | string | null | 单件包裹重量,单位 g,最多 2 位小数;尚未完成 SKU 配置的草稿可能为 null,提交 SKU 更新时仍为必填 |
created_at | string | 创建时间,ISO 8601 UTC |
updated_at | string | 更新时间,ISO 8601 UTC |