概览
所有开放接口使用 /api/v1/*。旧 open_* 路由不再提供兼容。
基础地址
将 https://shop.example.com 替换成商城绑定域名。例如:https://shop.example.com/api/v1/goods
响应格式
{
"code": 0,
"goods": { "id": 1001, "status": 0 }
}
code = 0 表示成功;失败时 code = 1,并返回 msg。认证、权限、参数和资源错误同时使用相应 HTTP 状态码。
认证签名
每个请求必须带以下 HTTP Header:
| Header | 说明 |
|---|---|
X-Shop-Key | 后台创建的 API Key。 |
X-Shop-Timestamp | Unix 秒级时间戳,服务器允许前后 300 秒。 |
X-Shop-Nonce | 每次请求唯一的随机字符串。重复 nonce 会被拒绝。 |
X-Shop-Signature | 使用 Secret 计算的 HMAC-SHA256 小写十六进制结果。 |
Content-Type | 带 JSON Body 的请求使用 application/json。 |
待签名字符串必须严格使用以下五段内容和换行符:
UPPERCASE_METHOD + "\n" +
PATH_WITH_RAW_QUERY + "\n" +
TIMESTAMP + "\n" +
NONCE + "\n" +
RAW_REQUEST_BODY
/api/v1/orders?updated_since=... 时,实际请求的参数顺序和编码必须完全一致。GET 请求的 Body 为空字符串。PHP 签名示例
$method = 'GET';
$path = '/api/v1/orders?updated_since=1780000000&limit=20';
$timestamp = (string) time();
$nonce = bin2hex(random_bytes(16));
$body = '';
$secret = '在后台保存的 Secret';
$string = strtoupper($method) . "\n" . $path . "\n" . $timestamp . "\n" . $nonce . "\n" . $body;
$signature = hash_hmac('sha256', $string, $secret);
$headers = [
'X-Shop-Key: ' . $apiKey,
'X-Shop-Timestamp: ' . $timestamp,
'X-Shop-Nonce: ' . $nonce,
'X-Shop-Signature: ' . $signature,
];
权限范围
| Scope | 能力 |
|---|---|
orders.read | 读取订单及订单详情。 |
orders.ship | 回传实物订单物流并标记发货。 |
payments.read | 读取支付流水。 |
goods.read | 读取商品列表及详情。 |
goods.write | 创建或更新商品。新商品默认保存为草稿。 |
goods.publish / goods.unpublish | 独立执行商品上架、下架。 |
categories.read | 读取频道和分类。 |
inventory.read / inventory.write | 读取或更新商品、SKU 库存。 |
leads.read / leads.write | 读取或更新客户线索状态、负责人和备注。 |
接口目录
| 方法 | 路径 | Scope | 用途 |
|---|---|---|---|
| GET | /api/v1/categories | categories.read | 读取当前可访问频道及分类。 |
| GET | /api/v1/goods | goods.read | 商品列表,支持 page、limit、status、channel_id、updated_since。 |
| GET | /api/v1/goods/{id_or_goods_no} | goods.read | 读取商品详情。 |
| POST / PUT | /api/v1/goods 或 /api/v1/goods/{id} | goods.write | 创建或更新商品。以 goods_no 作为外部稳定编码;新建默认草稿。 |
| POST | /api/v1/goods/{id}/publish | goods.publish | 上架商品。 |
| POST | /api/v1/goods/{id}/unpublish | goods.unpublish | 下架商品。 |
| GET | /api/v1/inventory?goods_id={id} | inventory.read | 读取商品和 SKU 库存。 |
| PUT / PATCH | /api/v1/inventory | inventory.write | 更新普通商品库存,或指定 sku_key 更新 SKU 库存。 |
| GET | /api/v1/orders | orders.read | 订单列表,支持 pay_status、order_status、updated_since。 |
| GET | /api/v1/orders/{order_no} | orders.read | 读取订单、明细与收货地址。 |
| POST | /api/v1/orders/{order_no}/ship | orders.ship | 回传物流单号。只允许已付款的实物订单。 |
| GET | /api/v1/payments | payments.read | 读取支付流水。 |
| GET | /api/v1/leads | leads.read | 读取线索,支持 status、updated_since。 |
| GET | /api/v1/leads/{id} | leads.read | 读取单条线索详情。 |
| PUT / PATCH | /api/v1/leads/{id} | leads.write | 更新线索状态、负责人和处理备注。 |
调用示例
创建商品草稿
POST /api/v1/goods
{
"goods_no": "ERP-10001",
"channel_id": 3,
"cate_id": 12,
"name": "示例商品",
"currency": "USD",
"price": 19.90,
"market_price": 29.90,
"stock": 100,
"thumb": "/webdata/shop/images/example.jpg",
"images": ["/webdata/shop/images/example.jpg"],
"sku": { "specs": [], "rows": [], "single": { "sn": "ERP-10001" } },
"goods_type": 1,
"shipping_template": "default"
}
创建后返回的 status 为 0。完成资料校验后,再以独立权限调用上架接口。
上架商品
POST /api/v1/goods/1001/publish
{}
更新 SKU 库存
PUT /api/v1/inventory
{
"goods_id": 1001,
"sku_key": "Red|M",
"stock": 36
}
回传物流
POST /api/v1/orders/ORD202608090001/ship
{
"track_company": "DHL",
"track_no": "JD014600006281234567"
}
远程图片导入
商品接口不会同步下载外部图片。先创建导入任务,等待任务完成后再把返回的媒体 ID 写入商品;这样商品不会因下载超时而写入半成品。
1. 创建导入任务
POST /api/v1/media
{
"url": "https://cdn.example.com/products/10001/main.jpg",
"channel_id": 3
}
需要 media.write 权限。一次最多提交 20 个 URL,也可以使用 urls 数组批量提交。
2. 查询任务
GET /api/v1/media/mi_xxxxxxxxxxxxxxxxxxxxxxxx
任务状态为 completed 时,响应中的 media_id 和 local_url 才可使用。pending、processing、retrying 时应继续轮询;failed 时检查 error_code 后修正 URL。
3. 引用本地媒体
PATCH /api/v1/goods/1001
{
"thumb_media_id": "med_...",
"image_media_ids": ["med_...", "med_..."]
}
媒体必须处于完成状态且属于同一频道。系统会将媒体 ID 转为本地地址后保存到商品,不会在商品中保留远程 URL。
Webhook
在商城后台为全局或频道配置 Webhook 地址和订阅事件。投递为 JSON POST,Header 包含 X-Shop-Event、X-Shop-Event-Id、X-Shop-Timestamp 和 X-Shop-Signature。
签名字符串为 timestamp + "\n" + raw_body,使用 Webhook Secret 计算 HMAC-SHA256。接收方应使用 event_id 去重。
| 类别 | 事件 |
|---|---|
| 订单 | order.created、order.paid、order.cancelled、order.shipped、order.refund_requested |
| 商品和库存 | goods.created、goods.updated、goods.published、goods.unpublished、stock.changed、stock.low |
| 线索 | lead.created、lead.updated |
| 其他 | payment.abnormal、digital.delivered 及运营预警事件。 |
排错说明
| HTTP 状态 | 常见原因 | 处理方式 |
|---|---|---|
| 401 | 缺少 Header、签名不一致、时间戳超时或 nonce 重复。 | 确认原始 Body、路径与 query、时间戳和 nonce 均未被代理改写。 |
| 403 | Key 已停用或 Scope 不足。 | 在后台检查 Key 状态和权限范围。 |
| 404 | 资源不存在,或不属于当前频道 Key 的范围。 | 确认资源 ID、商品频道和 Key 范围。 |
| 409 | 商品编码冲突、订单状态冲突或不能发货。 | 先读取最新资源状态,再决定是否重试。 |
| 422 | 字段缺失、分类不匹配、SKU 不存在或状态不合法。 | 根据 msg 修正请求字段。 |
| 503 | nonce Redis 或线索数据表不可用。 | 稍后重试,并检查商城基础服务状态。 |
