支付回调丢失后的主动查单补单
场景
支付成功了,回调没到。
微信支付在支付完成时会向商户回调地址推送通知,但系统抖动、网络分区、回调地址短暂不可用,通知都可能到不了。干等是等不回来的,结果就是“用户钱扣了、系统没入单”的单边账。
兜底手段只有一个:主动调查单接口,把订单真实状态拉回来。依据是微信支付官方《支付回调和查单实现指引》《查单设计指引》和《商户订单号查询订单》接口文档。
查单接口:字段与判断
请求方式:GET /v3/pay/transactions/out-trade-no/{out_trade_no}
必填参数:
out_trade_no:商户订单号,string(32)mchid:商户号
应答关键字段:
transaction_id:微信侧订单号,支付成功后才返回trade_state:订单状态trade_state_desc:状态描述
判断支付成功的硬性条件:验签通过 且 trade_state 为 SUCCESS,两者缺一不可。
trade_state 取值:SUCCESS、REFUND、NOTPAY、CLOSED、REVOKED、USERPAYING、PAYERROR、ORDER_NOT_EXIST。
触发时机与频率:官方给的是参考,不是硬性
官方文档给出的间隔序列是:5秒 / 30秒 / 1分钟 / 3分钟 / 5分钟 / 10分钟 / 30分钟。间隔和次数商户自己定,官方不提供细节建议。
一个常用做法是:定时任务每 30 秒跑一次,找出最近 10 分钟内创建且未支付的订单去查单;记录查询次数,累计 10 次仍未支付成功就停止,调关单接口关闭订单。
这里的权衡要自己判断:查得越频繁越费 API 配额,查得越疏漏单窗口越大。这几个数值(30秒、10分钟、10次)都不是官方强约束,是实践参考。
触发基准时间:以订单下单成功时间为准,或以前端支付返回成功/报错后第一次查单失败的时间为准。
两条查单链路(官方推荐方案二)
- 链路一:前端回调触发。用户支付完成跳回商户页时,同步触发一次查单。
- 链路二:下单时写入任务队列,按设定频率开始轮询。
两条并行跑,避免单一链路失效后长时间盲等。
前端返回值的判断
前端返回 fail:说明用户取消支付,将该订单从查单队列移除。
前端返回 success:说明用户没取消,但最终是否支付成功,要依赖后台回调或查单结果。此时应触发一次商户内部订单查询服务,把状态确认后同步给前端展示。
关单的边界
最后一次查单仍非 SUCCESS,立即调关单接口,中间不要留时间差。
硬性边界:关单接口只能对未支付成功的订单调用,已支付成功的订单调关单会失败。
订单到达过期时间时,也要触发一次查单,保证过期时的状态记录正确——未支付成功的关单,已支付成功的走退款,这样才不产生单边账。
对账单兜底(最迟到 T+1)
T+1 上午 10 点后,调对账单下载接口(或手工下载 T 日账单),逐笔与商户系统订单核对。
- 订单匹配成功但商户侧状态非支付成功:视业务情况处理,更新状态为支付成功并发货,或发起退款。
- 订单匹配失败(商户系统找不到记录):这是异常情况,优先排查查单/回调逻辑是否存在 bug,别先怀疑账有问题。
对账单是最后一道防线,前面查单链路全部失效时靠它收口。