开发指引

更新时间:2025.03.24

1. 接口规则

为了在保证支付安全的前提下,带给商户简单、一致且易用的开发体验,我们推出了全新的微信支付APIv3接口。该版本API的具体规则请参考“APIv3接口规则

2. 开发环境搭建

为了帮助开发者调用开放接口,我们提供了JavaPHPGO语言版本的开发库,封装了签名生成、签名验证、敏感信息加/解密、媒体文件上传等基础功能

JAVA

2.1.1. 使用条件

  • WechatPay merchant account

  • Java 1.8 or later

  • Maven or Gradle;

  • 0.4.6 or later version of the Java httpClient SDK

2.1.2. 安装

Gradle:在你的 build.gradle 文件中加入如下的依赖

1implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.4.7'

Maven:在 pom.xml 文件中加入以下依赖

1<dependency>
2<groupId>com.github.wechatpay-apiv3</groupId>
3<artifactId>wechatpay-apache-httpclient</artifactId>
4<version>0.4.7</version>
5</dependency>

2.1.3. 初始化

用WechatPayHttpClientBuilder初始化创建一个httpClient,httpClient将被用于发送请求调用微信支付接口。 用CertificatesManager初始化一个verifier实例,用于验证签名。

1    private CloseableHttpClient httpClient;
2    private CertificatesManager certificatesManager;
3    private Verifier verifier;
4
5    @Before
6    //initialize verifier and build httpClient
7    public void setup() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException {
8
9        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(privateKey);
10        certificatesManager = CertificatesManager.getInstance();
11        certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
12                        new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
13                apiV3Key.getBytes(StandardCharsets.UTF_8));
14        verifier = certificatesManager.getVerifier(merchantId);
15        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
16                .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
17                .withValidator(new WechatPay2Validator(verifier));
18        httpClient = builder.build();
19    }

2.1.4. 通用功能

敏感信息加密

1    @Test
2    public void encryptedTest() throws IllegalBlockSizeException {
3        String text = "helloWorld";
4        String transformation = "RSA/ECB/PKCS1Padding";
5        String encryptedText = RsaCryptoUtil.encrypt(text, verifier.getValidCertificate(), transformation);
6        System.out.println(encryptedText);
7    }

敏感信息解密

1    @Test
2    public void decryptedTest() throws BadPaddingException {
3        String encryptedText = OBTgun4jiN13n3nmSg8v0MNDMy3mbs380yq4GrgO8vwCqXnvrWxwo3jUCNY2UY7MIOtv/SD8ke64MxcSB0hn5EzKv1LOLprI3NvvmNLS4C3SBulxpZG62RYp1+8FgwAI4M//icXvjtZWVH4KVDg==";
4        String transformation = "RSA/ECB/PKCS1Padding";
5        String decryptedText = RsaCryptoUtil.decrypt(encryptedText, PemUtil.loadPrivateKey(privateKey), transformation);
6        assert("helloWorld".equals(decryptedText));
7    }

Golang

2.2.1. 使用条件

  • WechatPay merchant account

  • GO SDK 0.2.13 or later version

2.2.2. 安装

1. 使用 Go Modules 管理你的项目

如果你的项目还不是使用 Go Modules 做依赖管理,在项目根目录下执行:

go mod init

2. 无需 clone 仓库中的代码,直接在项目目录中执行:

来添加依赖,完成 go.mod 修改与 SDK 下载

2.2.3. 初始化

初始化Client并向Client中加载商户号,私钥,API V3 key,商户证书和序列号, 用于之后发送接口请求。

