订单消息推送
仅提供已授权的门店数据服务:已完成门店授权(客户门店与收钱吧门店映射)的门店,其订单消息才会被推送。
1. 概述
消息推送平台是开放平台中,由开放平台主动发起调用开发者应用服务的一个通道,用于向应用推送订单变更等消息。
与主动查询接口(请求方为开发者)相反,消息推送为开放平台 → 开发者方向:开发者按消息类型提供 HTTPS 回调地址接收推送。推送与主动调用接口完全复用同一套签名鉴权规范(见鉴权与签名):签名参数通过标准请求头携带,验签使用 HMAC-SHA256 保证消息完整性与防篡改;业务数据以明文 JSON 作为请求体发送,验签通过后即可直接解析。传输强制 HTTPS,接收方使用自己的
accessSecret即可完成验签,无需额外配置密钥。
2. 通道要求
三方应用需要按消息类型提供 HTTP 回调通道,有需要推送的消息时,开放平台会按照约定格式,主动调用对应消息类型的回调地址,完成消息推送功能。
接口有以下要求:
- 请使用标准 HTTP 协议,非标私有实现可能会有一定的兼容问题,必须使用 HTTPS,并需要保证 SSL 证书有效
- POST 请求,UTF-8 编码,HTTP 请求头中:
Content-Type: application/json,Body 中存放 JSON 格式报文 - 接收方需要进行消息体验签
- 推送必须遵循推送与回调机制,尤其是其中的响应要求(HTTP 200、
Content-Type: application/json、Body 为{"status": "success"}、3 秒内响应)为强制项,不满足即视为推送失败并触发重试;重试策略、幂等处理与消息兼容机制同见该文件
3. 回调地址配置
每种消息类型(msgType)对应一个独立的回调地址,开发者在接入时按消息类型配置。未配置回调地址的消息类型将不会收到推送。
| msgType | 名称 | URL 地址 |
|---|---|---|
| ORDER_FINISHED | 已完成订单 | https://3rd.smartopen.com/smart/orderComplete |
| ORDER_REFUND | 订单退款 | https://3rd.smartopen.com/smart/orderRefund |
消息类型(
msgType)由平台定义,回调地址路径由开发者自行定义;接入时需向收钱吧运营提供各消息类型的回调地址,或按开放平台管理后台指引配置。每个回调地址收到的推送请求均需按第 5 节完成验签。
4. 请求参数说明
推送请求的签名参数通过 HTTP 请求头携带,与主动调用接口完全一致。
4.1 请求头
| Header | 类型 | 必填 | 说明 |
|---|---|---|---|
| X-AccessKey | String | 是 | 开放平台分配给开发者的公开凭证 |
| X-Timestamp | Long | 是 | 消息实际发送时间戳,单位毫秒,例如:1684986985000 |
| X-Nonce | String | 是 | 参与签名生成的随机字符串,每次推送不同 |
| X-Signature | String | 是 | HMAC-SHA256 签名值(十六进制小写),验签方式见鉴权与签名 |
4.2 请求体(信封结构)
Body 为业务消息明文 JSON,采用统一的信封结构,外层固定 msgId、msgType、data 三个字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| msgId | String | 是 | 消息 ID,唯一标识 1 个消息,在重复推送时不变 |
| msgType | String | 是 | 消息类型,决定回调地址与 data 结构,见第 3 节 |
| data | Object | 是 | 业务数据,结构随 msgType 而定,见第 6 节 |
msgId 与主动接口 requestId 的区别:
msgId为消息的唯一标识,由开放平台生成,用于推送去重与幂等处理(同一事件重复推送时不变);主动写操作接口的requestId为请求幂等键,由调用方(开发者)生成,用于主动写操作请求的重试去重,见幂等机制。二者概念不同,不可混用。
5. 消息验签
应用在接收到消息后,首先需要验签,验证消息未被篡改或部分丢失。推送请求的验签与主动调用接口的请求签名完全一致,签名参数取自请求头 X-AccessKey、X-Timestamp、X-Nonce、X-Signature:
第一步:拼接签名字符串
其中 requestBody 为推送请求的 HTTP Body 原文(即信封结构 JSON 字符串,需与发送方逐字节一致):
accessKey | timestamp | nonce | requestBody
第二步:计算本地签名
以 accessSecret 作为密钥,对签名字符串计算 HMAC-SHA256,输出十六进制小写:
localSignature = HMAC_SHA256(accessKey + "|" + timestamp + "|" + nonce + "|" + <HTTP Body 原文>, accessSecret)
第三步:比对签名
比对 localSignature 与请求头中的 X-Signature,一致则验签通过;否则说明消息被篡改或部分丢失,应丢弃该消息。
推送同样适用鉴权与签名的防重放机制:
X-Timestamp与服务器时间差 ≤ 5 分钟,X-Nonce5 分钟内不可重复使用。
6. 订单业务消息
6.1 已完成订单(msgType: ORDER_FINISHED)
订单完成后,推送订单完整信息给开发者。推送的 data 为订单完整信息,其字段结构(订单基础信息、商品、优惠、支付等)与订单查询接口的"3. 响应参数"一致,完整字段定义以该接口为准。
6.2 订单退款(msgType: ORDER_REFUND)
用户或客服发起退款流程后推送。推送的 data 为退款信息,包含退款状态、退款方式、退款商品等字段:
data 结构说明
| 字段 | 类型 | 必填 | 示例值 | 说明 |
|---|---|---|---|---|
| clientStoreSn | String | 是 | SH001 | 客户门店号 |
| sqbStoreSn | String | 是 | 1580000003443730 | 收钱吧门店号 |
| orderSn | String | 是 | 210000001000001 | 收钱吧订单号 |
| refundMethod | String | 是 | BY_AMOUNT | 退款方式,枚举见订单枚举附录 |
| refundReason | String | 否 | 不好吃 | 退款原因 |
| goods | Array | 否 | 退款商品列表,按金额退款时无此字段 | |
| refundAmount | Long | 是 | 1200 | 退款金额,单位分 |
| updateTime | Long | 是 | 1700318325713 | 事件发生时间戳 |
退款商品列表结构说明
| 字段 | 类型 | 必填 | 示例值 | 说明 |
|---|---|---|---|---|
| id | String | 是 | 4e351201-9ae2-4142-9863-1a3500ac7857 | 商品唯一 ID |
| name | String | 是 | 苹果 | 商品名称 |
| quantity | String | 是 | 1 | 退款数量,最多 3 位小数 |
| amount | Long | 是 | 100 | 金额,单位分 |
7. 完整请求示例
以下为各消息类型的完整请求示例,包含全部请求头签名参数与完整业务数据。
7.1 已完成订单(msgType: ORDER_FINISHED)
以下为推送"已完成订单"消息的完整请求示例,data 为订单完整信息:
curl --location --request POST 'https://3rd.smartopen.com/smart/orderComplete' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'Connection: keep-alive' \
--header 'X-AccessKey: ak_live_xK9mP2nQ7wR4tY6z' \
--header 'X-Timestamp: 1684986985000' \
--header 'X-Nonce: a1b2c3d4' \
--header 'X-Signature: 3f7a8b2c1e9d4f6a5b8c3e2d1f0a9e8b...' \
--data-raw '{
"msgId": "202312261413412118468370213",
"msgType": "ORDER_FINISHED",
"data": {
"orderSn": "210000001000001",
"orderStatus": "FINISHED",
"clientStoreSn": "SH001",
"sqbStoreSn": "1580000003443730",
"orderType": "RETAIL",
"updateTime": 1786590141819,
"remark": "",
"originalAmount": 350,
"merchantDiscountTotalAmount": 0,
"expectedIncomeAmount": 350,
"refundAmount": 0,
"goods": [
{
"spuId": "2258087",
"url": null,
"name": "伊利 火炬苦咖啡口味冰淇淋 80g",
"originalAmountPer": 350,
"effectiveAmountPer": 350,
"totalAmount": 350,
"discountCount": null,
"count": 1,
"refundCount": null,
"spuType": "PRODUCT",
"skuType": "SINGLE",
"spec": null,
"specInfo": {
"id": "2258087",
"name": null,
"price": 350,
"attachedInfo": null
},
"attributeInfos": null,
"materials": null,
"packageGoods": null,
"saleUnit": "袋",
"refPayType": "PAY",
"processStatus": "ACCEPTED",
"extraInfo": {
"localGoodsId": "2258087_1774510934030",
"userName": "收银员",
"saleWeight": 1,
"itemSort": 429,
"orderTimeStamp": "1774510935802",
"userIcon": "https://shouqianba-marketing.oss-cn-hangzhou.aliyuncs.com/99zhe/meal-merge/defaultPortrait.png",
"unitType": "NUMBER",
"barcode": "6907992822716",
"categorySort": 0,
"originGoodsPrice": 350
},
"extraMap": {
"localGoodsId": "2258087_1774510934030",
"userName": "收银员",
"saleWeight": 1,
"itemSort": 429,
"orderTimeStamp": "1774510935802",
"userIcon": "https://shouqianba-marketing.oss-cn-hangzhou.aliyuncs.com/99zhe/meal-merge/defaultPortrait.png",
"unitType": "NUMBER",
"barcode": "6907992822716",
"categorySort": 0,
"originGoodsPrice": 350
},
"goodsDiscountType": null,
"discountAmount": 0,
"categoryId": "124820",
"goodsTag": null
}
],
"payments": [
{
"clientSn": "2300003326705134",
"transSn": "7895210846728718",
"tradeNo": "14002026032615421600476419057",
"refClientSn": null,
"refundBatchNo": null,
"totalAmount": 350,
"receiveAmount": 350,
"buyerPayAmount": 350,
"discountAmount": 0,
"channelAssistDiscount": 0,
"payDiscountAmount": 0,
"refundAmount": 0,
"cashBackAmount": 0,
"chargeGiftAmount": 0,
"payWay": "WECHAT",
"subPayWay": "BARCODE",
"payType": "PAYMENT",
"orderPayStatus": "PAID",
"payerLogin": "opwm3uPOkl7dSw71sx_QRr5FPWTQ",
"tradeTime": 1774510936000,
"payTime": 1774510938000,
"cashierId": "6be8a438-eff2-4f5b-8cdc-5c1f4b32be92",
"profitSharingAmount": 0
}
],
"discounts": []
}
}'
7.2 订单退款(msgType: ORDER_REFUND)
以下为推送"订单退款"消息的完整请求示例,data 为退款信息:
curl --location --request POST 'https://3rd.smartopen.com/smart/orderRefund' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--header 'Connection: keep-alive' \
--header 'X-AccessKey: ak_live_xK9mP2nQ7wR4tY6z' \
--header 'X-Timestamp: 1684986985000' \
--header 'X-Nonce: a1b2c3d4' \
--header 'X-Signature: 3f7a8b2c1e9d4f6a5b8c3e2d1f0a9e8b...' \
--data-raw '{
"msgId": "202312261413412118468370213",
"msgType": "ORDER_REFUND",
"data": {
"clientStoreSn": "SH001",
"sqbStoreSn": "1580000003443730",
"orderSn": "210000001000001",
"refundStatus": "C_REFUND_APPLY",
"refundMethod": "BY_GOODS",
"refundReason": "不好吃",
"goods": [
{
"id": "4e351201-9ae2-4142-9863-1a3500ac7857",
"name": "苹果",
"quantity": 1,
"amount": 100
},
{
"id": "6f2c4b3a-1d5e-4f8a-b7c3-9e2d1a0f5c8b",
"name": "香蕉",
"quantity": 2,
"amount": 200
}
],
"refundAmount": 1200,
"updateTime": 1700318325713
}
}'