為了在保證支付安全的前提下,帶給商戶簡單、一致且易用的開發(fā)體驗,我們推出了全新的微信支付APIv3接口。該版本API的具體規(guī)則請參考“APIv3接口規(guī)則”
為了幫助開發(fā)者調(diào)用開放接口,我們提供了Java、PHP、GO語言版本的開發(fā)庫,封裝了簽名生成、簽名驗證、敏感信息加/解密、媒體文件上傳等基礎(chǔ)功能
文檔展示了如何使用微信支付服務(wù)端 SDK 快速接入掃碼支付產(chǎn)品,完成與微信支付對接的部分。
? 文檔中的代碼示例是用來闡述 API 基本使用方法,代碼中的示例參數(shù)需替換成商戶自己賬號及請求參數(shù)才能跑通。
? 以下接入步驟僅提供參考,請商戶結(jié)合自身業(yè)務(wù)需求進行評估、修改。
步驟說明:通過本接口提交微信支付APP支付訂單,獲取預(yù)支付交易單prepay_id。
代碼示例
@Test
//Call Unified Order API
public void unifiedOrderTest() throws IOException {
String unifiedOrderBody = String.join("\n" ,
"{" ,
"'sp_appid': 'wx2421b1c4370ec43b'," ,
"'sp_mchid': '10000100'," ,
"'sub_mchid': '20000100'," ,
"'sub_appid': 'wx352671b037b437ec'," ,
"'out_trade_no': '20150806125346'," ,
"'merchant_category_code': '1011'," ,
"'payer': {" ,
"'sp_openid': 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o'" ,
"}," ,
"'notify_url': 'https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php'," ,
"'trade_type': 'APP'," ,
"'amount': {" ,
"'total': 10000," ,
"'currency': 'HKD'" ,
"}," ,
"'attach': 'Payment test'," ,
"'description': 'In-APP Pay test'," ,
"'goods_tag': '," ,
"'detail': {" ,
"'cost_price': 10000," ,
"'receipt_id': '1234'," ,
"'goods_detail': [{" ,
"'goods_id': 'iphone6s_16G'," ,
"'wxpay_goods_id': '1001'," ,
"'goods_name': 'iPhone6s 16G'," ,
"'quantity': 1," ,
"'price': 528800" ,
"}]" ,
"}," ,
"'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'" ,
"}" ,
"}" ,
"}").replace("'","\"");
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/transactions/app");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(unifiedOrderBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
重要參數(shù):
notify_url: 接受異步支付結(jié)果回調(diào)通知的地址,通知url必須為外網(wǎng)可訪問的url,不能攜帶參數(shù)。請使用https協(xié)議鏈接
out_trade_no: 商戶系統(tǒng)內(nèi)部訂單號
其他重要參數(shù)請前往APP支付下單API文檔頁面參考。
步驟說明:通過APP支付下單接口獲取到發(fā)起支付的必要參數(shù)prepay_id,可以按照接口定義中的規(guī)則,使用微信支付提供的SDK調(diào)起APP支付。
APP調(diào)起支付的參數(shù)需要按照簽名規(guī)則進行簽名計算
構(gòu)造簽名串
簽名串一共有四行,每一行為一個參數(shù)。行尾以\n(換行符,ASCII編碼值為0x0A)結(jié)束,包括最后一行。
如果參數(shù)本身以\n結(jié)束,也需要附加一個\n
參與簽名的字段及格式:
應(yīng)用id
時間戳
隨機字符串
預(yù)支付交易會話ID
待簽名串舉例:
wx8888888888888888
1414561699
5K8264ILTKch16CQ2502SI8ZNMTM67VS
WX1217752501201407033233368018
計算簽名值:
絕大多數(shù)編程語言提供的簽名函數(shù)支持對簽名數(shù)據(jù) 進行簽名。強烈建議商戶調(diào)用該類函數(shù),使用商戶私鑰對待簽名串進行SHA256 with RSA簽名,并對簽名結(jié)果進行Base64編碼得到簽名值。
$ echo -n -e \
"wx8888888888888888\n1414561699\n5K8264ILTKCH16CQ2502SI8ZNMTM67VS\nWX1217752501201407033233368018\n" \
| openssl dgst -sha256 -sign apiclient_key.pem \
| openssl base64 -A
uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9Bx7cob8H/4nLBiCwIUFluw==
代碼示例
PayReq *request = [[[PayReq alloc] init] autorelease];
request.partnerId = @"10000100";
request.prepayId= @"1101000000140415649af9fc314aa427";
request.package = @"Sign=WXPay";
request.nonceStr= @"a462b76e7436e98e0ed6e13c64b4fd1c";
request.timeStamp= @"1397527777";
request.sign= @"oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==";
[WXApi sendReq:request];
重要參數(shù):
paySign:構(gòu)造的支付簽名
package:暫填寫固定值Sign=WXPay
其他重要參數(shù)請前往APP調(diào)起支付文檔頁面參考。
步驟說明:商戶在用戶下單一定時間后,需主動進行查單以確認(rèn)訂單狀態(tài)。
代碼示例
@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
}
重要參數(shù):
id: 微信支付訂單號
out_trade_no:商戶內(nèi)部訂單號
可以用上述任一訂單號進行查詢。其他重要參數(shù)請前往查詢訂單API文檔頁面參考。
步驟說明:支付完成支付狀態(tài)為SUCCESS后,可以調(diào)用該接口提交退款請求。
代碼示例
@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
}
重要參數(shù):
out_trade_no: 商戶內(nèi)部訂單號
transaction_id: 微信訂單號
out_refund_no: 商戶內(nèi)部退款單號,應(yīng)與訂單號一一對應(yīng)
notify_url: 退款結(jié)果接收地址
其他重要參數(shù)請前往申請退款A(yù)PI文檔頁面參考。
步驟說明:提交退款申請后,通過調(diào)用該接口查詢退款狀態(tài)。
代碼示例
@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
}
重要參數(shù):
out_trade_no: 商戶內(nèi)部訂單號
refund_id:微信支付退款單號
其他重要參數(shù)請前往查詢單筆退款A(yù)PI文檔頁面參考。
步驟說明:提交退款申請后,通過調(diào)用該接口查詢一筆訂單下對應(yīng)的全部退款信息。
代碼示例
@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
}
重要參數(shù):
out_trade_no: 商戶內(nèi)部訂單號
transaction_id: 微信訂單號
offset: 分頁起始位置
count: 單頁返回的記錄數(shù),最大20條記錄.
其他重要參數(shù)請前往查詢所有退款A(yù)PI文檔頁面參考。
步驟說明:商戶每天可以通過調(diào)用該接口可以下載歷史交易賬單,通過對帳單核對后可以校對更正支付信息。
代碼示例
@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
}
重要參數(shù):
date: 賬單日期, 格式:20180103
其他重要參數(shù)請前往下載對賬單API文檔頁面參考。
步驟說明:下單超過5分鐘后,可以調(diào)用該接口對下單未支付的訂單進行關(guān)單操作,以便商戶更換訂單號重新下單發(fā)起支付或商戶系統(tǒng)退出不再受理后避免用戶繼續(xù)支付。
代碼示例
@Test
//Call close order API
public void closeOrderTest() throws IOException {
String closeBody = String.join("\n" ,
"{" ,
" 'sp_mchid': '10000100'," ,
" 'sub_mchid': '20000100'" ,
"}").replace("'","\"");
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/transactions/out-trade-no/YX001/close");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(closeBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode());
}
重要參數(shù):
out_trade_no: 商戶內(nèi)部訂單號
transaction_id: 微信支付訂單號
可以用上述任一訂單號進行查詢。其他重要參數(shù)請前往關(guān)閉訂單API文檔頁面參考。
步驟說明:在調(diào)用其他接口之前,需要調(diào)用該接口下載平臺證書用于對返回消息進行驗簽和返回消息中的加密字段進行解密。
代碼示例
@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();
}
重要參數(shù):無
其他重要參數(shù)請前往下載平臺證書API文檔頁面參考。
步驟說明:用戶完成支付后,微信支付會向下單時傳入的notify_url推送支付結(jié)果通知,商戶需要在接收到通知后返回對應(yīng)的信息。
? 同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。 推薦的做法是,當(dāng)商戶系統(tǒng)收到通知進行處理時,先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),并判斷該通知是否已經(jīng)處理。如果未處理,則再進行處理;如果已處理,則直接返回結(jié)果成功。在對業(yè)務(wù)數(shù)據(jù)進行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。
? 如果在所有通知頻率(4小時)后沒有收到微信側(cè)回調(diào),商戶應(yīng)調(diào)用查詢訂單接口確認(rèn)訂單狀態(tài)。
特別提醒:機構(gòu)系統(tǒng)對于支付結(jié)果通知的內(nèi)容一定要做簽名驗證,并校驗返回的訂單金額是否與商戶側(cè)的訂單金額一致,防止數(shù)據(jù)泄露導(dǎo)致出現(xiàn)“假通知”,造成資金損失。
用戶支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,商戶需要接收處理后返回應(yīng)答成功。只有支付成功才會通知。
對后臺通知交互時,如果微信收到應(yīng)答不是成功或超時,微信認(rèn)為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 總計 24h4m)
支付結(jié)果通知是以“POST”方法訪問商戶設(shè)置的通知url,通知的數(shù)據(jù)以“JSON”格式通過請求主體(BODY)傳輸。通知的數(shù)據(jù)包括了加密的支付結(jié)果詳情。
下面詳細(xì)描述證書解密的流程
1、從商戶平臺上獲取商戶的密鑰,記為“key”。
2、針對“algorithm”中描述的算法(目前為AEAD_AES_256_GCM),取得對應(yīng)的參數(shù)“nonce”和“associated_data”。
3、使用“key”、“nonce”和“associated_data”對數(shù)據(jù)密文“ciphertext”進行解密(需要先對ciphertext做base64解碼,然后再解密),得到證書內(nèi)容
加密不能保證通知請求來自微信。微信會對發(fā)送給商戶的通知進行簽名,并將簽名值放在通知的HTTP頭Wechatpay-Signature。商戶應(yīng)當(dāng)驗證簽名,以確認(rèn)請求來自微信,而不是其他的第三方。簽名驗證的算法請參考《微信支付API V3簽名驗證》。
支付成功結(jié)果通知
{
"id":"EV-2018022511223320873",
"create_time":"20180225112233",
"resource_type":"encrypt-resource",
"event_type":"TRANSACTION.SUCCESS",
"resource" : {
"algorithm":"AEAD_AES_256_GCM",
"ciphertext": "...",
"nonce": "...",
"associated_data": ""
}
}
商戶對resource對象進行解密后,得到的資源對象示例
{
"id": "1008450740201411110005820873",
"sp_appid": "wx2421b1c4370ec43b",
"sp_mchid": "10000100",
"sub_mchid": "20000100",
"out_trade_no": "20150806125346",
"payer": {
"sp_openid": "oUpF8uN95-Ptaags6E_roPHg7AG0"
},
"amount" : {
"total": 528800,
"currency": "HKD",
"payer_total": 518799,
"payer_currency": "CNY",
"exchange_rate" : {
"type": "SETTLEMENT_RATE",
"rate": 8000000
}
},
"trade_type": "MICROPAY",
"trade_state": "SUCCESS",
"trade_state_desc": "支付成功",
"bank_type": "CCB_DEBIT",
"attach": "支付測試",
"success_time": "2018-06-08T10:34:56+08:00",
"promotion_detail":[
{
"promotion_id":"109519",
"name":"單品惠-6",
"scope":"SINGLE",
"type":"DISCOUNT",
"amount":1,
"currency":"HKD",
"activity_id":"931386",
"wechatpay_contribute_amount":1,
"merchant_contribute_amount":0,
"other_contribute_amount":0,
"goods_detail":[
{
"goods_id":"iphone6s_16G",
"goods_remark":"商品備注",
"quantity":1,
"price":528800
}
]
}
]
}
支付通知http應(yīng)答碼為200或204才會當(dāng)作正常接收,當(dāng)回調(diào)處理異常時,應(yīng)答的HTTP狀態(tài)碼應(yīng)為500,或者4xx。
其他重要參數(shù)請前往支付結(jié)果通知API文檔頁面參考。
步驟說明:退款狀態(tài)改變后,微信會把相關(guān)退款結(jié)果發(fā)送給商戶。
? 同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。 推薦的做法是,當(dāng)商戶系統(tǒng)收到通知進行處理時,先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),并判斷該通知是否已經(jīng)處理。如果未處理,則再進行處理;如果已處理,則直接返回結(jié)果成功。在對業(yè)務(wù)數(shù)據(jù)進行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。
? 如果在所有通知頻率(4小時)后沒有收到微信側(cè)回調(diào),商戶應(yīng)調(diào)用查詢訂單接口確認(rèn)訂單狀態(tài)。
特別提醒:機構(gòu)系統(tǒng)對于支付結(jié)果通知的內(nèi)容一定要做簽名驗證,并校驗返回的訂單金額是否與商戶側(cè)的訂單金額一致,防止數(shù)據(jù)泄露導(dǎo)致出現(xiàn)“假通知”,造成資金損失。
退款狀態(tài)改變后,微信會把相關(guān)退款結(jié)果發(fā)送給商戶。
對后臺通知交互時,如果微信收到應(yīng)答不是成功或超時,微信認(rèn)為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 總計 24h4m)
退款結(jié)果通知是以“POST”方法訪問商戶設(shè)置的通知url,通知的數(shù)據(jù)以“JSON”格式通過請求主體(BODY)傳輸。通知的數(shù)據(jù)包括了加密的退款結(jié)果詳情。
下面詳細(xì)描述證書解密的流程
1、從商戶平臺上獲取商戶的密鑰,記為“key”。
2、針對“algorithm”中描述的算法(目前為AEAD_AES_256_GCM),取得對應(yīng)的參數(shù)“nonce”和“associated_data”。
3、使用“key”、“nonce”和“associated_data”對數(shù)據(jù)密文“ciphertext”進行解密(需要先對ciphertext做base64解碼,然后再解密),得到證書內(nèi)容
加密不能保證通知請求來自微信。微信會對發(fā)送給商戶的通知進行簽名,并將簽名值放在通知的HTTP頭Wechatpay-Signature。商戶應(yīng)當(dāng)驗證簽名,以確認(rèn)請求來自微信,而不是其他的第三方。簽名驗證的算法請參考《微信支付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應(yīng)答碼為200或204才會當(dāng)作正常接收,當(dāng)回調(diào)處理異常時,應(yīng)答的HTTP狀態(tài)碼應(yīng)為500,或者4xx。
其他重要參數(shù)請前往退款通知API文檔頁面參考。
步驟說明:商戶在交易完結(jié)之后,可按結(jié)算日期查詢已結(jié)算資金明細(xì)(sette_state為SETTLED),也可以查詢未結(jié)算資金明細(xì)(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
}
重要參數(shù):
settle_state: 資金結(jié)算狀態(tài),枚舉值:
SETTLED:已結(jié)算
UNSETTLE:未結(jié)算
其他重要參數(shù)請前往查詢資金結(jié)算明細(xì)API文檔頁面參考。
Customer Service Tel
Business Development
9:00-18:00
Monday-Friday GMT+8
Technical Support
WeChat Pay Global
ICP證