开放API接入文档 v1.0
面向租户自研系统(App / 小程序 / 自有系统)的标准化接入指南
简介
开放API允许租户通过标准 HTTP 接口驱动商城中台业务,实现商品查询、订单管理、售后处理、用户管理和营销功能,无需依赖中台托管的 H5/PC 商城前端。发货与售后状态变化另见左侧「消息推送」:由平台主动 POST 到接入方 URL,不是再调一组查询接口。
先选接入方式
| 你要做的 | 看哪份文档 |
|---|---|
| 自建 App / 小程序 / 后台,自己调商品、下单、售后 | 本文(开放API) |
| 已有企业商城,嵌一条可装修的完整福利商城 | 《对外H5链接(托管商城)》 |
| 直接用品牌落地页(淘宝闪购、淘票票、好食期券码) | 找运营开通,阅读 《H5 接入说明》 |
接口基础信息
| 项目 | 说明 |
|---|---|
| Base URL | http://mall.hzkting.com:9988/open/api/v1 |
| 协议 | HTTP |
| 数据格式 | JSON(Content-Type: application/json) |
| 字符编码 | UTF-8 |
接入流程
- 联系平台运营,在管理后台创建开放应用,获取
AppKey和AppSecret - 根据业务需要申请对应的权限范围(PermScope)
- 在沙箱模式下完成接口联调测试
- 测试通过后,由运营人员审核升级为生产模式
权限范围(PermScope)
| 权限值 | 说明 | 覆盖接口 |
|---|---|---|
PRODUCT_READ | 商品查询 | 商品列表、详情、价格、库存、分类 |
ORDER_WRITE | 订单写入 | 创建订单、取消订单 |
ORDER_READ | 订单查询 | 订单详情、列表、物流 |
AFTERSALE | 售后管理 | 申请售后、查询、取消 |
USER | 用户管理 | 注册、登录、个人信息、收货地址 |
PROMOTION | 营销 | 优惠券列表、领取 |
FINANCE | 资金流 | 账户余额、资金流水、结算账单、提现 |
FILM | 电影票 | 淘票票影片、场次、下单 |
AI_CHAT | AI对话 | 同步/流式选品对话 |
/notify/config)与租户配置相同,只需有效 AppKey,无需额外 PermScope。签名鉴权
所有接口请求必须携带以下三个请求头:
| 请求头 | 说明 | 示例 |
|---|---|---|
X-App-Key | 应用标识,由平台分配 | a1b2c3d4e5f6... |
X-Timestamp | Unix 时间戳(秒),与服务器时差不超过 300 秒 | 1745548800 |
X-Sign | 请求签名,见下方签名算法 | A3F2B1C4... |
签名算法
- 收集所有请求参数:URL Query 参数 + JSON Body 顶层字段(嵌套对象不参与签名,空值字段跳过)
- 将参数按 key 字母升序排列,拼接为
key1=value1&key2=value2&... - 末尾追加
&app_secret={AppSecret} - 对拼接字符串执行 MD5,结果转大写即为签名值
拼接:
page=1&product_id=123&app_secret=mysecret签名:
MD5("page=1&product_id=123&app_secret=mysecret").toUpperCase()Java 示例
public static String sign(Map<String, String> params, String appSecret) {
TreeMap<String, String> sorted = new TreeMap<>(params);
StringBuilder sb = new StringBuilder();
sorted.forEach((k, v) -> {
if (v != null && !v.isEmpty()) {
if (sb.length() > 0) sb.append("&");
sb.append(k).append("=").append(v);
}
});
sb.append("&").append("app_secret=").append(appSecret);
return DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8)).toUpperCase();
}
Python 示例
import hashlib
def sign(params: dict, app_secret: str) -> str:
items = sorted((k, v) for k, v in params.items() if v)
query = "&".join(f"{k}={v}" for k, v in items)
query += f"&app_secret={app_secret}"
return hashlib.md5(query.encode()).hexdigest().upper()
完整 curl 示例
# 1. 拼接签名字符串:pageNo=1&app_secret=mysecret
# 2. 计算签名:MD5("pageNo=1&app_secret=mysecret").toUpperCase()
# 3. 发起请求:
curl -X GET "http://mall.hzkting.com:9988/open/api/v1/products?pageNo=1" \
-H "X-App-Key: abc123" \
-H "X-Timestamp: 1745548800" \
-H "X-Sign: D41D8CD98F00B204E9800998ECF8427E"
消费者 Token(X-User-Token)
用户登录成功后,响应体中返回 user_token。后续调用需要消费者身份的接口时,需在请求头中携带:
| 请求头 | 说明 |
|---|---|
X-User-Token | 用户登录后获取的 Token,有效期 7 天 |
统一响应格式
所有接口均返回以下 JSON 结构:
{
"code": 0, // 0=成功,非0=失败
"message": "success",
"data": { ... }, // 业务数据,失败时为 null
"is_sandbox": false // true 表示沙箱模式响应
}
| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 0 表示成功,非 0 表示失败,见错误码表 |
message | string | 成功时为 "success",失败时为错误描述 |
data | object/null | 业务数据 |
is_sandbox | boolean | 沙箱模式下写单操作返回 true |
错误码
| HTTP | code | 错误码 | 说明 |
|---|---|---|---|
| 400 | 1001 | MISSING_HEADER | 缺少必要请求头 X-App-Key / X-Timestamp / X-Sign |
| 401 | 1002 | SIGN_INVALID | 签名错误或应用不存在 |
| 401 | 1003 | TIMESTAMP_EXPIRED | 时间戳与服务器时差超过 5 分钟 |
| 401 | 1004 | USER_TOKEN_INVALID | X-User-Token 无效或已过期 |
| 403 | 1005 | IP_FORBIDDEN | 请求 IP 不在白名单 |
| 403 | 1006 | PERMISSION_DENIED | 应用无该接口的权限范围 |
| 403 | 1007 | APP_DISABLED | 应用已停用 |
| 403 | 1008 | TENANT_DISABLED | 租户已停用 |
| 403 | 1009 | PRODUCT_NOT_AUTHORIZED | 商品不在租户授权范围 |
| 403 | 1010 | ORDER_NOT_AUTHORIZED | 订单不属于当前租户 |
| 403 | 1011 | AFTERSALE_NOT_AUTHORIZED | 售后单不属于当前租户 |
| 409 | 1012 | PHONE_ALREADY_EXISTS | 手机号已注册 |
| 409 | 1013 | COUPON_ALREADY_CLAIMED | 优惠券已领取 |
| 400 | 1014 | COUPON_UNAVAILABLE | 优惠券不可用或已过期 |
| 429 | 1015 | RATE_LIMIT_EXCEEDED | 调用频率超限(默认 60 次/分钟),或商品读并发已满(全局 20 / 单租户 4) |
| 403 | 1016 | FINANCE_NOT_AUTHORIZED | 账单或提现记录不属于当前租户 |
| 502 | 2001 | UPSTREAM_ERROR | 上游平台调用失败 |
| 500 | 9999 | INTERNAL_ERROR | 系统内部错误 |
商品接口
所有商品接口需要 PRODUCT_READ 权限。
1. 拿货价:
salePrice(商品级)与详情里的 skuDetail[].price / skuDetail[].tenantPrice(SKU级)——
这是贵司的采购结算价,商品级与 SKU 级数值口径一致,下单结算以此为准;贵司终端售价请在此基础上自行加价。2. 建议零售价:
marketPrice(商品级)与详情里的 skuDetail[].reservePrice(SKU级,仅部分渠道如天猫超市返回)——
上游建议零售价,仅供参考展示,切勿当作拿货价或结算价使用;系统保证其非空时不低于对应拿货价,为空时请勿展示。3.
costPrice:保留字段,OpenAPI 不返回(恒为 null)。4. 商品列表默认不返回
skuDetail(字段为 null)。规格请调 GET /open/api/v1/products/{productId};若列表必须带 SKU,传 includeSkuDetail=true。前端展示 SKU 价格时请固定读取
skuDetail[].price,不要读 reservePrice。
saasCategoryId 为准):·
saasCategoryId:中台类目单个 ID(/saas-categories 返回的 id);·
saasCategoryIdList:中台类目多个 ID(可勾选多个节点);·
categoryCode:中台类目编码(/saas-categories 返回的 categoryCode,如 food)。均按「该类目及其所有子类目」范围过滤;传入未知/停用的编码时返回空列表。
null)。规格请调详情接口。需要列表带 SKU 时传 includeSkuDetail=true(与历史列表一致,报文更大)。
响应示例
{"code":0,"data":{"total":100,"pageNo":1,"pageSize":20,"products":[{"unifiedProductId":"123456","productName":"京东京造示例商品","brandName":"京东京造","brandTag":"JD_JINGZAO","salePrice":99.00,"mainImage":"https://...","status":"ON_SALE"}]}}
响应示例
{"code":0,"data":{"unifiedProductId":"123456","platformProductId":"SKU001","productName":"示例商品","brandName":"品牌A","category":"食品","salePrice":99.00,"marketPrice":128.00,"costPrice":null,"mainImage":"https://...","status":"ON_SALE","stockStatus":"IN_STOCK","stockNum":500,
"skuDetail":"[{\"skuId\":\"SKU001\",\"specName\":\"规格A\",\"price\":99.00,\"tenantPrice\":99.00,\"reservePrice\":128.00,\"images\":[\"https://...\"]}]",
"skuStockDetail":"[{\"skuId\":\"SKU001\",\"quantity\":\"500\",\"stockTagCode\":\"NORMAL\",\"stockTagName\":\"有货\",\"hasStock\":true,\"specName\":\"规格A\"}]"}}
price/tenantPrice=99.00 是拿货价,reservePrice=128.00 是建议零售价(仅部分渠道返回);页面取价请固定用 price。Query 参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| areaCode | string | 可选 | 区域编码(省_市_区_镇),用于区域差价 |
响应示例
{"code":0,"data":{"productId":"123456","salePrice":99.00,"costPrice":null,"marketPrice":128.00,"skuPrices":{"SKU001":99.00}}}
salePrice 与 skuPrices 均为拿货价;marketPrice 为建议零售价,仅供展示。Query 参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| areaCode | string | 可选 | 区域编码 |
响应示例
{"code":0,"data":{"productId":"123456","hasStock":true,"stockNum":500,"areaCode":"1_72_2799_0"}}
返回中台全部启用类目(status=ENABLED),按 parentId 组装为树形结构。用于客户端展示中台类目、与商品接口返回的 saasCategoryId 对应。
PRODUCT_READ 权限。可加 ?flat=true 返回平铺列表(不组树,children 恒为空)。响应示例
{
"code": 0,
"data": [
{
"id": 3,
"categoryCode": "food",
"categoryName": "食品",
"parentId": 0,
"sortOrder": 0,
"icon": null,
"children": [
{"id": 31, "categoryCode": "food_snack", "categoryName": "休闲零食", "parentId": 3, "sortOrder": 0, "icon": null, "children": []}
]
}
]
}
订单接口
创建/取消订单需要 ORDER_WRITE 权限;查询订单需要 ORDER_READ 权限。
请求示例
{
"products": [
{"platformProductId": "1008814639745", "skuId": "6010122344404", "quantity": 1, "price": 28.9}
],
"address": {
"receiverName": "张三",
"receiverMobile": "13800138000",
"province": "北京市",
"city": "北京市",
"district": "朝阳区",
"detailAddress": "xxx路xxx号",
"fullAddress": "北京市朝阳区xxx路xxx号"
},
"areaCode": "110105",
"paymentType": 4,
"buyerRemark": "请尽快发货",
"customerOrderNo": "CUSTOM-20260506-001"
}
响应示例
{"code":0,"data":{"orderSn":"SO20260425143000T001ABC123","orderId":1,"tenantAmount":66.00,"status":"CREATED"},"is_sandbox":false}
// 沙箱模式响应:
{"code":0,"data":{"orderSn":"SANDBOX_D0C35852DB854C05","orderId":1,"status":"CREATED","receiverName":"张三","receiverPhone":"13800138000","receiverAddress":"北京市朝阳区xxx路xxx号"},"is_sandbox":true}
{ "reason": "取消原因" }。响应示例
{"code":0,"data":{"orderSn":"SO20260425143000T001ABC123","status":"CANCELLED"}}
响应示例
{"code":0,"data":{"order":{"id":1,"orderSn":"SO20260425...","status":"CREATED","tenantAmount":66.00,"freightAmount":0.00,"receiverName":"张三","orderTime":"2026-04-25T14:30:00"},"items":[{"productId":123,"productName":"示例商品","quantity":1,"tenantPrice":66.00}]}}
tenantAmount/items[].tenantPrice 为贵司应付结算金额/单价,与商品接口拿货价同口径。consumerId 为额外查询参数(非 DTO 字段),可按消费者ID筛选;订单状态见 status 枚举。响应示例
{"code":0,"data":{"total":50,"pageNo":1,"pageSize":20,"orders":[{"unifiedOrderId":"1","platformOrderId":"JD001","totalAmount":60.00,"status":"CREATED","orderTime":"2026-04-25T14:30:00"}]}}
响应示例
{"code":0,"data":{"logisticsCompany":"顺丰速运","waybillNo":"SF1234567890","status":"IN_TRANSIT","tracks":[{"time":"2026-04-25 10:00:00","content":"已揽收"}]}}
售后接口
所有售后接口需要 AFTERSALE 权限。
售后类型(type)可选值
| 枚举值 | 说明 |
|---|---|
REFUND_ONLY | 仅退款 |
RETURN_REFUND | 退货退款 |
EXCHANGE | 换货 |
REPAIR | 维修 |
申请原因编码(reasonCode)可选值
| 编码 | 含义 |
|---|---|
QUALITY_ISSUE | 质量问题 |
NOT_AS_DESCRIBED | 与描述不符 |
DAMAGED | 商品损坏 |
WRONG_ITEM | 发错商品 |
NO_LONGER_NEEDED | 不再需要 |
{afterSaleSn, type, status};下方响应字段为生产模式(AfterSaleCreateResult)。请求示例
{
"platformOrderId": "SANDBOX_CE3C017EF6FE4FB5",
"type": "REFUND_ONLY",
"reasonCode": "NO_LONGER_NEEDED",
"description": "不想要了,申请退款",
"refundAmount": 99.00,
"contactName": "张三",
"contactPhone": "13800138000",
"items": [
{"platformProductId": "123456", "quantity": 1, "productName": "测试商品"}
]
}
响应示例
// 沙箱模式
{"code":0,"data":{"afterSaleSn":"SANDBOX_AS_A1B2C3D4E5F6","type":"REFUND_ONLY","status":"CREATED"},"is_sandbox":true}
// 生产模式
{"code":0,"data":{"success":true,"platformAfterSaleId":"AS123456"},"is_sandbox":false}
响应示例
{"code":0,"data":{"afterSaleId":"AS001","orderSn":"SO20260425...","afterSaleType":"REFUND_ONLY","reason":"质量问题","status":"PENDING_AUDIT","refundAmount":60.00,"createTime":"2026-04-25T15:00:00"}}
响应示例
{"code":0,"data":[{"id":1,"orderSn":"SO20260425...","afterSaleType":"REFUND_ONLY","status":"PENDING_AUDIT","refundAmount":60.00,"createTime":"2026-04-25T15:00:00"}]}
无需请求体,直接 POST 即可。
响应字段(data)- 生产模式
| 字段 | 类型 | 说明 |
|---|---|---|
| data | boolean | true 表示取消成功 |
响应示例
// 生产模式
{"code":0,"data":true}
// 沙箱模式
{"code":0,"data":{"afterSaleSn":"SANDBOX_AS_A1B2C3D4E5F6","type":"REFUND_ONLY","status":"CANCELLED"},"is_sandbox":true}
仅适用于 RETURN_REFUND(退货退款)类型、且售后单已审核通过后,买家寄回商品时回填退货运单号。
请求体字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| logisticsCompany | string | 是 | 退货快递公司名称,如“中通快递” |
| logisticsNo | string | 是 | 退货运单号 |
| shipperCode | string | 否 | 快递公司编码,如 ZTO |
请求示例
{
"logisticsCompany": "中通快递",
"logisticsNo": "78474409893076",
"shipperCode": "ZTO"
}
响应示例
{"code":0,"data":true}
用户接口
所有用户接口需要 USER 权限。注册和登录接口无需 X-User-Token,其余接口需要。
响应示例
{"code":0,"data":{"userId":10001,"username":"testuser","mobile":"13800138000","nickName":"testuser","status":"ENABLED","createTime":"2026-04-25T16:00:00"}}
响应示例
{"code":0,"data":{"user_token":"a1b2c3d4e5f6...","user_id":10001}}
无需额外参数,从 X-User-Token 识别用户身份。
响应示例
{"code":0,"data":{"userId":10001,"username":"testuser","mobile":"13800138000","nickName":"小明","avatar":"https://...","sex":1,"status":"ENABLED"}}
响应示例
{"code":0,"data":{"userId":10001,"username":"testuser","nickName":"新昵称","avatar":"https://new-avatar.png","sex":1}}
返回当前用户的所有收货地址。
响应示例
{"code":0,"data":[{"addressId":1,"receiverName":"张三","receiverMobile":"13800138000","province":"浙江省","city":"杭州市","district":"西湖区","detailAddress":"文三路100号","isDefault":true}]}
响应示例
{"code":0,"data":{"addressId":2,"receiverName":"李四","receiverMobile":"13900139000","province":"广东省","city":"深圳市","district":"南山区","detailAddress":"科技园路1号","fullAddress":"广东省深圳市南山区科技园路1号","isDefault":false}}
营销接口
所有营销接口需要 PROMOTION 权限。
响应示例
{"code":0,"data":{"total":5,"coupons":[{"couponId":1,"couponName":"满100减10","couponType":"PRICE","price":10.00,"consumeThreshold":100.00,"status":"ACTIVE"}]}}
无需请求体,通过 X-User-Token 识别领取用户。
响应示例
{"code":0,"data":{"userCouponId":100,"couponId":1,"couponName":"满100减10","status":"UNUSED","startTime":"2026-04-25","endTime":"2026-05-25"}}
| 错误情况 | HTTP | 错误码 |
|---|---|---|
| 优惠券已领完或不在有效期 | 400 | COUPON_UNAVAILABLE |
| 消费者已领取过同一优惠券 | 409 | COUPON_ALREADY_CLAIMED |
资金流接口
所有资金流接口需要 FINANCE 权限。
响应字段(data)
| 字段 | 类型 | 说明 |
|---|---|---|
| data | decimal | 账户余额(元) |
响应示例
{"code":0,"data":1280.50}
storeId 由系统按当前租户自动覆盖,无需传入。flowType:ORDER_IN / REFUND_OUT / WITHDRAW / COMMISSION / SUBSIDY / ADJUSTMENT。响应示例
{"code":0,"data":[{"flowId":1,"flowSn":"F20260425...","flowType":"ORDER_IN","amount":60.00,"direction":"IN","balanceBefore":1220.50,"balanceAfter":1280.50,"description":"订单结算","createTime":"2026-04-25T14:30:00"}]}
storeId 由系统按当前租户自动覆盖,无需传入。响应示例
{"code":0,"data":{"total":3,"bills":[{"billId":1,"billSn":"B20260425...","orderAmount":1000.00,"commissionAmount":60.00,"finalAmount":940.00,"status":"PENDING","startTime":"2026-04-01","endTime":"2026-04-30"}]}}
返回指定账单的完整信息。
响应示例
{"code":0,"data":{"billId":1,"billSn":"B20260425...","orderAmount":1000.00,"refundAmount":0,"commissionAmount":60.00,"finalAmount":940.00,"status":"PENDING","startTime":"2026-04-01","endTime":"2026-04-30"}}
返回账单下的所有结算明细条目。
响应示例
{"code":0,"data":[{"detailId":1,"billId":1,"orderSn":"SO20260425...","orderAmount":100.00,"commissionAmount":6.00,"settlementAmount":94.00}]}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| applyAmount | decimal | 必填 | 申请提现金额 |
| bankName | string | 必填 | 开户银行 |
| bankAccountName | string | 必填 | 开户名 |
| bankAccountNumber | string | 必填 | 银行账号 |
| remark | string | 可选 | 备注 |
响应字段(data)
| 字段 | 类型 | 说明 |
|---|---|---|
| data | long | 提现申请ID(withdrawalId) |
响应示例
{"code":0,"data":1}
返回当前租户的提现申请记录列表,支持分页。
响应示例
{"code":0,"data":{"total":3,"withdrawals":[{"withdrawalId":1,"withdrawalSn":"W20260425...","applyAmount":500.00,"status":"PENDING","applyTime":"2026-04-25T16:00:00"}]}}
返回指定提现申请的详细信息及当前审核状态。
响应示例
{"code":0,"data":{"withdrawalId":1,"withdrawalSn":"W20260425...","applyAmount":500.00,"actualAmount":500.00,"bankName":"工商银行","bankAccountName":"张三","status":"APPROVED","applyTime":"2026-04-25T16:00:00","approveTime":"2026-04-26T10:00:00"}}
消息推送(平台 → 接入方)
平台在订单发货、售后状态变更时 主动 POST 到您配置的 notifyUrl。商品标题/价格/库存变更 不推送,请继续轮询商品接口,或后续使用 updatedSince。
POST /orders。发货与售后不要只靠轮询,接入本模块即可。v1 事件
| event | 触发时机 | 建议处理 |
|---|---|---|
ORDER_SHIPPED | SaaS 订单首次进入 SHIPPED(上游发货同步 / 猫超·京东回调 / 运营补救) | 按 orderSn 或 customerOrderNo 更新物流,通知终端用户 |
AFTERSALE_STATUS | 售后单状态变化(申请 PENDING、上游受理 PROCESSING、待寄回 RETURN_PENDING、退款完成 REFUNDED 等) | 按 afterSaleId + status 刷新售后;需寄回时引导用户填退货物流 |
出站报文
平台向 notifyUrl 发送 POST application/json,Body 全部为顶层标量(无嵌套对象,便于与开放 API 同一套签名)。请求头:
| 请求头 | 说明 |
|---|---|
X-App-Key | 与入站相同的 AppKey |
X-Timestamp | Unix 秒级时间戳,与 Body timestamp 一致 |
X-Sign | 与 Body sign 一致 |
X-Event | 事件名,如 ORDER_SHIPPED |
X-Event-Id | 幂等键,与 Body eventId 一致 |
签名(与入站算法相同)
- 取 Body 全部顶层非空标量,排除
sign - 按 key 字母升序拼接
key1=value1&key2=value2&... - 末尾追加
&app_secret={AppSecret} - UTF-8 MD5 后转大写,与
X-Sign/sign比对
发货事件示例
POST {notifyUrl}
X-App-Key: a1b2c3d4...
X-Timestamp: 1745548800
X-Sign: A3F2B1C4...
X-Event: ORDER_SHIPPED
X-Event-Id: ORDER_SHIPPED:SO20260902001:7310001234567
{
"event": "ORDER_SHIPPED",
"eventId": "ORDER_SHIPPED:SO20260902001:7310001234567",
"orderSn": "SO20260902001",
"customerOrderNo": "CRMEB123456",
"status": "SHIPPED",
"logisticsCompany": "中通快递",
"logisticsNo": "7310001234567",
"shipperCode": "ZTO",
"shipTime": "2026-09-02T10:15:00",
"appKey": "a1b2c3d4...",
"timestamp": "1745548800",
"sign": "A3F2B1C4..."
}
售后事件示例
{
"event": "AFTERSALE_STATUS",
"eventId": "AFTERSALE_STATUS:9001:RETURN_PENDING",
"afterSaleId": "9001",
"orderSn": "SO20260902001",
"status": "RETURN_PENDING",
"afterSaleType": "RETURN_REFUND",
"refundAmount": "88.00",
"appKey": "a1b2c3d4...",
"timestamp": "1745548900",
"sign": "..."
}
接收方要求
- 幂等:以
eventId去重。发货为ORDER_SHIPPED:{orderSn}:{logisticsNo}(尚无运单时末段为_,补物流后再推一条);售后为AFTERSALE_STATUS:{afterSaleId}:{status}。平台可能因多通道并发重试而重复投递。 - 成功应答:HTTP 2xx,且 Body 为空,或 JSON
code为 0 / 200 / SUCCESS,或errcode=0/success=true,或正文含SUCCESS。 - 失败重试:未确认时进程内最多 8 次,间隔约 1s / 2s / 4s / 8s / 16s / 32s / 60s / 120s。仍失败请用订单/售后查询接口补偿。
- 请在数秒内返回 ACK,业务处理放到异步队列,避免拖垮推送线程。
返回当前 AppKey 对应应用的回调地址与订阅事件。无需额外 PermScope。
响应示例
{"code":0,"data":{"notifyUrl":"https://your.example.com/openapi/notify","events":"ORDER_SHIPPED,AFTERSALE_STATUS"}}
省略字段表示不改。notifyUrl 传空字符串关闭推送(会写入 NULL)。仅允许指向公网的 http/https,本机与内网地址会被拒绝。生产请用 HTTPS。events 传空则默认订阅全部 v1 事件。生产订单只推给 app_type=PRODUCTION 的应用。
请求示例
{"notifyUrl":"https://your.example.com/openapi/notify","events":"ORDER_SHIPPED,AFTERSALE_STATUS"}
向已配置的 notifyUrl 投递一条测试报文(eventId 以 TEST: 开头,orderSn=TEST_ORDER),用于联调接收端,无需真实发货。
请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | string | 可选 | 默认 ORDER_SHIPPED,也可 AFTERSALE_STATUS |
响应示例
{"code":0,"data":{"event":"ORDER_SHIPPED","eventId":"TEST:ORDER_SHIPPED:ab12...","queued":true}}
queued=true 表示已进入投递队列,不是对方 HTTP 已成功。请在接收端核对 eventId。字典表
对接的是中台开放接口,不是京东、天猫、好食期、聚水潭等供应商原始接口。各供应商自己的状态码、类目码、原因码都不一样,中台已全部映射成下面这套统一枚举。
请只认本页取值。不要按供应商原始字典做判断,也不要再各自做一层供应商映射。开放接口不会返回供应商原始状态码。
GET /open/api/v1/saas-categories。商品状态 status
| 枚举值 | 说明 |
|---|---|
ON_SALE | 在售 |
OFF_SALE | 下架 |
OUT_OF_STOCK | 缺货 |
DELETED | 已删除 |
AUTH_FAILED | 未授权(对接入方等同不存在) |
UNKNOWN | 未知 |
库存状态 stockStatus
| 枚举值 | 说明 |
|---|---|
IN_STOCK | 有货 |
LOW_STOCK | 库存紧张 |
OUT_OF_STOCK | 无货 |
价格字段(中台统一口径)
| 字段 | 口径 | 说明 |
|---|---|---|
salePrice、skuDetail[].price、skuDetail[].tenantPrice | 拿货价 / 结算价 | 三者相同。订单结算以此为准,终端售价请在此基础上加价 |
marketPrice、skuDetail[].reservePrice | 建议零售价 | 仅部分渠道返回,仅供展示,禁止当拿货价。为空则不要展示 |
costPrice | 保留字段 | 开放接口不返回,恒为 null |
skuDetail[].price,不要读 reservePrice。订单状态 status
| 枚举值 | 说明 |
|---|---|
CREATED | 已创建(尚未提交履约) |
SUBMITTING | 提交中 |
RESULT_UNKNOWN | 提交结果待核实 |
FAILED | 提交失败 |
SUBMITTED | 已提交 |
PAID | 已支付 / 待发货 |
SHIPPED | 已发货 |
COMPLETED | 已完成 |
CANCELLED | 已取消 |
POST /open/api/v1/orders。创建成功后状态为 SUBMITTED 或 PAID。发货请接消息推送 ORDER_SHIPPED(payload 中 status=SHIPPED),不要只靠轮询。售后类型 type
| 枚举值 | 说明 |
|---|---|
REFUND_ONLY | 仅退款 |
RETURN_REFUND | 退货退款 |
EXCHANGE | 换货 |
REPAIR | 维修 |
售后申请原因 reasonCode
| 枚举值 | 说明 |
|---|---|
QUALITY_ISSUE | 质量问题 |
NOT_AS_DESCRIBED | 与描述不符 |
DAMAGED | 商品损坏 |
WRONG_ITEM | 发错商品 |
NO_LONGER_NEEDED | 不再需要 |
售后状态 status
| 枚举值 | 说明 |
|---|---|
PENDING | 已申请(仅此状态可取消) |
APPROVED | 审核通过(可填写退货物流) |
RETURN_PENDING | 待寄回(可填写退货物流) |
PROCESSING | 处理中 |
REFUNDED | 已退款 |
REJECTED | 审核拒绝 |
CANCELLED | 已取消 |
COMPLETED | 已完成(终态) |
CLOSED | 已关闭(终态) |
AFTERSALE_STATUS,报文里的 status 即上表取值。沙箱申请售后可能返回 CREATED,生产申请成功为 PENDING,请以生产为准。沙箱环境
新创建的应用默认为沙箱模式(app_type=SANDBOX),用于安全地测试 API 集成,不影响真实业务。
沙箱与生产的区别
| 操作类型 | 沙箱模式 | 生产模式 |
|---|---|---|
| 创建订单 | 仅本地落库,生成 SANDBOX_ 前缀订单号 | 调用上游平台,真实下单 |
| 区域配送预检 | 拒绝真实配送确认,返回 reason=SANDBOX | 调用上游确认该地址是否可配送 |
| 取消订单 | 仅本地更新状态 | 调用上游平台取消 |
| 申请售后 | 仅本地落库 | 调用上游平台 |
| 查询订单列表 | 查询沙箱订单表,返回 SANDBOX_ 前缀订单 | 查询生产订单表 |
| 查询订单详情/物流 | 返回沙箱数据 | 返回真实数据 |
| 商品/用户/优惠券 | 与生产一致 | 与生产一致 |
识别沙箱响应
{"code":0,"data":{"orderSn":"SANDBOX_A1B2C3D4E5F6G7H8","orderId":1,"status":"CREATED","receiverName":"张三","receiverPhone":"13800138000","receiverAddress":"北京市朝阳区xxx路xxx号"},"is_sandbox":true}
升级为生产模式
完成沙箱联调测试后,联系平台运营人员在管理后台审核升级为生产模式。
常见问题
不需要为托管 H5 申请 AppKey。联系运营开通,按 《H5 接入说明》 提供机构信息即可;渠道码由运营分配。同一租户若还有自建系统,再按本文对接开放API。
- 确认参数排序是否按 key 字母升序(区分大小写)
- 确认空值字段是否已跳过(值为 null 或空字符串的字段不参与签名)
- 确认 JSON Body 中只有顶层字段参与签名,嵌套对象(如 address)整体不参与
- 确认 MD5 结果是否转为大写
- 确认使用的是 UTF-8 编码计算 MD5
- 使用秒级时间戳,不是毫秒(毫秒值会比服务器时间大 1000 倍)
- 服务器时钟与 NTP 同步,避免时钟漂移
- 每次请求重新生成时间戳,不要复用
- 默认限制为 60 次/分钟,收到文案「调用频率超限」后等待 1 分钟再重试
- 商品列表/详情/价格/库存另有并发闸:全局 20 路、单租户 4 路。文案为「商品查询繁忙」时请降低并发或稍后重试
- 如业务需要更高频率,联系平台运营调整 rate_limit 配置
Token 有效期 7 天,过期后重新调用 POST /users/login 获取新 Token。建议捕获 USER_TOKEN_INVALID 错误后自动跳转登录流程。
沙箱订单号以 SANDBOX_ 为前缀,如 SANDBOX_A1B2C3D4E5F6G7H8。生产模式下为上游平台的真实订单号格式。
这不是地址或商品配送问题。当前 AppKey 对应的开放应用仍是沙箱(app_type=SANDBOX),中台不会向供应商确认真实配送范围。请在开放应用管理中将该应用「升级生产」后再试。
不必。配置 消息推送 后,平台会在 ORDER_SHIPPED / AFTERSALE_STATUS 时 POST 到您的 URL。商品变价/库存仍请轮询。推送失败可继续用订单详情、售后详情补偿。
算法与入站完全一致(顶层标量排序 + AppSecret + MD5 大写),不要把 sign 本身加入签名原文。用 eventId 做幂等:发货键含运单号,补物流会再推一次。联调可调用 POST /open/api/v1/notify/test(返回 queued 仅表示入队)。