订单每次状态流转后,我方向渠道方配置的回调地址异步推送事件报文。推送失败不影响订单流转与结算,由我方自动重试,重试耗尽后转人工补推。 配套阅读:接入说明(状态机与流转语义)、接口安全(接口签名与响应码)。
| 项 | 说明 |
|---|---|
| 推送方式 | HTTP POST,Content-Type: application/json,UTF-8 |
| 单次超时 | 10 秒(未响应视为失败) |
| 触发时机 | 仅状态发生变化时(同状态幂等刷新不推送,扣款事件除外) |
| 推送顺序 | 不保证有序(重试可能导致乱序) |
| 重复投递 | 允许重复,以 eventId 幂等 |
| 失败重试 | 自动重试 4 次(约 1 分钟 / 5 分钟 / 30 分钟 / 2 小时),仍失败转人工补推 |
notifyUrl(HTTPS,最长 256 字符),由我方写入渠道配置;变更同样走线下申请。未配置回调地址时不会推送,配置后由 我方人工补推。验签使用与接口签名相同的 secret,无需额外配置。
| eventType | 含义 | 触发时机 | 订单 status |
|---|---|---|---|
ORDER_REGISTERED | 报名成功 | order/apply 受理成功 | 10 |
ORDER_SUBMITTED | 已提单 | 回填外卖单号成功 | 20 |
ORDER_REVIEWED | 待审核 | 上传凭证成功或系统推进到待审核 | 30 |
ORDER_REJECTED | 审核驳回 | 审核驳回,订单停留在 30 | 30 |
ORDER_COMPLETED | 已完成 | 审核通过并完成结算(status 为 50;入账待完成的为 40) | 40 / 50 |
ORDER_CANCELED | 已取消 | 渠道取消、系统关单、超时关单 | -1 |
ORDER_DEDUCTED | 扣款 | 已完成订单被扣款(状态不变,仅追加原因) | 当前状态 |
ORDER_COMPLETED 同时覆盖 40 与 50,两者对渠道方含义相同,都按“已完成”处理,具体值看报文里的 status。ORDER_REJECTED 后订单仍停留在 30,重新调用 submitVoucher 提交新凭证即可,可多次重提。ORDER_DEDUCTED 是同状态下的额外事件,status 不变,reason 前缀为 [扣款]。收到后请暂停或调整对该用户的返利。reason,不产生推送事件(ORDER_DEDUCTED 除外)。若订单早已处于待审核,后续驳回刷新不会再发事件,需以 order/detail 回查的 reason 为准。| 字段 | 类型 | 必有 | 说明 |
|---|---|---|---|
eventId | string(36) | 是 | 事件唯一 ID(UUID),幂等键;补推沿用同一值 |
eventType | string | 是 | 事件类型,取值见上表 |
appId | string | 是 | 渠道应用 ID,与请求头 X-App-Id 一致 |
timestamp | long | 是 | 事件生成时间,毫秒时间戳 |
orderNo | string | 是 | 我方订单号(order/apply 返回值) |
channelOrderNo | string | 是 | 渠道侧单号 |
status | int | 是 | 统一状态:10 / 20 / 30 / 40 / 50 / -1(整数,与接口响应的枚举名不同) |
reason | string | 是 | 取消/驳回/扣款原因,无原因时为空字符串(不省略字段) |
commissionAmount | long | 是 | 该单渠道服务费,单位分;报名时快照,之后不变 |
channelAmount | long | 是 | 该单渠道入账金额,单位分 = 结算额 − 渠道服务费 |
completeTime | long | 否 | 完成时间(毫秒),仅完成态报文携带 |
cancelTime | long | 否 | 取消时间(毫秒),仅取消态报文携带 |
{
"eventId": "0f0d7f0e7a9c4f5e8b0a1c2d3e4f5a6b",
"eventType": "ORDER_REGISTERED",
"appId": "200009",
"timestamp": 1761234567123,
"orderNo": "BW17612345670001234",
"channelOrderNo": "CH20261023001",
"status": 10,
"reason": "",
"commissionAmount": 500,
"channelAmount": 4500
}其余事件字段一致,差异仅在于: status与eventType取值、reason内容,以及完成态多一个completeTime、取消态多一个cancelTime。
| 请求头 | 说明 |
|---|---|
Content-Type | 固定 application/json |
X-App-Id | 渠道应用 ID |
X-Timestamp | 毫秒时间戳 |
X-Nonce | 随机串(UUID),同一事件重试时会变化 |
X-Sign | 验签签名,十六进制小写 |
X-Sign = lowerHex( HMAC-SHA256( key = secret,
message = X-App-Id + X-Timestamp + X-Nonce + body ) )secret 即接口签名的同一个密钥。body 为原始请求体字符串(UTF-8),四段之间无分隔符直接拼接。X-Sign 不通过直接丢弃并返回失败(用 hmac.compare_digest 做常量时间比较)。eventId 幂等:同一 eventId 重复到达只处理一次(落库唯一键或 Redis 标记均可)。status 单调处理:乱序到达时忽略回退事件(例如已处理 50,再收到 20 可丢弃)。2xx 且 body 中含 success 即视为成功:成功判定是对响应 body 做子串匹配:包含 success,或包含"error":10000(冒号后无空格)。返回空 body、5xx、或 body 中不含这两种字样都会被判为失败并触发重试。
GET /openapi/bwc/order/detail 或 order/search 的实时结果为准。| 投递次数 | 时机 |
|---|---|
| 第 1 次 | 状态流转后立即推送 |
| 第 2 次 | 首次失败后约 1 分钟 |
| 第 3 次 | 再失败后约 5 分钟 |
| 第 4 次 | 再失败后约 30 分钟 |
| 第 5 次 | 再失败后约 2 小时 |
eventId,接收方按 eventId 去重即可。orderNo + eventType 向我方查询推送状态。| 现象 | 可能原因 | 处理 |
|---|---|---|
| 一直收不到推送 | 未配置回调地址 | 联系我方确认 notifyUrl,配置后人工补推 |
| 报文验签总是失败 | 用反序列化后的 body 重新签名;或密钥不一致 | 用原始 body 计算;核对 secret |
| 我们的接口被反复调用同一事件 | 响应慢于 10 秒 / body 不含 success / 返回 5xx | 改为快速响应 + 返回 {"code":0,"message":"success"} |
| 事件顺序错乱 | 重试导致 | 按 status 单调处理,忽略回退;最终态回查 order/detail |