1import (
2   "context"
3   "crypto/rand"
4   "crypto/rsa"
5   "crypto/x509"
6   "encoding/base64"
7   "fmt"
8   "github.com/wechatpay-apiv3/wechatpay-go/core"
9   "github.com/wechatpay-apiv3/wechatpay-go/core/option"
10   "github.com/wechatpay-apiv3/wechatpay-go/utils"
11   "log"
12   "net/http"
13)
14
15var (
16   mchID                      = ""                  // merchant id
17   mchCertificateSerialNumber = "" // merchant certificate serial number
18   mchAPIv3Key                = ""                  // merchant api v3 key
19   header                     = make(http.Header)
20   ctx                        = context.Background()
21   cert                       *x509.Certificate
22   mchPrivateKey              *rsa.PrivateKey
23   client                     *core.Client
24   err                        error
25)
26
27func setup() {
28   //Load platform certificate
29   cert, err = utils.LoadCertificateWithPath("Path/To/Platform/Cert")
30   if err != nil {
31      log.Fatal(err)
32   }
33   // Load private key
34   mchPrivateKey, err = utils.LoadPrivateKeyWithPath("Path/To/Private/Key")
35   if err != nil {
36      log.Fatal("load merchant private key error")
37   }
38   // Initialize client which is capable to update platform certificate periodically
39   opts := []core.ClientOption{
40      option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
41   }
42   client, err = core.NewClient(ctx, opts...)
43   if err != nil {
44      log.Fatalf("new wechat pay client err:%s", err)
45   }
46}   

2.2.4. 通用功能

敏感信息加密

1
2func Encryption(t *testing.T) {
3	var testRSACryptoUtilMchCertificateStr = `-----BEGIN CERTIFICATE-----
4	-----END CERTIFICATE-----`
5	testRSACryptoUtilCertificate, _ = LoadCertificate(testRSACryptoUtilMchCertificateStr)
6   const message = "hello world"
7   
8   // 使用OAEP padding方式对证书加密
9   ciphertext, _ := EncryptOAEPWithCertificate(message, testRSACryptoUtilCertificate)
10   
11   // 使用PKCS1 padding对证书加密
12   ciphertext, _ := EncryptPKCS1v15WithCertificate(message, testRSACryptoUtilCertificate)
13}
14  

敏感信息解密

1func TestDecryption(t *testing.T) {
2	var testRSACryptoUtilPrivateKeyStr = `-----BEGIN PRIVATE KEY-----
3-----END PRIVATE KEY-----`
4	testRSACryptoUtilPrivateKey, _ = LoadPrivateKey(testingKey(testRSACryptoUtilPrivateKeyStr))
5	const ciphertext = ""
6
7	// 使用PKCS1 padding进行私钥解密
8	decryptMessage, _ := DecryptPKCS1v15(ciphertext, testRSACryptoUtilPrivateKey)
9
10	// 使用OAEP padding方式私钥解密
11	decryptMessage, _ := DecryptOAEP(ciphertext, testRSACryptoUtilPrivateKey)
12}

PHP

2.3.1. 使用条件

  • Guzzle 7.0,PHP >= 7.2.5

  • Guzzle 6.5,PHP >= 7.1.2

  • 项目已支持 PHP 8。

2.3.2. 安装

推荐使用 PHP 包管理工具 Composer 安装 SDK:

composer require wechatpay/wechatpay

2.3.3. 初始化

初始化Client并向Client中加载商户号,私钥,API V3 key,商户证书和序列号, 用于之后发送接口请求。

1
2require_once('vendor/autoload.php');
3
4use WeChatPay\Builder;
5use WeChatPay\Crypto\Rsa;
6use WeChatPay\Util\PemUtil;
7
8$merchantId = '190000****';
9$merchantPrivateKeyFilePath = 'file:///path/to/merchant/apiclient_key.pem';
10$merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);
11$merchantCertificateSerial = '3775B6A45ACD588826D15E583A95F5DD********';
12$platformCertificateFilePath = 'file:///path/to/wechatpay/cert.pem';
13$platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);
14$platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);
15
16// init a API V3 instance
17$instance = Builder::factory([
18    'mchid'      => $merchantId,
19    'serial'     => $merchantCertificateSerial,
20    'privateKey' => $merchantPrivateKeyInstance,
21    'certs'      => [
22        $platformCertificateSerial => $platformPublicKeyInstance,
23    ],
24]); 
25        

2.3.4. 通用功能

敏感信息加密

1    $encryptor = static function(string $msg) use ($platformPublicKeyInstance): string {
2        return Rsa::encrypt($msg, $platformPublicKeyInstance, OPENSSL_PKCS1_PADDING);
3    };
4	$encryptedMsg =  $encryptor('HelloWorld');  

敏感信息解密

