為了在保證支付安全的前提下,帶給商戶簡(jiǎn)單、一致且易用的開(kāi)發(fā)體驗(yàn),我們推出了全新的微信支付APIv3接口。該版本API的具體規(guī)則請(qǐng)參考“APIv3接口規(guī)則”
為了幫助開(kāi)發(fā)者調(diào)用開(kāi)放接口,我們提供了JAVA、PHP、GO三種語(yǔ)言版本的開(kāi)發(fā)庫(kù),封裝了簽名生成、簽名驗(yàn)證、敏感信息加/解密、媒體文件上傳等基礎(chǔ)功能(更多語(yǔ)言版本的開(kāi)發(fā)庫(kù)將在近期陸續(xù)提供)
測(cè)試步驟:
1、根據(jù)自身開(kāi)發(fā)語(yǔ)言,選擇對(duì)應(yīng)的開(kāi)發(fā)庫(kù)并構(gòu)建項(xiàng)目,具體配置請(qǐng)參考下面鏈接的詳細(xì)說(shuō)明:
? wechatpay-java(推薦)wechatpay-apache-httpclient,適用于Java開(kāi)發(fā)者。
? wechatpay-php(推薦)、wechatpay-guzzle-middleware,適用于PHP開(kāi)發(fā)者
注:當(dāng)前開(kāi)發(fā)指引接口PHP示例代碼采用wechatpay-guzzle-middleware版本
? wechatpay-go,適用于Go開(kāi)發(fā)者
更多資源可前往微信支付開(kāi)發(fā)者社區(qū)搜索查看
2、創(chuàng)建加載商戶私鑰、加載平臺(tái)證書(shū)、初始化httpClient的通用方法
@Before
public void setup() throws IOException {
// 加載商戶私鑰(privateKey:私鑰字符串)
PrivateKey merchantPrivateKey = PemUtil
.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
// 加載平臺(tái)證書(shū)(mchId:商戶號(hào),mchSerialNo:商戶證書(shū)序列號(hào),apiV3Key:V3密鑰)
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));
// 初始化httpClient
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier)).build();
}
@After
public void after() throws IOException {
httpClient.close();
}
3、基于接口的示例代碼,替換請(qǐng)求參數(shù)后可發(fā)起測(cè)試
說(shuō)明:
? 上面的開(kāi)發(fā)庫(kù)為微信支付官方開(kāi)發(fā)庫(kù),其它沒(méi)有審核或者控制下的第三方工具和庫(kù),微信支付不保證它們的安全性和可靠性
通過(guò)包管理工具引入SDK后,可根據(jù)下面每個(gè)接口的示例代碼替換相關(guān)參數(shù)后進(jìn)行快速測(cè)試
? 開(kāi)發(fā)者如果想詳細(xì)了解簽名生成、簽名驗(yàn)證、敏感信息加/解密、媒體文件上傳等常用方法的具體代碼實(shí)現(xiàn),可閱讀下面的詳細(xì)說(shuō)明:
1.簽名生成
3.敏感信息加解密
5.wechatpayCertificates(平臺(tái)證書(shū))
? 如想更詳細(xì)的了解我們的接口規(guī)則,可查看我們的接口規(guī)則指引文檔
重點(diǎn)步驟說(shuō)明:
步驟2用戶確認(rèn)支付后,商戶調(diào)用微信支付Native下單API生成預(yù)支付交易以獲取支付二維碼鏈接code_url;
商戶調(diào)用NativeNative下單API后,分正常返回和異常返回情況:
步驟4: 商戶根據(jù)返回的code_url生成二維碼供用戶掃描,有關(guān)二維碼的規(guī)則請(qǐng)參考3.2.2部分的說(shuō)明
步驟9-11 : 用戶支付成功后,商戶可通過(guò)以下兩種方式獲取訂單狀態(tài)
方法一:支付結(jié)果通知。用戶支付成功后,微信支付會(huì)將支付成功的結(jié)果以回調(diào)通知的形式同步給商戶,商戶的回調(diào)地址需要在調(diào)用Native下單API時(shí)傳入notify_url參數(shù)。
方法二:當(dāng)因網(wǎng)絡(luò)抖動(dòng)或本身notify_url存在問(wèn)題等原因,導(dǎo)致無(wú)法接收到回調(diào)通知時(shí),商戶也可主動(dòng)調(diào)用查詢訂單API來(lái)獲取訂單狀態(tài)
本章節(jié)展示了如何使用微信支付服務(wù)端 SDK 快速接入Native支付產(chǎn)品,完成與微信支付對(duì)接的部分。
注意:
步驟說(shuō)明:用戶在商戶PC網(wǎng)站內(nèi)完成商品選擇后進(jìn)入支付頁(yè)面,商戶需要通過(guò)后端請(qǐng)求該Native下單API來(lái)獲取支付二維碼鏈接code_url。
示例代碼
public void CreateOrder() throws Exception{
//請(qǐng)求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/native");
// 請(qǐng)求body參數(shù)
String reqdata = "{"
+ "\"time_expire\":\"2018-06-08T10:34:56+08:00\","
+ "\"amount\": {"
+ "\"total\":100,"
+ "\"currency\":\"CNY\""
+ "},"
+ "\"settle_info\": {"
+ "\"profit_sharing\":false"
+ "},"
+ "\"sp_mchid\":\"1230000109\","
+ "\"description\":\"Image形象店-深圳騰大-QQ公仔\(zhòng)","
+ "\"sub_appid\":\"wxd678efh567hg6999\","
+ "\"notify_url\":\"https://www.weixin.qq.com/wxpay/pay.php\","
+ "\"sp_appid\":\"wx8888888888888888\","
+ "\"out_trade_no\":\"1217752501201407033233368018\","
+ "\"goods_tag\":\"WXG\","
+ "\"sub_mchid\":\"1900000109\","
+ "\"attach\":\"自定義數(shù)據(jù)說(shuō)明\","
+ "\"detail\": {"
+ "\"invoice_id\":\"wx123\","
+ "\"goods_detail\": ["
+ "{"
+ "\"goods_name\":\"iPhoneX 256G\","
+ "\"wechatpay_goods_id\":\"1001\","
+ "\"quantity\":1,"
+ "\"merchant_goods_id\":\"商品編碼\","
+ "\"unit_price\":828800"
+ "},"
+ "{"
+ "\"goods_name\":\"iPhoneX 256G\","
+ "\"wechatpay_goods_id\":\"1001\","
+ "\"quantity\":1,"
+ "\"merchant_goods_id\":\"商品編碼\","
+ "\"unit_price\":828800"
+ "}"
+ "],"
+ "\"cost_price\":608800"
+ "},"
+ "\"scene_info\": {"
+ "\"store_info\": {"
+ "\"address\":\"廣東省深圳市南山區(qū)科技中一道10000號(hào)\","
+ "\"area_code\":\"440305\","
+ "\"name\":\"騰訊大廈分店\","
+ "\"id\":\"0001\""
+ "},"
+ "\"device_id\":\"013467007045764\","
+ "\"payer_client_ip\":\"14.23.150.211\""
+ "}"
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成簽名并執(zhí)行請(qǐng)求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //處理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //處理成功,無(wú)返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
重要參數(shù)說(shuō)明:
? out_trade_no:商戶系統(tǒng)內(nèi)部訂單號(hào),只能是數(shù)字、大小寫(xiě)字母_-*且在同一個(gè)商戶號(hào)下唯一
? description:商品描述
? notify_url:支付回調(diào)通知URL,該地址必須為直接可訪問(wèn)的URL,不允許攜帶查詢串
? total:訂單總金額,單位為分
更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請(qǐng)參見(jiàn)Native下單API接口文檔
步驟說(shuō)明:通過(guò)Native下單API成功獲取支付二維碼鏈接(code_url)后,需要在前端(PC網(wǎng)頁(yè)或POS機(jī)具)生成二維碼供用戶掃描支付。
注意code_url對(duì)應(yīng)鏈接格式:weixin://weixin://www.tg885.com/bizpayurl/up?pr=NwY5Mz9&groupid=00。請(qǐng)商戶調(diào)用第三方庫(kù)將code_url生成二維碼圖片。該模式鏈接較短,生成的二維碼打印到結(jié)賬小票上的識(shí)別率較高。
例如,weixin://weixin://www.tg885.com/bizpayurl/up?pr=NwY5Mz9&groupid=00 生成二維碼見(jiàn)下圖
更多二維碼的相關(guān)背景知識(shí)可參考
步驟說(shuō)明:當(dāng)用戶完成支付,微信會(huì)把相關(guān)支付結(jié)果將通過(guò)異步回調(diào)的方式通知商戶,商戶需要接收處理,并按文檔規(guī)范返回應(yīng)答
注意:
更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請(qǐng)參見(jiàn) JSAPI / APP / H5 / Native / 小程序支付通知API接口文檔
步驟說(shuō)明:當(dāng)商戶后臺(tái)、網(wǎng)絡(luò)、服務(wù)器等出現(xiàn)異常,商戶系統(tǒng)最終未接收到支付通知時(shí),商戶可通過(guò)查詢訂單接口核實(shí)訂單支付狀態(tài)
示例代碼(通過(guò)微信訂單號(hào)查詢):
public void QueryOrder() throws Exception {
//請(qǐng)求URL
HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/id/1217752501201407033233368018?sp_mchid=1230000109&sub_mchid=1900000109");
httpGet.setHeader("Accept", "application/json");
//完成簽名并執(zhí)行請(qǐng)求
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //處理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //處理成功,無(wú)返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
注意:
更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請(qǐng)參見(jiàn) JSAPI / APP / H5 / Native / 小程序查詢訂單API接口文檔
步驟說(shuō)明:當(dāng)商戶訂單支付失敗需要生成新單號(hào)重新發(fā)起支付,要對(duì)原訂單號(hào)調(diào)用關(guān)單,避免重復(fù)支付;系統(tǒng)下單后,用戶支付超時(shí),系統(tǒng)退出不再受理,避免用戶繼續(xù),請(qǐng)調(diào)用關(guān)單接口
示例代碼:
public void CloseOrder() throws Exception {
//請(qǐng)求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/{out_trade_no}/close");
// 請(qǐng)求body參數(shù)
String reqdata = "{"
+ "\"sp_mchid\":\"1230000109\","
+ "\"sub_mchid\":\"1900000109\""
+ "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成簽名并執(zhí)行請(qǐng)求
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //處理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //處理成功,無(wú)返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
注意:
更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請(qǐng)參見(jiàn) JSAPI / APP / H5 / Native / 小程序接口文檔
步驟說(shuō)明:微信支付按天提供交易賬單文件,商戶可以通過(guò)該接口獲取賬單文件的下載地址
示例代碼:
public void TradeBill() throws Exception {
//請(qǐng)求URL
HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&sub_mchid=1900000001&bill_type=ALL");
httpGet.setHeader("Accept", "application/json");
//完成簽名并執(zhí)行請(qǐng)求
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) { //處理成功
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) { //處理成功,無(wú)返回Body
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
注意:
更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請(qǐng)參見(jiàn) JSAPI / APP / H5 / Native / 小程序接口文檔
步驟說(shuō)明:通過(guò)申請(qǐng)交易賬單接口獲取到賬單下載地址(download_url)后,再通過(guò)該接口獲取到對(duì)應(yīng)的賬單文件,文件內(nèi)包含交易相關(guān)的金額、時(shí)間、營(yíng)銷等信息,供商戶核對(duì)訂單、退款、銀行到賬等情況
示例代碼:
public void DownloadUrl(String download_url) throws Exception{
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
//初始化httpClient
//該接口無(wú)需進(jìn)行簽名驗(yàn)證、通過(guò)withValidator((response) -> true)實(shí)現(xiàn)
httpClient = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator((response) -> true).build();
//請(qǐng)求URL
//賬單文件的下載地址的有效時(shí)間為30s
URIBuilder uriBuilder = new URIBuilder(download_url);
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
//執(zhí)行請(qǐng)求
CloseableHttpResponse response = httpClient.execute(httpGet);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
} else if (statusCode == 204) {
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
}
}
注意:
? 賬單文件的下載地址的有效時(shí)間為30s
? 強(qiáng)烈建議商戶將實(shí)際賬單文件的哈希值和之前從接口獲取到的哈希值進(jìn)行比對(duì),以確認(rèn)數(shù)據(jù)的完整性
更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請(qǐng)參見(jiàn) JSAPI / APP / H5 / Native / 小程序下載賬單API接口文檔
一個(gè)二維碼的有效期是根據(jù)Native下單接口返回的code_url決定,code_url的有效期是2小時(shí)。
A:微信支付已經(jīng)不支持通過(guò)長(zhǎng)按識(shí)別二維碼的方式或通過(guò)相冊(cè)識(shí)別二維碼的方式完成支付。