1. 接口定位
SDK 接入
适合大部分商户。商户嵌入 SDK 页面/组件,SDK 负责商品展示、下单参数收集和部分体验封装。测试联调请登录商户后台操作。
面向:商户前端 + 商户后台配置
OpenAPI 接入
适合有自研后端能力的商户或系统级合作方。使用 AppId/AppSecret/HMAC 签名调用商品、余额、下单、查单接口。
面向:商户服务端/合作方系统
结论:这些接口是“对授权商户开放的外部能力”,但不是给普通 C 端用户裸调。C 端用户在商户页面付款,商户确认收款后再通过 SDK/OpenAPI 通知平台履约。联调测试统一放在商户后台,避免公开文档暴露测试工具。
2. 完整业务流程
资金安全 当前测试环境已经采用冻结/确认/解冻机制,不再直接扣款后再履约。
价格体系与调价规则
平台采用三层价格治理,商户端展示和下单金额必须以平台后端快照为准,不能相信前端裸传金额。
三层价格
- 上游成本价:平台向权益供应商采购/结算的底价,仅平台内部可见。
- 平台基准结算价:平台给商户的默认结算价,必须大于等于上游成本价,是平台毛利底线。
- 商户零售价:商户展示给用户并向用户收款的价格,必须大于等于商户结算价。
价格安全底线
- 平台基准结算价 >= 上游成本价。
- 商户结算价 >= 平台基准结算价。
- 用户支付价/商户零售价 >= 商户结算价。
- 发现倒挂、空价格、过期报价时,平台会拒单或回退到安全建议价。
价格模式
| 模式 | 适用场景 | 下单要求 |
|---|---|---|
| 固定价 fixed | 话费、会员、洗车、洁牙、标准权益券等 | 按后台授权价格下单,前端金额仅展示,后端重算。 |
| 动态锁价 quote | 餐饮、商超、酒店、景区、电影、票务等价格波动或SKU组合类 | 先由平台后端查询真实商品并生成 quoteId,再用 quoteId 创建订单;quoteId短期有效。 |
| 实时/H5价 h5 | 打车、外跳H5、展码付、第三方收银等实时场景 | 用户在实时页面完成选品/支付,平台按回调和订单快照核验。 |
商户调价边界
- 商户可在平台授权范围内设置零售价、建议价、最低价、最高价。
- 低于结算价的零售价不允许保存;已存在历史倒挂数据会被治理脚本拉回安全价。
- 动态价产品不允许商户自行填写最终履约价,必须使用 quoteId 或平台实时价格快照。
- 建议零售价默认按平台基准结算价加合理毛利生成,后续可按商户等级、行业、城市、活动配置差异化规则。
3. SDK v2 接入路径
商户最短接入
- 平台开通商户、产品授权、SDK 域名白名单、商户收银台地址与支付回调地址。
- 商户页面引入
/sdk/commercial-v2/commercial-v2.css与/sdk/commercial-v2/commercial-v2-sdk.js。 - 调用
ChinaDaoCommercialV2.init渲染商户权益商城。 - 用户选择权益,SDK 自动完成城市/资源/规格选择,并请求后端
quoteId锁价。 - 平台创建待支付订单并返回
cashierUrl,地址仅包含一次性短期token=cst_xxx,不暴露订单号、金额、签名等敏感参数。 - 商户前端只负责跳转
cashierUrl,不要解析或自行拼接merchantId/orderNo/quoteId/amount/timestamp/nonce/sign。 - 用户在商户收银台付款,商户服务端通过
/sdk/payment/notify或/sdk/order-pay-notify签名回调平台确认收款,平台履约并回调商户。
正式接入代码
<div id="merchant-benefit-sdk"></div>
<link rel="stylesheet" href="/sdk/commercial-v2/commercial-v2.css">
<script src="/sdk/commercial-v2/commercial-v2-sdk.js"></script>
<script>
ChinaDaoCommercialV2.init({
merchantId: '你的商户ID',
container: '#merchant-benefit-sdk',
merchantName: '商户权益商城',
apiBase: '/prod-api/openapi/v1',
liveMode: true,
merchantMemberId: '商户侧会员ID',
memberOpenId: '微信openId/unionId,可选',
memberMobile: '会员手机号,可选',
memberName: '会员昵称,可选',
memberSource: 'h5'
});
</script>旧版 /sdk/sdk.js 仅作为历史兼容文件保留,新商户统一接入 SDK v2。
产品准入口径
用户端产品展示以 product-admission.json 为准,分为可购买、可查/联调、即将开放、暂不可接入。只有已验证 query/quote/order-create 链路的产品才允许进入购买。
4. 收银台 cashierUrl 安全说明
token 化跳转
/sdk/order-create 返回的 cashierUrl 是平台生成的短期跳转地址,格式类似 /sdk/commercial-v2/merchant-cashier.html?token=cst_xxx。浏览器 URL 不再携带 merchantId/orderNo/quoteId/amount/timestamp/nonce/sign。
商户前端只需要跳转该地址;不要解析、保存、转发或自行拼接 token。token 过期后需要重新创建订单或重新发起支付流程。
支付确认边界
token 仅用于收银台展示订单信息,不代表支付成功凭证。
正式支付成功后,必须由商户服务端调用 /sdk/payment/notify 或 /sdk/order-pay-notify,携带 merchantId/orderNo/quoteId/amount/timestamp/nonce/sign 完成验签确认。浏览器前端不能直接确认支付成功。
5. 客户常用入口
以下仅保留商户接入必须使用的正式入口。
6. 回调与订单状态
订单状态
WAIT_PAY 待商户确认收款 → PAID 已确认 → PROCESSING 上游处理中 → SUCCESS 成功 / CLOSED 失败关闭 / REFUNDED 已退款。
回调要求
商户按 orderNo 做幂等。平台可能因网络失败重试通知,同一订单重复通知不得重复发货/重复退款。
{
"orderNo":"SDK202605201812405703",
"status":"SUCCESS",
"merchantId":1,
"payAmount":"105.00",
"event":"ORDER_SUCCESS"
}7. 会员身份透传与我的订单
SDK v2 已支持商户自有会员身份透传,解决同一浏览器/多商户场景下“我的订单”归属不清的问题。会员身份始终按商户维度隔离,不建立平台全局用户ID。
SDK 初始化字段
| 字段 | 说明 | 建议 |
|---|---|---|
merchantMemberId | 商户会员ID/用户ID | 优先传,作为订单归属第一优先级 |
memberOpenId | 公众号/小程序 openId 或 unionId | 微信生态推荐传 |
memberMobile | 会员手机号 | 可作为兜底归属,不建议单独依赖 |
memberName | 会员昵称/姓名 | 可选,仅用于展示或辅助排查 |
memberSource | 会员来源 | 如 h5/wechat/miniapp/app |
订单归属优先级
merchantId + merchantMemberIdmerchantId + memberOpenIdmerchantId + memberMobile- 浏览器本地订单缓存仅作为老版本兜底,不作为正式归属依据。
后端订单表已新增 merchant_member_id、member_mobile、member_open_id、member_source 字段,均按商户维度索引查询。
推荐接入代码
<div id="merchant-benefit-sdk"></div>
<link rel="stylesheet" href="/sdk/commercial-v2/commercial-v2.css">
<script src="/sdk/commercial-v2/commercial-v2-sdk.js"></script>
<script>
ChinaDaoCommercialV2.init({
merchantId: '11',
container: '#merchant-benefit-sdk',
merchantName: '商户权益商城',
apiBase: '/prod-api/openapi/v1',
liveMode: true,
merchantMemberId: window.CURRENT_USER_ID || '',
memberOpenId: window.WECHAT_OPEN_ID || '',
memberMobile: window.CURRENT_USER_MOBILE || '',
memberName: window.CURRENT_USER_NAME || '',
memberSource: 'h5'
});
</script>我的订单接口
GET /prod-api/openapi/v1/sdk/order-list?merchantId=11&merchantMemberId=U10001 GET /prod-api/openapi/v1/sdk/order-list?merchantId=11&memberOpenId=oXxxx GET /prod-api/openapi/v1/sdk/order-list?merchantId=11&memberMobile=13800138000
跨域接入时请求必须来自已授权域名;接口会校验 Origin/Referer 与商户白名单。
8. 售后/退款能力
SDK端表现
- 订单详情显示售后状态。
- 符合条件的订单展示“申请退款/售后”按钮。
- 提交前有二次确认,提交后自动刷新订单状态。
- 订单列表新增售后筛选,便于会员查看处理中/已退款订单。
接口边界
退款申请仅创建售后请求,不代表资金立即原路退回。实际退款需平台/商户按支付渠道、履约状态和风控规则审核处理。
生产环境禁止用真实订单做退款演示,除非商户明确授权。
餐饮/券类 quoteId 报价锁价
餐饮、咖啡、兑换券等 SKU 价格不能由前端裸传金额。商户端应先让平台后端重查真实菜单并生成短期 quoteId,再用 quoteId 创建订单。
正式流程
- 查询真实门店和菜单 SKU。
- 调用
POST /openapi/v1/sdk/food/quote?merchantId=3生成报价快照。 - 订单创建只提交
quoteId,不要提交前端计算金额。 - 后端按 Redis 价格快照写入订单金额,保障 quote/order/DB 一致。
星巴克正式服验收样例
商品:双杯美式咖啡
productId:sbk_135533136191685166
价格:43.20
测试订单:TEST202605202018285095
验收:quote = order = DB = 43.20
报价接口
POST /prod-api/openapi/v1/sdk/food/quote?merchantId=3
Content-Type: application/json
{
"merchantId": 3,
"shopType": "XBK",
"shopId": "ff6f2064-8bf7-4f4a-9c83-4bf201714971",
"productId": "sbk_135533136191685166",
"quantity": 1
}下单接口
POST /prod-api/openapi/v1/sdk/order-create?merchantId=3
Content-Type: application/json
{
"merchantId": 3,
"typeCode": "Food",
"testMode": true,
"quoteId": "foodq_xxx",
"phoneNumber": "18100348861"
}安全要求:正式餐饮/券类下单必须使用 quoteId;quoteId 5分钟有效,后续应增加一次性消费、防重放和 SKU 级成本校验。
7. 安全与正式上线
- SDK:必须配置商户域名白名单,避免任意站点盗用 merchantId。
- OpenAPI:必须使用 AppId/AppSecret/HMAC 签名,建议配置 IP 白名单。
- 价格:动态价格/券类/餐饮类必须使用平台后端价格快照
quoteId,不能相信前端裸传金额。 - 资金:正式环境只允许冻结/确认/解冻闭环,不允许回到直接扣款模式。
- 上线:正式环境同步前必须备份代码、JAR、关键表,并重新跑价格/商户/补偿检查。