1    $decryptor = static function(string $msg) use ($merchantPrivateKeyInstance): string {
2        return Rsa::decrypt($msg, $merchantPrivateKeyInstance, OPENSSL_PKCS1_PADDING);
3    };
4	$decryptedMsg =  $decryptor('ciphertext');

3、快速接入

3.1、业务时序图

3.2、API调用示例

文档展示了如何使用微信支付服务端 SDK 快速接入JSAPI支付产品,完成与微信支付对接的部分。

注意:
文档中的代码示例是用来阐述 API 基本使用方法,代码中的示例参数需替换成商户自己账号及请求参数才能跑通。
以下接入步骤仅提供参考,请商户结合自身业务需求进行评估、修改。

3.2.1 小程序预签约

步骤说明:如 时序图2.2步骤 描述,当用户在商户小程序中选择同意使用代扣产品时,商户应请求小程序-预签约API 以获得预签约ID session_id,供下一步调起签约小程序使用。

代码示例 - JAVA:

1
2//Obtaining Signing Session ID API for mini-program signing
3    public void miniProgramSignTest() throws IOException {
4		String miniprogramSignBody = """{
5"expired_time": "2021-11-20T13:29:35+08:00",
6"openid": "of8YZ6A_ySrPYzjX7joXo_0000",
7"out_contract_code": "20220614out_contract_code",
8"plan_id": 10001,
9"sp_appid": "wx7bc9000000000000",
10"sub_mchid": "90325355",
11"success_notify_url": "https://yoursite.com",
12"user_display_name": "mike"
13}""";
14        HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/miniprogram-pre-entrust-sign");
15        httpPost.addHeader("Accept", "application/json");
16        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
17        httpPost.setEntity(new StringEntity(miniprogramSignBody));
18        CloseableHttpResponse response = httpClient.execute(httpPost);
19        //Process the response
20    }

示例代码 - PHP:

1
2 //Mini Program Signing API
3  public function miniProgramSigning($instance)
4  {
5    try {
6      $resp = $instance
7        ->chain('v3/global/papay/contracts/miniprogram-pre-entrust-sign')
8        ->post([
9          'json' => [
10            "sp_appid" => "wx7bc9000000000000",
11			"sub_mchid" => "90325355",
12            "openid" => "of8YZ6A_ySrPYzjX7joXo_0000",
13            "out_contract_code" => "20220614out_contract_code",
14            "plan_id" => 10001,
15            "success_notify_url" => "https://www.yoursite.com",
16            "user_display_name" => "mike",
17			"expired_time" => "2021-11-20T13:29:35+08:00",
18          ]
19        ]);
20
21      echo $resp->getStatusCode(), PHP_EOL;
22      echo $resp->getBody(), PHP_EOL;
23    } catch (\Exception $e) {
24      // Exception handling
25    }
26  }

示例代码 - GO:

