为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考“APIv3接口规则”
文档展示了如何使用微信支付服务端 SDK 快速接入JSAPI支付产品,完成与微信支付对接的部分。
注意:
文档中的代码示例是用来阐述 API 基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通。
以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。
步骤说明:如 时序图2.2步骤 描述,当用户在商户小程序中选择同意使用代扣产品时,商户应请求小程序-预签约API 以获得预签约ID session_id,供下一步调起签约小程序使用。
代码示例 - 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小程序预签约 接口返回的 Body json字符串,获取其中的 session_id,返回示例: { "session_id": "201710180325670965" }
使用上一步得到的 session_id 参数拉起签约小程序
示例代码:
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;
}
}
}
}
})
步骤说明:用户完成签约后,微信支付会向发起签约时传入的success_notify_url推送签约结果通知,商户需要在接收到通知后返回对应的信息。
签约通知示例
// 签约成功回调 http body 数据示例
{
"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 解密后得到的数据示例如下:
{
"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"
}
// 解约成功回调 http body 数据示例
{
"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 解密后得到的数据示例如下:
{
"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"
}
当商户接收到微信支付回调通知时,应更新本地存储的用户签约状态,更新完成后返回如下 http body给微信支付,http状态应设置为200。
{
"code": "SUCCESS",
"message": "OK"
}
步骤说明:当商户后台、网络、服务器等出现异常,商户系统最终未接收到签约结果通知时商户可通过查询签约结果API核实签约状态。微信支付提供了两种查询签约状态的方式,一种是通过商户签约号即out_contract_code,另一种是通过微信支付返回的微信签约号contract_id。
JAVA - 示例代码:
通过商户签约号out_contract_code查询签约状态
//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查询签约状态
//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查询签约状态
//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查询签约状态
//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查询签约状态
//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查询签约状态
//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)
}
重要参数:
步骤说明:在完成签约后,商户可使用对应的协议ID发起扣款
代码示例 - 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)
}
重要参数:
步骤说明:扣款成功后,微信支付会以异步通知的方式通过扣款请求中的 notify_url 参数告知商户扣款已成功。
// 扣款结果通知 http body 数据示例
{
"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 解密后得到的数据示例如下:
{
"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
}]
}]
}
步骤说明:当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知时商户可通过查询订单接口核实订单支付状态。
代码示例 - 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)
}
重要参数:
步骤说明:当商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口
代码示例 - 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)
}
重要参数:
步骤说明:当用户希望在商户侧发起解约时,商户需调用解约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)
}
重要参数:
Customer Service Tel
Business Development
9:00-18:00
Monday-Friday GMT+8
Technical Support
WeChat Pay Global
ICP证