為了在保證支付安全的前提下,帶給商戶簡單、一致且易用的開發(fā)體驗,我們推出了全新的微信支付APIv3接口。該版本API的具體規(guī)則請參考“APIv3接口規(guī)則”
備注:當前接口用于微信國內錢包
為了幫助開發(fā)者調用開放接口,我們提供了JAVA、PHP、GO三種語言版本的開發(fā)庫,封裝了簽名生成、簽名驗證、敏感信息加/解密、媒體文件上傳等基礎功能(更多語言版本的開發(fā)庫將在近期陸續(xù)提供)
測試步驟:
1、根據自身開發(fā)語言,選擇對應的開發(fā)庫并構建項目,具體配置請參考下面鏈接的詳細說明:
? wechatpay-java(推薦)wechatpay-apache-httpclient,適用于Java開發(fā)者。
? wechatpay-php(推薦)、wechatpay-guzzle-middleware,適用于PHP開發(fā)者
注:當前開發(fā)指引接口PHP示例代碼采用wechatpay-guzzle-middleware版本
? wechatpay-go,適用于Go開發(fā)者
更多資源可前往微信支付開發(fā)者社區(qū)搜索查看
2、創(chuàng)建加載商戶私鑰、加載平臺證書、初始化httpClient的通用方法
@Before
public void setup() throws IOException {
// 加載商戶私鑰(privateKey:私鑰字符串)
PrivateKey merchantPrivateKey = PemUtil
.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
// 加載平臺證書(mchId:商戶號,mchSerialNo:商戶證書序列號,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、基于接口的示例代碼,替換請求參數后可發(fā)起測試
說明:
? 上面的開發(fā)庫為微信支付官方開發(fā)庫,其它沒有審核或者控制下的第三方工具和庫,微信支付不保證它們的安全性和可靠性
通過包管理工具引入SDK后,可根據下面每個接口的示例代碼替換相關參數后進行快速測試
? 開發(fā)者如果想詳細了解簽名生成、簽名驗證、敏感信息加/解密、媒體文件上傳等常用方法的具體代碼實現,可閱讀下面的詳細說明:
1.簽名生成
2.簽名驗證
3.敏感信息加解密
? 如想更詳細的了解我們的接口規(guī)則,可查看我們的接口規(guī)則指引文檔
● 前往微信支付商戶平臺—>產品中心—>H5支付—>申請開通
● 登錄【微信支付商戶平臺—>產品中心—>開發(fā)配置—>H5支付】,設置后一般10分鐘內生效。
注意:
重點步驟說明:
步驟1 用戶向商戶系統(tǒng)后臺請求下單,商戶后臺必須做好安全校驗
Access-Control-Allow-*
相關頭部 Access-Control-Allow-*
相關頭部 步驟2 商戶可通過H5下單API創(chuàng)建支付訂單。
步驟3 用戶通過微信外部的瀏覽器調起微信支付中間頁,進行發(fā)起支付請求。
步驟5 用戶支付成功后,商戶可接收到微信支付支付結果通知支付通知API
步驟8 商戶在沒有接收到微信支付結果通知的情況下需要主動調用查詢訂單API查詢支付結果。
注意:
本文檔展示了如何使用微信支付服務端 SDK 快速接入H5支付產品,完成與微信支付對接的部分。
注意:
步驟說明:用戶使用微信外部的瀏覽器訪問商戶H5頁面,當用戶選擇相關商品購買時,商戶系統(tǒng)先調用該接口在微信支付服務后臺生成預支付交易單。
示例代碼
public void CreateOrder() throws Exception{
//請求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/h5");
// 請求body參數
String reqdata = "{"
+ "\"amount\": {"
+ "\"total\": 100,"
+ "\"currency\": \"CNY\""
+ "},"
+ "\"scene_info\": {"
+ "\"payer_client_ip\":\"14.23.150.211\","
+ "\"h5_info\": {"
+ "\"type\": \"IOS\"" + "}},"
+ "\"mchid\": \"1900006891\","
+ "\"description\": \"Image形象店-深圳騰大-QQ公仔\(zhòng)","
+ "\"notify_url\": \"https://www.weixin.qq.com/wxpay/pay.php\","
+ "\"out_trade_no\": \"1217752501201407033233388881\","
+ "\"goods_tag\": \"WXG\","
+ "\"appid\": \"wxdace645e0bc2c424\"" + "}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成簽名并執(zhí)行請求
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) {
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();
}
}
重要參數說明:
? out_trade_no:商戶系統(tǒng)內部訂單號,只能是數字、大小寫字母_-*且在同一個商戶號下唯一
? description:商品描述
? notify_url:支付回調通知URL,該地址必須為直接可訪問的URL,不允許攜帶查詢串
? total:訂單總金額,單位為分
? scene_info:支付場景描述
更多參數、響應詳情及錯誤碼請參見H5下單API接口文檔
步驟說明:通過H5下單API成功獲取H5下單返回的支付中間頁(h5_url)后,用戶需要通過微信外部的瀏覽器調起微信支付收銀臺
注意:
由于設置redirect_url后,回跳指定頁面的操作可能發(fā)生在:
1、微信支付中間頁調起微信收銀臺后超過5秒
2、用戶點擊“取消支付”或支付完成后點擊“完成”按鈕。因此無法保證頁面回跳時,支付流程已結束,所以商戶設置的redirect_url地址不能自動執(zhí)行查單操作,應讓用戶去點擊按鈕觸發(fā)查單操作,回跳頁面展示效果可參考下圖
步驟說明:當用戶完成支付,微信會把相關支付結果將通過異步回調的方式通知商戶,商戶需要接收處理,并按文檔規(guī)范返回應答
注意:
步驟說明:當商戶后臺、網絡、服務器等出現異常,商戶系統(tǒng)最終未接收到支付通知時,商戶可通過查詢訂單接口核實訂單支付狀態(tài)
示例代碼(通過微信訂單號查詢):
public void QueryOrder() throws Exception {
//請求URL
URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/id/4200000745202011093730578574");
uriBuilder.setParameter("mchid", mchId);
//完成簽名并執(zhí)行請求
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
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();
}
}
注意:
步驟說明:當商戶訂單支付失敗需要生成新單號重新發(fā)起支付,要對原訂單號調用關單,避免重復支付;系統(tǒng)下單后,用戶支付超時,系統(tǒng)退出不再受理,避免用戶繼續(xù),請調用關單接口
示例代碼:
public void CloseOrder() throws Exception {
//請求URL
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/sdkphp12345678920201028112429/close");
//請求body參數
String reqdata ="{\"mchid\": \""+mchId+"\"}";
StringEntity entity = new StringEntity(reqdata,"utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
//完成簽名并執(zhí)行請求
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) {
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();
}
}
注意:
步驟說明:微信支付按天提供交易賬單文件,商戶可以通過該接口獲取賬單文件的下載地址
示例代碼:
public void TradeBill() throws Exception {
//請求URL
URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/bill/tradebill");
uriBuilder.setParameter("bill_date", "2020-11-09");
uriBuilder.setParameter("bill_type", "ALL");
//完成簽名并執(zhí)行請求
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
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();
}
}
注意:
步驟說明:通過申請交易賬單接口獲取到賬單下載地址(download_url)后,再通過該接口獲取到對應的賬單文件,文件內包含交易相關的金額、時間、營銷等信息,供商戶核對訂單、退款、銀行到賬等情況
示例代碼:
public void DownloadUrl(String download_url) throws Exception{
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
//初始化httpClient
//該接口無需進行簽名驗證、通過withValidator((response) -> true)實現
httpClient = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator((response) -> true).build();
//請求URL
//賬單文件的下載地址的有效時間為30s
URIBuilder uriBuilder = new URIBuilder(download_url);
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.addHeader("Accept", "application/json");
//執(zhí)行請求
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();
}
}
注意:
? 賬單文件的下載地址的有效時間為30s
? 強烈建議商戶將實際賬單文件的哈希值和之前從接口獲取到的哈希值進行比對,以確認數據的完整性
A:請按以下幾點進行排查:
A:請按以下幾點進行排查:
A:H5下單返回的H5_URL生成后,有效期為5分鐘,如超時請重新生成H5_URL后再發(fā)起支付
A:H5支付不能直接在微信客戶端內調起,請在外部瀏覽器調起
A:請按以下幾點進行排查:
2,如H5_URL有添加redirect_url,請確認參數拼接格式是否有誤,是否有對redirect_url的值做urlencode,可參考以下例子格式:
https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn
A:完成H5支付后需通過schame信息返回調起支付的瀏覽器,但由于部分瀏覽器隱藏了這個信息,在無法拿到schame信息的情況下,就會默認回到safari瀏覽器