1
2//Mini program signing API
3func miniProgramSigning() {
4	signBody := `{
5"expired_time": "2021-11-20T13:29:35+08:00",
6"openid": "of8YZ6A_ySrPYzjX7joXo_0000",
7"out_contract_code": "20220614out_contract_code",
8"plan_id": 10001,
9"sp_appid": "wx7bc9000000000000",
10"sub_mchid": "90325355",
11"success_notify_url": "https://yoursite.com",
12"user_display_name": "mike"
13}`
14	
15	result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/miniprogram-pre-entrust-sign", signBody)
16	if err != nil {
17		// Process error
18	}
19	log.Printf("%s", result.Response.Body)

3.2.2 小程序调起签约

步骤说明:
解析 3.1小程序预签约 接口返回的 Body json字符串,获取其中的 session_id,返回示例: { "session_id": "201710180325670965" }
使用上一步得到的 session_id 参数拉起签约小程序

示例代码:

1
2 var session_id = "201710180325670965"; // obtained from miniprogram-pre-entrust-sign
3// start signing process
4wx.navigateToMiniProgram({
5	appId: wxbd687630cd02ce1d,
6	path: 'pages/Oversea/walletSelect?sessionId=' + session_id,
7	extraData: {},
8	success(res) {
9		// Jumped to the signing mini program successfully
10	},
11	fail(res) {
12		// Failed to jump to the signing mini program 
13	}
14})
15
16
17// After signing process, user will return back to merchant's miniprogram
18App({
19	onShow(res)  {
20		if  (res.scene  ===  1038)  {  //Scenario value 1038: return from the opened min program
21			const { appId, extraData } = res.referrerInfo
22			if  (appId  ==  'wxbd687630cd02ce1d')  {  // appId is wxbd687630cd02ce1d: jump back from the signing min program
23				if  (typeof  extraData  ==  'undefined') {
24					// TODO
25					// The client min program is not sure of the signing result and needs to request the merchant-side background to confirm the signing result
26					return;
27				}
28				if (extraData.return_code  ==  'SUCCESS') {
29					// TODO
30					// The client min program signs successfully and needs to request the merchant-side background to confirm the signing result
31					var  contract_id  =  extraData.contract_id
32					return;
33				} 
34				else  {
35					// TODO
36					// Signing failed
37					return;
38				}
39			}
40		}
41	}
42})

3.2.3 签约结果通知

步骤说明:用户完成签约后,微信支付会向发起签约时传入的success_notify_url推送签约结果通知,商户需要在接收到通知后返回对应的信息。

签约通知示例

1
2 // 签约成功回调 http body 数据示例
3{
4    "id":"EV-2018022511223320873",
5    "create_time":"2022-06-14T14:01:35+08:00",
6    "resource_type":"encrypt-resource",
7    "event_type":"PAPAY.SIGN",
8	"summary": "签约成功",
9    "resource" : {
10        "algorithm":"AEAD_AES_256_GCM",
11        "ciphertext": "...",
12        "nonce": "dAvnRJWFOfdL",
13        "associated_data": "papay"
14    }
15}
16// 对 resource.ciphertext 解密后得到的数据示例如下:
17{
18   "sp_mchid":"10000091",
19   "sub_mchid":"10000097",
20   "out_contract_code":"100001256",
21   "plan_id":123,
22   "contract_id":"Wx15463511252015071056489715",
23   "sp_appid":"wxcbda96de0b165486",
24   "openid":"ouFhd5X9s9WteC3eWRjXV3lea123",
25   "operate_time":"2015-09-01T10:00:00+08:00"
26}
27
28// 解约成功回调 http body 数据示例
29{
30   "id":"2646bee0-aef8-5804-9752-ef1a56170fdf",
31   "create_time":"2022-06-14T16:31:53+08:00",
32   "resource_type":"encrypt-resource",
33   "event_type":"PAPAY.TERMINATE",
34   "summary":"解约成功",
35   "resource":{
36      "original_type":"papay",
37      "algorithm":"AEAD_AES_256_GCM",
38      "ciphertext": "...",
39      "associated_data":"papay",
40      "nonce":"SExJ2Xxx7sr1"
41   }
42}
43// 对 resource.ciphertext 解密后得到的数据示例如下:
44{
45	"sp_mchid": "10000091",
46	"sub_mchid": "10000097",
47	"out_contract_code": "100001256",
48	"plan_id": 123,
49	"contract_id": "Wx15463511252015071056489715",
50	"sp_appid": "wxcbda96de0b165486",
51	"openid": "ouFhd5X9s9WteC3eWRjXV3lea123",
52	"contract_termination_mode": "USER",
53	"operate_time": "2015-10-01T10:00:00+08:00"
54}

当商户接收到微信支付回调通知时,应更新本地存储的用户签约状态,更新完成后返回如下 http body给微信支付,http状态应设置为200。

1{
2	"code": "SUCCESS",
3	"message": "OK"
4}

注意:

  • 支付结果通知是以POST 方法访问商户设置的通知url,通知的数据以JSON 格式通过请求主体(BODY)传输。通知的数据包括了加密的支付结果详情。

  • 加密不能保证通知请求来自微信。微信会对发送给商户的通知进行签名,并将签名值放在通知的HTTP头Wechatpay-Signature。商户应当验证签名,以确认请求来自微信,而不是其他的第三方。签名验证的算法请参考《微信支付API V3签名验证》

  • 支付通知http应答码为200或204才会当作正常接收,当回调处理异常时,应答的HTTP状态码应为500,或者4xx。

  • 商户成功接收到回调通知后应返回成功的http应答码为200或204。

  • 同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是,当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

  • 对后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。(通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m)

3.2.4 查询签约结果

步骤说明:当商户后台、网络、服务器等出现异常,商户系统最终未接收到签约结果通知时商户可通过查询签约结果API核实签约状态。微信支付提供了两种查询签约状态的方式,一种是通过商户签约号即out_contract_code,另一种是通过微信支付返回的微信签约号contract_id。

JAVA - 示例代码:
通过商户签约号out_contract_code查询签约状态

1
2//Querying Signing Status (By out_contract_code)
3    public void querySignStatusByContractCodeTest() throws IOException {
4        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");
5        httpGet.addHeader("Accept", "application/json");
6        httpGet.addHeader("Content-type", "application/json; charset=utf-8");
7        CloseableHttpResponse response = httpClient.execute(httpGet);
8        //Process the response
9    }

通过微信签约号contract_id查询签约状态

1
2//Querying Signing Status (By contract_id) API
3    public void querySignStatusTest() throws IOException {
4        HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/202203242337333903387184301572?sub_mchid=10000097&sp_appid=wxcbda96de0b165486&sub_appid=wxcbda96de0b165484");
5        httpGet.addHeader("Accept", "application/json");
6        httpGet.addHeader("Content-type", "application/json; charset=utf-8");
7        CloseableHttpResponse response = httpClient.execute(httpGet);
8        //Process the response
9    }

PHP - 示例代码:
通过商户签约号out_contract_code查询签约状态

1
2  //Querying Signing Status (By out_contract_code) API
3  public function querySignStatusByContractCode($instance)
4  {
5    try {
6      $resp = $instance
7        ->v3->global->papay->contracts->outContractCode->_out_contract_code_
8        ->get([
9          'query' => [
10            'sp_appid' => 'wxcbda96de0000006',
11            'sub_appid' => 'wxcbda96de0000004',
12            'sub_mchid' => '110000000'
13          ],
14          '_out_contract_code_' => '100005698'
15        ]);
16
17      echo $resp->getStatusCode(), PHP_EOL;
18      echo $resp->getBody(), PHP_EOL;
19    } catch (\Exception $e) {
20      // Exception handling
21    }
22  }

通过微信签约号contract_id查询签约状态

1				
2  //Querying Signing Status (By contract_id) API
3  public function querySignStatus($instance)
4  {
5    try {
6      $resp = $instance
7        ->v3->global->papay->contracts->_contract_id_
8        ->get([
9          'query' => [
10            'sp_appid' => 'wxcbda96de0000006',
11            'sub_appid' => 'wxcbda96de0000004',
12            'sub_mchid' => '110000000'
13          ],
14          'contract_id' => '202203242337333903387184301572'
15        ]);
16
17      echo $resp->getStatusCode(), PHP_EOL;
18      echo $resp->getBody(), PHP_EOL;
19    } catch (\Exception $e) {
20      // Exception handling
21    }
22  }

GO - 示例代码:
通过商户签约号out_contract_code查询签约状态

1				
2//Querying signing status by out_contract_code API
3func querySigningStatusByContractCode() {
4	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")
5	if err != nil {
6		// Process error
7	}
8	log.Printf("status=%d resp=%s", result.Response.StatusCode, result.Response.Body)
9}

通过微信签约号contract_id查询签约状态

1				
2//Querying signing status API
3func querySigningStatus() {
4	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")
5	if err != nil {
6		// Process error
7	}
8	log.Printf("status=%d resp=%s", result.Response.StatusCode, result.Response.Body)
9}

重要参数:

  • contract_id - 微信测返回的签约协议号,唯一标识一条签约协议,示例值:202203242337333903387184301572

  • out_contract_code - 商户侧生成的签约协议号,示例值:100001261

  • sp_appid - 服务商公众号的appid

  • sub_appid - 发起签约的子商户小程序appid

3.2.5 扣款

步骤说明:在完成签约后,商户可使用对应的协议ID发起扣款
代码示例 - JAVA:

1
2//Applying for Termination API
3public void deductionTest() throws IOException {
4		String deductionBody = """
5{
6	"sp_appid": "wxcbda96de0b165486",
7	"sub_mchid": "10000097",
8	"sub_appid": "wxcbda96de0b165484",
9	"description": "PAPAuto-debit支付测试",
10	"attach": "支付测试",
11	"notify_url": "https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php",
12	"out_trade_no": "1217752501201407033233368018",
13	"goods_tag": "WXG",
14	"merchant_category_code": "1011",
15	"contract_id": "Wx15463511252015071056489715",
16	"amount": {
17		"total": 10000,
18		"currency": "HKD"
19	},
20	"scene_info": {
21		"device_ip": "59.37.125.32",
22		"device_id": "013467007045764"
23	}
24}
25""";
26        HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions");
27        httpPost.addHeader("Accept", "application/json");
28        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
29        httpPost.setEntity(new StringEntity(deductionBody));
30        CloseableHttpResponse response = httpClient.execute(httpPost);
31        //Process the response
32}

示例代码 - PHP:

1
2  //Deduction API
3  public function deduction($instance)
4  {
5    try {
6      $resp = $instance
7        ->v3->global->papay->transactions
8        ->post([
9          'json' => [
10            "sp_appid" => "wxcbda96de0b165486",
11            "sub_mchid" => "10000097",
12            "sub_appid" => "wxcbda96de0b165484",
13            "description" => "PAPAuto-debit支付测试",
14            "attach" => "支付测试",
15            "notify_url" => "https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php",
16            "out_trade_no" => "1217752501201407033233368018",
17            "goods_tag" => "WXG",
18            "merchant_category_code" => "1011",
19            "contract_id" => "Wx15463511252015071056489715",
20            "amount" => array(
21              "total" => 10000,
22              "currency" => "HKD"
23            ),
24            "scene_info" => array(
25              "device_ip" => "59.37.125.32",
26              "device_id" => "013467007045764"
27            )
28          ]
29        ]);
30      echo $resp->getStatusCode(), PHP_EOL;
31      echo $resp->getBody(), PHP_EOL;
32    } catch (\Exception $e) {
33      // Exception handling
34    }
35  }

示例代码 - GO:

1
2//Deduction API
3func deduction() {
4	body := `
5{
6	"sp_appid": "wxcbda96de0b165486",
7	"sub_mchid": "10000097",
8	"sub_appid": "wxcbda96de0b165484",
9	"description": "PAPAuto-debit支付测试",
10	"attach": "支付测试",
11	"notify_url": "https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php",
12	"out_trade_no": "1217752501201407033233368018",
13	"goods_tag": "WXG",
14	"merchant_category_code": "1011",
15	"contract_id": "Wx15463511252015071056489715",
16	"amount": {
17		"total": 10000,
18		"currency": "HKD"
19	},
20	"scene_info": {
21		"device_ip": "59.37.125.32",
22		"device_id": "013467007045764"
23	}
24}
25`
26	result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions", body)
27	if err != nil {
28		// Process error
29	}
30	log.Printf("%s", result.Response.Body)
31}

重要参数:

  • contract_id:用户签约协议号,微信支付根据该字段校验用户和商户的签约关系,如果未签约或者用户已解约则返回 NO_AUTH - 签约协议不存在

3.2.6 扣款结果通知

步骤说明:扣款成功后,微信支付会以异步通知的方式通过扣款请求中的 notify_url 参数告知商户扣款已成功。

1
2// 扣款结果通知 http body 数据示例
3{
4    "id":"EV-2018022511223320873",
5    "create_time":"20180225112233",
6    "resource_type":"encrypt-resource",
7    "event_type":"TRANSACTION.SUCCESS",
8    "resource" : {
9        "algorithm":"AEAD_AES_256_GCM",
10        "ciphertext": "...",
11        "nonce": "...",
12        "associated_data": ""
13    }
14}
15// 对 resource.ciphertext 解密后得到的数据示例如下:
16{
17	"sp_mchid": "10000100",
18	"sp_appid": "wx2421b1c4370ec43b",
19	"sub_mchid": "20000100",
20	"out_trade_no": "20150806125346",
21	"transaction_id": "1008450740201411110005820873",
22	"attach": "支付测试",
23	"trade_type": "AUTH",
24	"bank_type": "CCB_DEBIT",
25	"success_time": "2018-06-08T10:34:56+08:00",
26	"trade_state": "SUCCESS",
27	"trade_state_desc": "支付成功",
28	"merchant_category_code": "1011",
29	"contract_id": "Wx15463511252015071056489715",
30	"payer": {
31		"sp_openid": "oUpF8uN95-Ptaags6E_roPHg7AG0"
32	},
33	"amount": {
34		"total": 528800,
35		"currency": "HKD",
36		"payer_total": 518799,
37		"payer_currency": "CNY",
38		"exchange_rate": {
39			"type": "SETTLEMENT_RATE",
40			"rate": 8000000
41		}
42	},
43	"promotion_detail": [{
44		"promotion_id": "109519",
45		"name": "单品惠-6",
46		"scope": "SINGLE",
47		"type": "DISCOUNT",
48		"amount": 1,
49		"currency": "HKD",
50		"activity_id": "931386",
51		"wechatpay_contribute_amount": 1,
52		"merchant_contribute_amount": 0,
53		"other_contribute_amount": 0,
54		"goods_detail": [{
55			"goods_id": "iphone6s_16G",
56			"goods_remark": "商品备注",
57			"quantity": 1,
58			"price": 528800
59		}]
60	}]
61}

3.2.7 订单查询API

步骤说明:当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知时商户可通过查询订单接口核实订单支付状态。

代码示例 - JAVA:

1
2	//Query transaction details by transaction_id   
3	public void queryOrderByIdTest() throws IOException {
4        HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/4015463511252015071056489715?sub_mchid=10000097");
5        httpGet.addHeader("Accept", "application/json");
6        httpGet.addHeader("Content-type", "application/json; charset=utf-8");
7        CloseableHttpResponse response = httpClient.execute(httpGet);
8        //Process the response
9    }
10
11	//Query transaction details by out_trade_no
12	public void queryOrderByNoTest() throws IOException {
13        HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out_trade_no/1217752501201407033233368018?sub_mchid=10000097");
14        httpGet.addHeader("Accept", "application/json");
15        httpGet.addHeader("Content-type", "application/json; charset=utf-8");
16        CloseableHttpResponse response = httpClient.execute(httpGet);
17        //Process the response
18    }

示例代码 - PHP:

1
2// Query transaction details by transaction_id 
3public function queryOrderById($instance)
4{
5    try {
6        $resp = $instance
7            ->v3->global->papay->transactions->_transaction_id_
8            ->get([
9                    'query' => [
10                		'sub_mchid'    => '10000097',
11                    ],
12                    'transaction_id' => '4015463511252015071056489715'
13                ]
14            );
15
16        echo $resp->getStatusCode(), PHP_EOL;
17        echo $resp->getBody(), PHP_EOL;
18    } catch (Exception $e) {
19        // Exception handling
20	}
21}
22
23// Query transaction details by out_trade_no
24public function queryOrderByNo($instance)
25{
26    try {
27        $resp = $instance
28            ->v3->global->papay->transactions->outTradeNo->_out_trade_no_
29            ->get([
30                    'query' => [
31                		'sub_mchid'    => '10000097',
32                    ],
33                    'out_trade_no' => '1217752501201407033233368018'
34                ]
35            );
36
37        echo $resp->getStatusCode(), PHP_EOL;
38        echo $resp->getBody(), PHP_EOL;
39    } catch (Exception $e) {
40        // Exception handling
41	}
42}

示例代码 - GO:

1
2//Query transaction details by transaction_id 
3func queryOrderById() {
4	result, err := client.Get(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/4015463511252015071056489715?sub_mchid=10000097")
5	if err != nil {
6		// Process error
7	}
8	log.Printf("%s", result.Response.Body)
9}
10
11
12//Query transaction details by out_trade_no
13func queryOrderByNo() {
14	result, err := client.Get(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out_trade_no/1217752501201407033233368018?sub_mchid=10000097")
15	if err != nil {
16		// Process error
17	}
18	log.Printf("%s", result.Response.Body)
19}

重要参数:

  • out_trade_no:商户侧扣费订单号

  • transaction_id:微信订单号

3.2.8 【服务端】关闭订单

步骤说明:当商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口

代码示例 - JAVA:

1
2//Applying for close order
3public void closeOrderTest() throws IOException {
4		String closeOrderBody = """
5{
6  "sub_mchid": "20000100"
7}
8""";
9        HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out-trade-no/1217752501201407033233368018/reverse");
10        httpPost.addHeader("Accept", "application/json");
11        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
12        httpPost.setEntity(new StringEntity(closeOrderBody ));
13        CloseableHttpResponse response = httpClient.execute(httpPost);
14        //Process the response
15}

示例代码 - PHP:

1
2  // Call close order API
3  public function closeOrder($instance)
4  {
5    try {
6      $resp = $instance
7		->v3->global->papay->transactions->outTradeNo->_out_trade_no_->reverse
8        ->post([
9          'json' => [
10            'sub_mchid'    => '20000100'
11          ],
12          'out_trade_no' => '1217752501201407033233368018'
13        ]);
14      echo $resp->getStatusCode(), PHP_EOL;
15      echo $resp->getBody(), PHP_EOL;
16    } catch (Exception $e) {
17      // Exception handling
18    }
19  }

示例代码 - GO:

1
2//Deduction API
3func closeOrder() {
4	body := `
5{
6  "sub_mchid": "20000100"
7}
8`
9	result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/transactions/out-trade-no/1217752501201407033233368018/reverse", body)
10	if err != nil {
11		// Process error
12	}
13	log.Printf("%s", result.Response.Body)
14}

重要参数:

  • out_trade_no:商户侧扣费订单号

3.2.9 【服务端】解约

步骤说明:当用户希望在商户侧发起解约时,商户需调用解约API来完成解约。

代码示例 - JAVA:

1
2//Applying for Termination API    
3public void deductionTest() throws IOException {
4		String terminateBody = """
5{
6"sp_appid": "wxcbda96de0b165486",
7"sub_mchid": "10000097",
8"sub_appid": "wxcbda96de0b165484", 
9"termination_note": "Cause of termination" 
10}
11""";
12        HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/100005698/terminate");
13        httpPost.addHeader("Accept", "application/json");
14        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
15        httpPost.setEntity(new StringEntity(terminateBody));
16        CloseableHttpResponse response = httpClient.execute(httpPost);
17        //Process the response
18    }

示例代码 - PHP:

1
2  //Applying for Termination API
3  public function termination($instance)
4  {
5    try {
6      $resp = $instance
7        ->v3->global->papay->contracts->_contract_id_->terminate
8        ->post([
9          'json' => [
10            'sp_appid' => 'wxcbda96de0b165486',
11			'sub_mchid' => '10000097',
12			'sub_appid' => 'wxcbda96de0b165484',
13			'termination_note' => 'Cause of termination'
14          ],
15          '_contract_id_' => '100005698'
16        ]);
17      echo $resp->getStatusCode(), PHP_EOL;
18      echo $resp->getBody(), PHP_EOL;
19    } catch (\Exception $e) {
20      // Exception handling
21    }
22  }

示例代码 - GO:

1
2//Applying for Termination API
3func terminate() {
4	body := `
5{
6"sp_appid": "wxcbda96de0b165486",
7"sub_mchid": "10000097",
8"sub_appid": "wxcbda96de0b165484", 
9"termination_note": "Cause of termination" 
10}
11`
12	result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/papay/contracts/100005698/terminate", body)
13	if err != nil {
14		// Process error
15	}
16	log.Printf("%s", result.Response.Body)
17}

重要参数:

  • contract_id:微信侧代扣协议ID

 

About  WeChat  Pay

Powered By Tencent & Tenpay Copyright©

2005-2025 Tenpay All Rights Reserved.

Contact Us
Wechat Pay Global

WeChat Pay Global

Contact Us

Customer Service Tel

+86 571 95017

9:00-18:00 Monday-Friday GMT+8

Business Development

wxpayglobal@tencent.com

Developer Support

wepayTS@tencent.com

Wechat Pay Global

About Tenpay
Powered By Tencent & Tenpay Copyright© 2005-2025 Tenpay All Rights Reserved.