商家转账回调通知(用户确认模式)
更新时间:2024.12.27微信支付系统通过商家转账回调通知接口通知商户系统单据处理到终态。
注意
1、同样的通知可能会多次发送给商户系统。商户系统需要重视对重复通知的正确处理。
当商户系统收到通知时,先检查对应业务数据状态:
(1)如果未处理,进行处理;
(2)如果已处理,则直接返回结果成功;
在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
2、如果在所有通知频率后仍没有收到微信侧回调,商户应主动调用查询订单接口确认订单状态。
3、商户系统对于支付成功通知的内容一定要做签名验证,并校验通知的信息是否与商户侧的信息一致,防止数据泄露导致出现“假通知”,造成资金损失。
# 接口说明
支持商户: 【普通商户】
请求方式: POST
回调URL: 该链接是通过商家转账的请求参数“notify_url”来设置的,要求必须为HTTPS地址。请确保回调URL是外部可正常访问的,且不能携带后缀参数,否则可能导致商户无法接收到微信的回调通知信息。回调URL示例:https://pay.weixin.qq.com/wxpay/pay.action (opens new window)
# 通知规则
商家转账单据到终态后 (转账完成、转账失败和已撤销,对应单据状态status的值为SUCCESS、FAIL和CANCELLED),微信支付会把单据的信息发送给商户,商户需要接收处理该消息,并返回应答。
对后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为0s/15s(尝试10次)/300s(尝试10次)/1800s(尝试44次))
# 通知报文
通知的数据以JSON格式通过请求主体(BODY)传输。通知的数据包括了加密的授权/解除授权结果详情。
注意
由于涉及到回调加密和解密,商户必须先设置好APIv3密钥后才能解密回调通知,APIv3密钥设置文档指引详见 APIv3密钥设置指引 (opens new window)
# 步骤说明
# 步骤一:验证签名
微信支付会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考 《微信支付API v3签名验证》。
# 步骤二:参数解密
为了保证安全性,微信支付在回调通知,对关键信息进行了AES-256-GCM加密。商户应当按照以下的流程进行解密关键信息,解密的流程:
- 用商户平台上设置的APIv3密钥【微信商户平台 (opens new window)—>账户设置—>API安全—>设置APIv3密钥】,记为key;
- 获取resource.algorithm中描述的算法(目前为AEAD_AES_256_GCM),以及resource.nonce和resource.associated_data;
- 使用key、nonce和associated_data,对数据密文resource.ciphertext进行解密,得到JSON形式的资源对象。
注意
- AEAD_AES_256_GCM算法的接口细节,请参考rfc5116 (opens new window)。微信支付使用的密钥key长度为32个字节,随机串nonce长度12个字节,associated_data长度小于16个字节并可能为空。
- Java回调解密Json取值不带引号。
# 通知参数
- id 必填【通知ID】
通知的唯一ID - create_time 必填【通知创建时间】
通知创建的时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。 - event_type 必填【通知类型】
通知的类型,商家转账通知的类型为MCHTRANSFER.BILL.FINISHED - resource_type 必填【通知数据类型】
通知的资源数据类型,商家转账通知为encrypt-resource - resource 必填【通知数据】
json格式 - summary 必填【回调摘要】
回调摘要
resource的格式:
- algorithm 必填【加密算法类型】
对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM - ciphertext 必填【数据密文】
Base64编码后的开启/停用结果数据密文 - associated_data 选填【附加数据】
附加数据 - original_type 必填【原始类型】
原始回调类型,为mch_payment - nonce 必填【随机串】
加密使用的随机串
当 event_type为MCHTRANSFER.BILL.FINISHED时,数据密文ciphertext解密之后的内容
ObjectBillFinished json结构:
- out_bill_no 必填【商户单号】
商户系统内部的商家单号,在商户系统内部唯一 - transfer_bill_no 必填【商家转账订单号】
微信单号,微信商家转账系统返回的唯一标识 - state 必填【单据状态】
ACCEPTED:单据已受理
PROCESSING:单据处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够
WAIT_USER_CONFIRM:待收款用户确认,可拉起微信收款确认页面进行收款确认
TRANSFERING:转账中,转账结果尚未明确,可拉起微信收款确认页面再次重试确认收款
SUCCESS: 转账成功
FAIL: 转账失败
CANCELING: 撤销中
CANCELLED: 已撤销 - mchid 必填【商户号】
微信支付分配的商户号 - transfer_amount 必填【转账金额】
转账总金额,单位为“分”。 - openid 选填【收款用户OpenID】
商户AppID下,某用户的OpenID - fail_reason 选填【失败原因】
订单已失败或者已退资金时,返回失败原因 - create_time 必填【单据创建时间】
遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。 - update_time 必填【最后一次状态变更时间】
遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss.表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
# 通知应答
接收成功:HTTP应答状态码需返回200,无需返回应答报文。 接收失败:HTTP应答状态码需返回5XX或4XX,同时需返回应答报文,格式如下:
- code 必填【返回状态码】
错误码,SUCCESS为接收成功,其他错误码为失败。 - message 必填【返回信息】
返回信息,如非空,为错误原因。
# 通知报文示例
header
1Content-Length: 756^M2User-Agent: Mozilla/4.0^M3Content-Type: application/json^M4Wechatpay-Nonce: LJCTbBBiwMkAzH80tCHsYYsMV6z5Ry7Z^M5Wechatpay-Timestamp: 1692175414^M6Wechatpay-Serial: 69B46F3CF558D60F47E6D4BAF8189C202275B397^M7Wechatpay-Signature: WECHATPAY/SIGNTEST/nTCS+cEBgZACF+F2fBpy+G2oIcwUWsmhMc/bWGy7iiA0pZiIuke+KMUmAJOAXDYUFiXgjKZ8U/haDTlH7+BMGOk7BKFNB6htmByGW2P78iwOQ0jzhHVyaRqNCl8soZF/KoqQyMzWktvfH1+Dv3QJn6ntHskjdetggPQUY6PDrVLVb6o4w67+vPBkusYJdHPAozoGW02ghDU8xT3F2ZI38m7Vx1zDPMLivvlQXRxHz6JJDmZAXKdx1Z1nKSIXR8JlkB2Ct5efogSynK77OgyOY6s9FHNAXm0UXarCCkGK7VwrvSFO3c+I3H60CA3dFJRMHPuIHW+z+y9LTw==^M8Wechatpay-Signature-Type: WECHATPAY2-SHA256-RSA2048^M9Pragma: no-cache^M10Connection: Keep-Alive^M11Host: wxpay.oa.com^M12Accept: */*^M13^M
body
1{2 "id": "1c8192d8-aba1-5898-a79c-7d3abb72eabe",3 "create_time": "2023-08-16T16:43:27+08:00",4 "resource_type": "encrypt-resource",5 "event_type": "MCHTRANSFER.BILL.FINISHED",6 "summary": "商家转账单据终态通知",7 "resource": {8 "original_type": "mch_payment",9 "algorithm": "AEAD_AES_256_GCM",10 "ciphertext": "zTBf6DDPzZSoIBkoLFkC+ho97QrqnT6UU/ADM0tJP07ITaFPek4vofQjmclLUof78NqrPcJs5OIBl+gnKKJ4xCxcDmDnZZHvev5o1pk4gwtJIFIDxbq3piDr4Wq6cZpvGPPQTYC8YoVRTdVeeN+EcuklRrmaFzv8wCTSdI9wFJ9bsxtLedhq4gpkKqN5fbSguQg9JFsX3OJeT7KPfRd6SD1gu4Lpw5gwxthfOHcYsjM/eY5gaew8zzpN6mMUEJ1HqkNuQgOguHBxFnqFPiMz+Iadw7X38Yz+IgfUkOhN1iuvMhGYKbwKJ7rTiBVvGGpF6Wse1zFKgSiTLH2RnUAMkkHmxqk+JhbQKZpSWr6O8BfhHO1OKg7hpcHZtOJKNMjIF62WYDVf36w1h8h5fg==",11 "associated_data": "mch_payment",12 "nonce": "DdF3UJVNQaKT"13 }14}
解密后单据信息
1{2 "mchid" : "1900001109",3 "out_bill_no" : "plfk2020042013",4 "transfer_bill_no" : "1330000071100999991182020050700019480001",5 "state" : "ACCEPTED",6 "transfer_amount" : 400000,7 "fail_reason" : "PAYEE_ACCOUNT_ABNORMAL",8 "openid" : "o-MYE42l80oelYMDE34nYD456Xoy",9 "create_time" : "2015-05-20T13:29:35.120+08:00",10 "update_time" : "example_update_time"11}