為了在保證支付安全的前提下,帶給商戶簡單、一致且易用的開發(fā)體驗(yàn),我們推出了全新的微信支付APIv3接口。該版本API的具體規(guī)則請參考“APIv3接口規(guī)則”
為了幫助開發(fā)者調(diào)用開放接口,我們提供了Java、PHP、GO語言版本的開發(fā)庫,封裝了簽名生成、簽名驗(yàn)證、敏感信息加/解密、媒體文件上傳等基礎(chǔ)功能
文檔展示了如何使用微信支付服務(wù)端 SDK 快速接入JSAPI支付產(chǎn)品,完成與微信支付對接的部分。
注意:
文檔中的代碼示例是用來闡述 API 基本使用方法,代碼中的示例參數(shù)需替換成商戶自己賬號及請求參數(shù)才能跑通。
以下接入步驟僅提供參考,請商戶結(jié)合自身業(yè)務(wù)需求進(jìn)行評估、修改。
步驟說明:如 時序圖2.2步驟 描述,當(dāng)用戶在商戶小程序中選擇同意使用代扣產(chǎn)品時,商戶應(yīng)請求小程序-預(yù)簽約API 以獲得預(yù)簽約ID session_id,供下一步調(diào)起簽約小程序使用。
代碼示例 - JAVA:
//Obtaining Signing Session ID API for mini-program signing
public void miniProgramSignTest() throws IOException {
String miniprogramSignBody = """{
"expired_time": "2021-11-20T13:29:35+08:00",
"openid": "of8YZ6A_ySrPYzjX7joXo_0000",
"out_contract_code": "20220614out_contract_code",
"plan_id": 10001,
"sp_appid": "wx7bc9000000000000",
"sub_mchid": "90325355",
"success_notify_url": "https://yoursite.com",
"user_display_name": "mike"
}""";
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/miniprogram-pre-entrust-sign");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(miniprogramSignBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
示例代碼 - PHP:
//Mini Program Signing API
public function miniProgramSigning($instance)
{
try {
$resp = $instance
->chain('v3/global/papay/contracts/miniprogram-pre-entrust-sign')
->post([
'json' => [
"sp_appid" => "wx7bc9000000000000",
"sub_mchid" => "90325355",
"openid" => "of8YZ6A_ySrPYzjX7joXo_0000",
"out_contract_code" => "20220614out_contract_code",
"plan_id" => 10001,
"success_notify_url" => "https://www.yoursite.com",
"user_display_name" => "mike",
"expired_time" => "2021-11-20T13:29:35+08:00",
]
]);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (\Exception $e) {
// Exception handling
}
}
示例代碼 - GO:
//Mini program signing API
func miniProgramSigning() {
signBody := `{
"expired_time": "2021-11-20T13:29:35+08:00",
"openid": "of8YZ6A_ySrPYzjX7joXo_0000",
"out_contract_code": "20220614out_contract_code",
"plan_id": 10001,
"sp_appid": "wx7bc9000000000000",
"sub_mchid": "90325355",
"success_notify_url": "https://yoursite.com",
"user_display_name": "mike"
}`
result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/miniprogram-pre-entrust-sign", signBody)
if err != nil {
// Process error
}
log.Printf("%s", result.Response.Body)
步驟說明:
解析 3.1小程序預(yù)簽約 接口返回的 Body json字符串,獲取其中的 session_id,返回示例: { "session_id": "201710180325670965" }
使用上一步得到的 session_id 參數(shù)拉起簽約小程序
示例代碼:
var session_id = "201710180325670965"; // obtained from miniprogram-pre-entrust-sign
// start signing process
wx.navigateToMiniProgram({
appId: wxbd687630cd02ce1d,
path: 'pages/Oversea/walletSelect?sessionId=' + session_id,
extraData: {},
success(res) {
// Jumped to the signing mini program successfully
},
fail(res) {
// Failed to jump to the signing mini program
}
})
// After signing process, user will return back to merchant's miniprogram
App({
onShow(res) {
if (res.scene === 1038) { //Scenario value 1038: return from the opened min program
const { appId, extraData } = res.referrerInfo
if (appId == 'wxbd687630cd02ce1d') { // appId is wxbd687630cd02ce1d: jump back from the signing min program
if (typeof extraData == 'undefined') {
// TODO
// The client min program is not sure of the signing result and needs to request the merchant-side background to confirm the signing result
return;
}
if (extraData.return_code == 'SUCCESS') {
// TODO
// The client min program signs successfully and needs to request the merchant-side background to confirm the signing result
var contract_id = extraData.contract_id
return;
}
else {
// TODO
// Signing failed
return;
}
}
}
}
})
步驟說明:用戶完成簽約后,微信支付會向發(fā)起簽約時傳入的success_notify_url推送簽約結(jié)果通知,商戶需要在接收到通知后返回對應(yīng)的信息。
簽約通知示例
// 簽約成功回調(diào) http body 數(shù)據(jù)示例
{
"id":"EV-2018022511223320873",
"create_time":"2022-06-14T14:01:35+08:00",
"resource_type":"encrypt-resource",
"event_type":"PAPAY.SIGN",
"summary": "簽約成功",
"resource" : {
"algorithm":"AEAD_AES_256_GCM",
"ciphertext": "...",
"nonce": "dAvnRJWFOfdL",
"associated_data": "papay"
}
}
// 對 resource.ciphertext 解密后得到的數(shù)據(jù)示例如下:
{
"sp_mchid":"10000091",
"sub_mchid":"10000097",
"out_contract_code":"100001256",
"plan_id":123,
"contract_id":"Wx15463511252015071056489715",
"sp_appid":"wxcbda96de0b165486",
"openid":"ouFhd5X9s9WteC3eWRjXV3lea123",
"operate_time":"2015-09-01T10:00:00+08:00"
}
// 解約成功回調(diào) http body 數(shù)據(jù)示例
{
"id":"2646bee0-aef8-5804-9752-ef1a56170fdf",
"create_time":"2022-06-14T16:31:53+08:00",
"resource_type":"encrypt-resource",
"event_type":"PAPAY.TERMINATE",
"summary":"解約成功",
"resource":{
"original_type":"papay",
"algorithm":"AEAD_AES_256_GCM",
"ciphertext": "...",
"associated_data":"papay",
"nonce":"SExJ2Xxx7sr1"
}
}
// 對 resource.ciphertext 解密后得到的數(shù)據(jù)示例如下:
{
"sp_mchid": "10000091",
"sub_mchid": "10000097",
"out_contract_code": "100001256",
"plan_id": 123,
"contract_id": "Wx15463511252015071056489715",
"sp_appid": "wxcbda96de0b165486",
"openid": "ouFhd5X9s9WteC3eWRjXV3lea123",
"contract_termination_mode": "USER",
"operate_time": "2015-10-01T10:00:00+08:00"
}
當(dāng)商戶接收到微信支付回調(diào)通知時,應(yīng)更新本地存儲的用戶簽約狀態(tài),更新完成后返回如下 http body給微信支付,http狀態(tài)應(yīng)設(shè)置為200。
{
"code": "SUCCESS",
"message": "OK"
}
步驟說明:當(dāng)商戶后臺、網(wǎng)絡(luò)、服務(wù)器等出現(xiàn)異常,商戶系統(tǒng)最終未接收到簽約結(jié)果通知時商戶可通過查詢簽約結(jié)果API核實(shí)簽約狀態(tài)。微信支付提供了兩種查詢簽約狀態(tài)的方式,一種是通過商戶簽約號即out_contract_code,另一種是通過微信支付返回的微信簽約號contract_id。
JAVA - 示例代碼:
通過商戶簽約號out_contract_code查詢簽約狀態(tài)
//Querying Signing Status (By out_contract_code)
public void querySignStatusByContractCodeTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/out-contract-code/100001261?sp_appid=wxcbda96de0b165486&sub_appid=wxcbda96de0b165484&plan_id=123");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
通過微信簽約號contract_id查詢簽約狀態(tài)
//Querying Signing Status (By contract_id) API
public void querySignStatusTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/202203242337333903387184301572?sub_mchid=10000097&sp_appid=wxcbda96de0b165486&sub_appid=wxcbda96de0b165484");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
PHP - 示例代碼:
通過商戶簽約號out_contract_code查詢簽約狀態(tài)
//Querying Signing Status (By out_contract_code) API
public function querySignStatusByContractCode($instance)
{
try {
$resp = $instance
->v3->global->papay->contracts->outContractCode->_out_contract_code_
->get([
'query' => [
'sp_appid' => 'wxcbda96de0000006',
'sub_appid' => 'wxcbda96de0000004',
'sub_mchid' => '110000000'
],
'_out_contract_code_' => '100005698'
]);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (\Exception $e) {
// Exception handling
}
}
通過微信簽約號contract_id查詢簽約狀態(tài)
//Querying Signing Status (By contract_id) API
public function querySignStatus($instance)
{
try {
$resp = $instance
->v3->global->papay->contracts->_contract_id_
->get([
'query' => [
'sp_appid' => 'wxcbda96de0000006',
'sub_appid' => 'wxcbda96de0000004',
'sub_mchid' => '110000000'
],
'contract_id' => '202203242337333903387184301572'
]);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (\Exception $e) {
// Exception handling
}
}
GO - 示例代碼:
通過商戶簽約號out_contract_code查詢簽約狀態(tài)
//Querying signing status by out_contract_code API
func querySigningStatusByContractCode() {
result, err := client.Get(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/out-contract-code/100001261?sp_appid=wxcbda96de0b165486&sub_appid=wxcbda96de0b165484&plan_id=123")
if err != nil {
// Process error
}
log.Printf("status=%d resp=%s", result.Response.StatusCode, result.Response.Body)
}
通過微信簽約號contract_id查詢簽約狀態(tài)
//Querying signing status API
func querySigningStatus() {
result, err := client.Get(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/202203242337333903387184301572?sub_mchid=10000097&sp_appid=wxcbda96de0b165486&sub_appid=wxcbda96de0b165484")
if err != nil {
// Process error
}
log.Printf("status=%d resp=%s", result.Response.StatusCode, result.Response.Body)
}
重要參數(shù):
步驟說明:在完成簽約后,商戶可使用對應(yīng)的協(xié)議ID發(fā)起扣款
代碼示例 - JAVA:
//Applying for Termination API
public void deductionTest() throws IOException {
String deductionBody = """
{
"sp_appid": "wxcbda96de0b165486",
"sub_mchid": "10000097",
"sub_appid": "wxcbda96de0b165484",
"description": "PAPAuto-debit支付測試",
"attach": "支付測試",
"notify_url": "https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php",
"out_trade_no": "1217752501201407033233368018",
"goods_tag": "WXG",
"merchant_category_code": "1011",
"contract_id": "Wx15463511252015071056489715",
"amount": {
"total": 10000,
"currency": "HKD"
},
"scene_info": {
"device_ip": "59.37.125.32",
"device_id": "013467007045764"
}
}
""";
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(deductionBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
示例代碼 - PHP:
//Deduction API
public function deduction($instance)
{
try {
$resp = $instance
->v3->global->papay->transactions
->post([
'json' => [
"sp_appid" => "wxcbda96de0b165486",
"sub_mchid" => "10000097",
"sub_appid" => "wxcbda96de0b165484",
"description" => "PAPAuto-debit支付測試",
"attach" => "支付測試",
"notify_url" => "https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php",
"out_trade_no" => "1217752501201407033233368018",
"goods_tag" => "WXG",
"merchant_category_code" => "1011",
"contract_id" => "Wx15463511252015071056489715",
"amount" => array(
"total" => 10000,
"currency" => "HKD"
),
"scene_info" => array(
"device_ip" => "59.37.125.32",
"device_id" => "013467007045764"
)
]
]);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (\Exception $e) {
// Exception handling
}
}
示例代碼 - GO:
//Deduction API
func deduction() {
body := `
{
"sp_appid": "wxcbda96de0b165486",
"sub_mchid": "10000097",
"sub_appid": "wxcbda96de0b165484",
"description": "PAPAuto-debit支付測試",
"attach": "支付測試",
"notify_url": "https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php",
"out_trade_no": "1217752501201407033233368018",
"goods_tag": "WXG",
"merchant_category_code": "1011",
"contract_id": "Wx15463511252015071056489715",
"amount": {
"total": 10000,
"currency": "HKD"
},
"scene_info": {
"device_ip": "59.37.125.32",
"device_id": "013467007045764"
}
}
`
result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions", body)
if err != nil {
// Process error
}
log.Printf("%s", result.Response.Body)
}
重要參數(shù):
步驟說明:扣款成功后,微信支付會以異步通知的方式通過扣款請求中的 notify_url 參數(shù)告知商戶扣款已成功。
// 扣款結(jié)果通知 http body 數(shù)據(jù)示例
{
"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.ciphertext 解密后得到的數(shù)據(jù)示例如下:
{
"sp_mchid": "10000100",
"sp_appid": "wx2421b1c4370ec43b",
"sub_mchid": "20000100",
"out_trade_no": "20150806125346",
"transaction_id": "1008450740201411110005820873",
"attach": "支付測試",
"trade_type": "AUTH",
"bank_type": "CCB_DEBIT",
"success_time": "2018-06-08T10:34:56+08:00",
"trade_state": "SUCCESS",
"trade_state_desc": "支付成功",
"merchant_category_code": "1011",
"contract_id": "Wx15463511252015071056489715",
"payer": {
"sp_openid": "oUpF8uN95-Ptaags6E_roPHg7AG0"
},
"amount": {
"total": 528800,
"currency": "HKD",
"payer_total": 518799,
"payer_currency": "CNY",
"exchange_rate": {
"type": "SETTLEMENT_RATE",
"rate": 8000000
}
},
"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
}]
}]
}
步驟說明:當(dāng)商戶后臺、網(wǎng)絡(luò)、服務(wù)器等出現(xiàn)異常,商戶系統(tǒng)最終未接收到支付通知時商戶可通過查詢訂單接口核實(shí)訂單支付狀態(tài)。
代碼示例 - JAVA:
//Query transaction details by transaction_id
public void queryOrderByIdTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/4015463511252015071056489715?sub_mchid=10000097");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
//Query transaction details by out_trade_no
public void queryOrderByNoTest() throws IOException {
HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out_trade_no/1217752501201407033233368018?sub_mchid=10000097");
httpGet.addHeader("Accept", "application/json");
httpGet.addHeader("Content-type", "application/json; charset=utf-8");
CloseableHttpResponse response = httpClient.execute(httpGet);
//Process the response
}
示例代碼 - PHP:
// Query transaction details by transaction_id
public function queryOrderById($instance)
{
try {
$resp = $instance
->v3->global->papay->transactions->_transaction_id_
->get([
'query' => [
'sub_mchid' => '10000097',
],
'transaction_id' => '4015463511252015071056489715'
]
);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (Exception $e) {
// Exception handling
}
}
// Query transaction details by out_trade_no
public function queryOrderByNo($instance)
{
try {
$resp = $instance
->v3->global->papay->transactions->outTradeNo->_out_trade_no_
->get([
'query' => [
'sub_mchid' => '10000097',
],
'out_trade_no' => '1217752501201407033233368018'
]
);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (Exception $e) {
// Exception handling
}
}
示例代碼 - GO:
//Query transaction details by transaction_id
func queryOrderById() {
result, err := client.Get(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/4015463511252015071056489715?sub_mchid=10000097")
if err != nil {
// Process error
}
log.Printf("%s", result.Response.Body)
}
//Query transaction details by out_trade_no
func queryOrderByNo() {
result, err := client.Get(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out_trade_no/1217752501201407033233368018?sub_mchid=10000097")
if err != nil {
// Process error
}
log.Printf("%s", result.Response.Body)
}
重要參數(shù):
步驟說明:當(dāng)商戶訂單支付失敗需要生成新單號重新發(fā)起支付,要對原訂單號調(diào)用關(guān)單,避免重復(fù)支付;系統(tǒng)下單后,用戶支付超時,系統(tǒng)退出不再受理,避免用戶繼續(xù),請調(diào)用關(guān)單接口
代碼示例 - JAVA:
//Applying for close order
public void closeOrderTest() throws IOException {
String closeOrderBody = """
{
"sub_mchid": "20000100"
}
""";
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out-trade-no/1217752501201407033233368018/reverse");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(closeOrderBody ));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
示例代碼 - PHP:
// Call close order API
public function closeOrder($instance)
{
try {
$resp = $instance
->v3->global->papay->transactions->outTradeNo->_out_trade_no_->reverse
->post([
'json' => [
'sub_mchid' => '20000100'
],
'out_trade_no' => '1217752501201407033233368018'
]);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (Exception $e) {
// Exception handling
}
}
示例代碼 - GO:
//Deduction API
func closeOrder() {
body := `
{
"sub_mchid": "20000100"
}
`
result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out-trade-no/1217752501201407033233368018/reverse", body)
if err != nil {
// Process error
}
log.Printf("%s", result.Response.Body)
}
重要參數(shù):
步驟說明:當(dāng)用戶希望在商戶側(cè)發(fā)起解約時,商戶需調(diào)用解約API來完成解約。
代碼示例 - JAVA:
//Applying for Termination API
public void deductionTest() throws IOException {
String terminateBody = """
{
"sp_appid": "wxcbda96de0b165486",
"sub_mchid": "10000097",
"sub_appid": "wxcbda96de0b165484",
"termination_note": "Cause of termination"
}
""";
HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/100005698/terminate");
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(terminateBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
//Process the response
}
示例代碼 - PHP:
//Applying for Termination API
public function termination($instance)
{
try {
$resp = $instance
->v3->global->papay->contracts->_contract_id_->terminate
->post([
'json' => [
'sp_appid' => 'wxcbda96de0b165486',
'sub_mchid' => '10000097',
'sub_appid' => 'wxcbda96de0b165484',
'termination_note' => 'Cause of termination'
],
'_contract_id_' => '100005698'
]);
echo $resp->getStatusCode(), PHP_EOL;
echo $resp->getBody(), PHP_EOL;
} catch (\Exception $e) {
// Exception handling
}
}
示例代碼 - GO:
//Applying for Termination API
func terminate() {
body := `
{
"sp_appid": "wxcbda96de0b165486",
"sub_mchid": "10000097",
"sub_appid": "wxcbda96de0b165484",
"termination_note": "Cause of termination"
}
`
result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/100005698/terminate", body)
if err != nil {
// Process error
}
log.Printf("%s", result.Response.Body)
}
重要參數(shù):
Customer Service Tel
Business Development
9:00-18:00
Monday-Friday GMT+8
Technical Support
WeChat Pay Global
ICP證