为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考“APIv3接口规则”
免密支付:
验密支付:
文档展示了如何使用微信支付服务端 SDK 快速接入扫码支付产品,完成与微信支付对接的部分。
• 文档中的代码示例是用来阐述 API 基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通。
• 以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。
步骤说明:通过本接口提交微信支付付款码支付订单,需要扫描用户付款码后调用。
代码示例
@Test
//Call Quick Pay Order API
public void quickPayOrderTest() throws IOException {
String requestBody = String.join("\n" ,
"{" ,
"'sp_appid': 'wxdace645e0bc2c424'," ,
"'sp_mchid': '10000100'," ,
"'sub_mchid': '20000100'," ,
"'out_trade_no': '20150806125346'," ,
"'merchant_category_code': '4111'," ,
"'payer': {" ,
"'auth_code': '134650720866361395'" ,
"}," ,
"'trade_type': 'MICROPAY'," ,
"'amount': {" ,
"'total': 1," ,
"'currency': 'HKD'" ,
"}," ,
"'attach': 'Payment Test'," ,
"'description': 'Image Store - Tencent Building in Shenzhen - QQ Doll'," ,
"'goods_tag': '1234'," ,
"'limit_pay': 'no_credit'," ,
"'detail': {" ,
"'cost_price': 1," ,
"'receipt_id': '1234'," ,
"'goods_detail': [{" ,
"'goods_id': 'iphone6s_16G'," ,
"'wxpay_goods_id': '3405'," ,
"'goods_name': 'iPhone6s 16G'," ,
"'quantity': 1," ,
"'price': 1" ,
"}]" ,
"}," ,
"'scene_info': {" ,
"'payer_client_ip': '14.23.150.211'," ,
"'device_ip': '59.37.125.32'," ,
"'device_id': '013467007045764'," ,
"'operator_id': 'P001'," ,
"'store_info': {" ,
"'id': 'SZTX001'," ,
"'name': 'Tencent Building Branch'," ,
"'address': 'Nanshan District, Shenzhen, Guangdong'" ,
"}" ,
"}" ,
"}").replace("'","\"");
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/micropay/transactions/pay");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(requestBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
重要参数:
out_trade_no: 商户系统内部订单号
auth_code: 扫码支付授权码,即用户打开微信钱包显示的支付对应的数字
其他重要参数请前往提交付款码支付API文档页面参考。
步骤说明:商户在用户下单一定时间后,需主动进行查单以确认订单状态。
代码示例
@Test
//Call query order API
public void queryOrderTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/transactions/id/" +
"4200123456789000?sub_mchid=100012321&sp_mchid=1900000000");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
重要参数:
id: 微信支付订单号
out_trade_no:商户内部订单号
可以用上述任一订单号进行查询。其他重要参数请前往查询订单API文档页面参考。
步骤说明:支付完成支付状态为SUCCESS后,可以调用该接口提交退款请求。
代码示例
@Test
//Call Refund API
public void refundTest() throws IOException {
String refundBody = String.join("\n" ,
"{" ,
"'sp_appid': 'wx2421b1c4370ec43b', " ,
"'sp_mchid': '10000100'," ,
"'sub_mchid': '20000100'," ,
"'transaction_id': '1008450740201411110005820873'," ,
"'out_refund_no': 'R20150806125346'," ,
" 'amount' : {" ,
" 'refund': 5," ,
" 'total':10," ,
" 'currency':'HKD'" ,
" }," ,
" 'reason': 'The item has been sold out.'," ,
" 'source': 'REFUND_SOURCE_UNSETTLED_FUNDS'" ,
"}").replace("'","\"");
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/refunds");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(refundBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
重要参数:
out_trade_no: 商户内部订单号
transaction_id: 微信订单号
out_refund_no: 商户内部退款单号,应与订单号一一对应
notify_url: 退款结果接收地址
其他重要参数请前往申请退款API文档页面参考。
步骤说明:提交退款申请后,通过调用该接口查询退款状态。
代码示例
@Test
//Call Query Refund API
public void querySingleRefundTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/refunds/out-refund-no/RYX001?sub_mchid=100012321&sp_mchid=1900000000");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
重要参数:
out_trade_no: 商户内部订单号
refund_id:微信支付退款单号
其他重要参数请前往查询单笔退款API文档页面参考。
步骤说明:提交退款申请后,通过调用该接口查询一笔订单下对应的全部退款信息。
代码示例
@Test
//Call Query All Refund API
public void queryAllRefundTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/refunds" +
"?out_trade_no=YX202111100020&count=10&offset=0&sp_mchid=1900000000&sub_mchid=100012321");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
重要参数:
out_trade_no: 商户内部订单号
transaction_id: 微信订单号
offset: 分页起始位置
count: 单页返回的记录数,最大20条记录.
其他重要参数请前往查询所有退款API文档页面参考。
步骤说明:商户每天可以通过调用该接口可以下载历史交易账单,通过对帐单核对后可以校对更正支付信息。
代码示例
@Test
//Downloading Reconciliation API
public void downloadReconTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/statements?date=20220401&mchid=1900000000");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
重要参数:
date: 账单日期, 格式:20180103
其他重要参数请前往下载对账单API文档页面参考。
步骤说明:下单超过5分钟后,可以调用该接口对下单未支付的订单进行关单操作,以便商户更换订单号重新下单发起支付或商户系统退出不再受理后避免用户继续支付。
代码示例
@Test
//Call revoke order API
public void RevokeOrderTest() throws IOException {
String revokeBody = String.join("\n" ,
"{" ,
" 'sp_mchid': '10000100'," ,
" 'sub_mchid': '20000100'" ,
"}").replace("'","\"");
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/micropay/transactions/out-trade-no/YX001/reverse");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(revokeBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
重要参数:
out_trade_no: 商户内部订单号
transaction_id: 微信支付订单号
out_refund_no: 商户内部退款单号,应与订单号一一对应
notify_url: 退款结果接收地址
可以用上述任一订单号进行查询。其他重要参数请前往撤销订单API文档页面参考。
步骤说明:在调用其他接口之前,需要调用该接口下载平台证书用于对返回消息进行验签和返回消息中的加密字段进行解密。
代码示例
@Test
//Call certificate downloading API
public void certDownloadingTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/certificates");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
//Get the response body: EntityUtils.toString(response.getEntity());
//Get the response status code: response.getStatusLine().getStatusCode();
//Instead of calling the API to download platform certificate,
//We also recommend use the certificateMenager to get the valid certificate
verifier.getValidCertificate();
}
重要参数:无
其他重要参数请前往下载平台证书API文档页面参考。
步骤说明:退款状态改变后,微信会把相关退款结果发送给商户。
• 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
• 如果在所有通知频率(4小时)后没有收到微信侧回调,商户应调用查询订单接口确认订单状态。
特别提醒:机构系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄露导致出现“假通知”,造成资金损失。
退款状态改变后,微信会把相关退款结果发送给商户。
对后台通知交互时,如果微信收到应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m)
退款结果通知是以“POST”方法访问商户设置的通知url,通知的数据以“JSON”格式通过请求主体(BODY)传输。通知的数据包括了加密的退款结果详情。
下面详细描述证书解密的流程
1、从商户平台上获取商户的密钥,记为“key”。
2、针对“algorithm”中描述的算法(目前为AEAD_AES_256_GCM),取得对应的参数“nonce”和“associated_data”。
3、使用“key”、“nonce”和“associated_data”对数据密文“ciphertext”进行解密(需要先对ciphertext做base64解码,然后再解密),得到证书内容
加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考《微信支付API V3签名验证》。
退款通知
{
"id": "EV-2018022511223320873",
"create_time": "2018-06-08T10:34:56+08:00",
"resource_type": "encrypt-resource",
"event_type": "REFUND.SUCCESS",
"summary": "退款成功",
"resource": {
"original_type": "refund",
"algorithm": "AEAD_AES_256_GCM",
"ciphertext": "...",
"associated_data": "",
"nonce": "..."
}
}
商户对resource对象进行解密后,得到的资源对象示例
{
"sp_mchid": "1900000100",
"sub_mchid": "1900000109",
"transaction_id": "1008450740201411110005820873",
"out_trade_no": "20150806125346",
"refund_id": "50200207182018070300011301001",
"out_refund_no": "7752501201407033233368018",
"refund_status": "SUCCESS",
"success_time": "2018-06-08T10:34:56+08:00",
"recv_account": "招商银行信用卡0403",
"fund_source": "REFUND_SOURCE_UNSETTLED_FUNDS",
"amount" : {
"total": 528800,
"currency": "HKD",
"refund": 528800,
"payer_total": 528800,
"payer_refund": 528800,
"payer_currency": "HKD",
"exchange_rate" : {
"type": "SETTLEMENT_RATE",
"rate": 100000000
}
}
}
退款通知http应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。
其他重要参数请前往退款通知API文档页面参考。
步骤说明:商户在交易完结之后,可按结算日期查询已结算资金明细(sette_state为SETTLED),也可以查询未结算资金明细(sette_state为UNSETTLE)。
代码示例
@Test
//Query Settlement API
public void querySettlementTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/settle/settlements" +
"?sub_mchid=100012321&settle_state=SETTLED&settle_start_date=20221225" +
"&settle_end_date=20221226&offset=10&limit=5");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
重要参数:
settle_state: 资金结算状态,枚举值:
SETTLED:已结算
UNSETTLE:未结算
其他重要参数请前往查询资金结算明细API文档页面参考。
Customer Service Tel
Business Development
9:00-18:00
Monday-Friday GMT+8
Technical Support
WeChat Pay Global
ICP证