1. API Rules
In order to provide a simple, consistent and easy-to-use development experience to merchants while ensuring payment security, we have launched the latest WeChat Pay APIv3 interface. Please refer to “APIv3 Interface Rules” for the specific rules of this API version.
2. Development Environment Setup
To help developers call the open interface, the development libraries of Java、PHP、GO are provided, encapsulating the basic functions such as signature generation, signature verification, encryption/decryption of sensitive information, and media document upload
JAVA
2.1.1. Conditions of Use
2.1.2. Installation
Gradle:Add the following dependencies to your build.gradle document

1implementation 'com.github.wechatpay-apiv3:wechatpay-apache-httpclient:0.4.7'
2
Maven:Add the following dependencies to the pom.xml document

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. Initialization
Initialize WechatPayHttpClientBuilder to create an httpClient, which will be used to send requests to call the WeChatPay interface. Initialize a verifier instance with CertificatesManager to verify the signature.

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

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

1
2 @Test
3 public void decryptedTest() throws BadPaddingException {
4 String encryptedText = OBTgun4jiN13n3nmSg8v0MNDMy3mbs380yq4GrgO8vwCqXnvrWxwo3jUCNY2UY7MIOtv/SD8ke64MxcSB0hn5EzKv1LOLprI3NvvmNLS4C3SBulxpZG62RYp1+8FgwAI4M
5 String transformation = "RSA/ECB/PKCS1Padding";
6 String decryptedText = RsaCryptoUtil.decrypt(encryptedText, PemUtil.loadPrivateKey(privateKey), transformation);
7 assert("helloWorld".equals(decryptedText));
8 }
Golang
2.2.1. Conditions of Use
2.2.2. Installation
1、Manage your projects with Go Modules |
If Go Modules are not used for the dependency management of your projects, run in the project root directory:
2、Without cloning the code in the repository, run directly in the project directory: |
to add a dependency, modify modand download SDK
2.2.3. Initialization
Initialize Client and load the merchant account, private key, API V3 key, merchant certificate and serial number to Client for sending an interface request later.

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

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
9 ciphertext, _ := EncryptOAEPWithCertificate(message, testRSACryptoUtilCertificate)
10
11
12 ciphertext, _ := EncryptPKCS1v15WithCertificate(message, testRSACryptoUtilCertificate)
13}
14
Decrypting Sensitive Information

1
2func TestDecryption(t *testing.T) {
3 var testRSACryptoUtilPrivateKeyStr = `-----BEGIN PRIVATE KEY-----
4-----END PRIVATE KEY-----`
5 testRSACryptoUtilPrivateKey, _ = LoadPrivateKey(testingKey(testRSACryptoUtilPrivateKeyStr))
6 const ciphertext = ""
7
8
9 decryptMessage, _ := DecryptPKCS1v15(ciphertext, testRSACryptoUtilPrivateKey)
10
11
12 decryptMessage, _ := DecryptOAEP(ciphertext, testRSACryptoUtilPrivateKey)
13}
PHP
2.3.1. Conditions of Use
2.3.2. Installation
It is recommended to use the PHP package management tool Composer to install SDK:
composer require wechatpay/wechatpay
2.3.3. Initialization
Initialize Client and load the merchant account, private key, API V3 key, merchant certificate and serial number to Client in order to send an interface request later.

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
17$instance = Builder::factory([
18 'mchid' => $merchantId,
19 'serial' => $merchantCertificateSerial,
20 'privateKey' => $merchantPrivateKeyInstance,
21 'certs' => [
22 $platformCertificateSerial => $platformPublicKeyInstance,
23 ],
24]);
25
2.3.4. General Functions
Encrypting Sensitive Information

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

1
2 $decryptor = static function(string $msg) use ($merchantPrivateKeyInstance): string {
3 return Rsa::decrypt($msg, $merchantPrivateKeyInstance, OPENSSL_PKCS1_PADDING);
4 };
5 $decryptedMsg = $decryptor('ciphertext');
3. Fast Access
3.1. Business Sequence Chart
3.2. Example of API access
The document shows how to use the WeChat Pay server SDK to In-App Payment by scanning code and interface with WeChat Pay.
3.2.1 User identity verification API
Procedure: This interface allows merchants to request WeChat Pay to verify the consistency between the user’s real name for user payment and the identity information involved in the parameter, and merchants can use the correct information for customs clearance based on the verification results.
Sensitive information fields: certificate_id and certificate_name are the sensitive information of users. Such information and the users' privacy should be encrypted and transmitted according to WeChat Pay APIv3 to avoid being intercepted by intermediaries.

1
2
3 public void idVerification() throws IOException {
4 String verifyIdInfoBody = """{
5 "appid": "wxd678efh567hg6787",
6 "mchid": "1230000109",
7 "out_trade_no": "20150806125346",
8 "transaction_id": "1000320306201511078440737890",
9 "sub_order_no": "20150806125346",
10 "customs": "SHANGHAI_ZS",
11 "merchant_customs_no": "123456",
12 "certificate_type": "IDCARD",
13 "certificate_id": "HHp24MagiQ6i7c5yIow5cJP5x2cGsAA8hi5yIow5cJP5x",
14 "certificate_name": "HHp24MagiQ6i7c5yIow/9ZTk5Zt5cJP5x2cGsAA8hif07fRdb2"
15}""";
16 HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/customs/verify-certificate");
17 httpPost.addHeader("Accept", "application/json");
18 httpPost.addHeader("Content-type", "application/json; charset=utf-8");
19 httpPost.addHeader("Wechatpay-Serial", "0798ABFDCBXXXXXXXXXXXXXXXXXXXXXXX054A761");
20 httpPost.setEntity(new StringEntity(verifyIdInfoBody));
21 CloseableHttpResponse response = httpClient.execute(httpPost);
22
23 }
24
Code example-Go

1
2
3func idVerification() {
4 idVerificationBody := `{
5 "appid": "wxd678efh567hg6787",
6 "mchid": "1230000109",
7 "out_trade_no": "20150806125346",
8 "transaction_id": "1000320306201511078440737890",
9 "sub_order_no": "20150806125346",
10 "customs": "SHANGHAI_ZS",
11 "merchant_customs_no": "123456",
12 "certificate_type": "IDCARD",
13 "certificate_id": "HHp24MagiQ6i7c5yIow5cJP5x2cGsAA8hi5yIow5cJP5x",
14 "certificate_name": "HHp24MagiQ6i7c5yIow/9ZTk5Zt5cJP5x2cGsAA8hif07fRdb2"
15}`
16 header.Add("Wechatpay-Serial", "")
17 header.Add("Idempotency-Key", "20220518-001")
18 result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/customs/verify-certificate", header, nil, idVerificationBody, "application/json")
19 if err != nil {
20
21 }
22 log.Printf("%s", result.Response.Body)
23}
Code example-PHP

1
2
3public function idInfoVerification($instance, $platformPublicKeyInstance, $platformCertificateSerial){
4 $encryptor = static function(string $msg) use ($platformPublicKeyInstance): string {
5 return Rsa::encrypt($msg, $platformPublicKeyInstance, OPENSSL_PKCS1_PADDING);
6 };
7 try {
8 $resp = $instance
9 ->chain('/v3/global/customs/verify-certificate')
10 ->post([
11 'json' => [
12 'appid' => 'wxdace12300000000',
13 'mchid' => '1900000000',
14 'out_trade_no' => 'YX001',
15 'transaction_id' => '420000000001500000089',
16 'customs' => 'SHANGHAI_ZS',
17 'merchant_customs_no' => '123456',
18 'sub_order_no' => '20150806125346',
19 'certificate_type' => 'IDCARD',
20 'certificate_id' => 'HHp24MagiQ6i7c5yIow5cJP5x2cGsAA8hi5yIow5cJP5x',
21 'certificate_name' => 'HHp24MagiQ6i7c5yIow/9ZTk5Zt5cJP5x2cGsAA8hif07fRdb2'
22 ],
23 'headers' => [
24 'Wechatpay-Serial' => $platformCertificateSerial
25 ]
26 ]);
27 echo $resp->getStatusCode(), PHP_EOL;
28 echo $resp->getBody(), PHP_EOL;
29 } catch (\Exception $e) {
30
31 }
32}
Please refer to the API document for ordering by scanning code for other critical parameters.
Procedure: Merchants request WeChat Pay to push the customs declaration information of payment orders to the Customs through this interface. WeChat Pay will asynchronously push the payment order declaration information to the Customs after receiving the additional information of customs declaration
Code example-JAVA

1
2
3 public void customsDeclaration() throws IOException {
4 String customsDeclarationBody= """{
5 "appid": "wxd678efh567hg6787",
6 "mchid": "1230000109",
7 "out_trade_no": "20150806125346",
8 "transaction_id": "1000320306201511078440737890",
9 "customs": "SHANGHAI_ZS",
10 "merchant_customs_no": "123456",
11 "duty": 888,
12 "sub_order_no": "20150806125346",
13 "fee_type": "CNY",
14 "order_fee": 888,
15 "transport_fee": 888,
16 "product_fee": 888
17}""";
18 HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/customs/orders");
19 httpPost.addHeader("Accept", "application/json");
20 httpPost.addHeader("Content-type", "application/json; charset=utf-8");
21 httpPost.setEntity(new StringEntity(customsDeclarationBody));
22 CloseableHttpResponse response = httpClient.execute(httpPost);
23
24 }
25
26
Code example-Go

1
2
3func customsDeclaration() {
4 customsDeclarationBody := `
5{
6 "appid": "wxd678efh567hg6787",
7 "mchid": "1230000109",
8 "out_trade_no": "20150806125346",
9 "transaction_id": "1000320306201511078440737890",
10 "customs": "SHANGHAI_ZS",
11 "merchant_customs_no": "123456",
12 "duty": 888,
13 "sub_order_no": "20150806125346",
14 "fee_type": "CNY",
15 "order_fee": 888,
16 "transport_fee": 888,
17 "product_fee": 888
18}
19`
20 result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/customs/orders", customsDeclarationBody)
21 if err != nil {
22
23 }
24 log.Printf("%s", result.Response.Body)
25}
Code example-PHP

1
2
3public function customsDeclaration($instance){
4 try {
5 $resp = $instance
6 ->chain('/v3/global/customs/orders')
7 ->post([
8 'json' => [
9 'appid' => 'wxd678efh567hg6787',
10 'mchid' => '1230000109',
11 'out_trade_no' => '20150806125346',
12 'transaction_id' => '1000320306201511078440737890',
13 'customs' => 'SHANGHAI_ZS',
14 'merchant_customs_no' => '123456',
15 'duty' => 888,
16 'sub_order_no' => '20150806125346',
17 'fee_type' => 'CNY',
18 'order_fee' => 888,
19 'transport_fee' => 888,
20 'product_fee' => 888
21 ]
22 ]);
23
24 echo $resp->getStatusCode(), PHP_EOL;
25 echo $resp->getBody(), PHP_EOL;
26 } catch (\Exception $e) {
27
28 }
29}
Please refer to the API document for ordering by scanning code for other critical parameters.
Procedure: This interface may be called to modify the customs declaration information if the merchant has incorrectly uploaded some fields. This interface allows to modify the following 5 fields only: merchant_customs_no, duty, order_fee, transport_fee, and product_fee
Code example-JAVA

1
2
3 public void modifyCustomsDeclarartionTest() throws IOException {
4 String modifyCustomsDeclarationBody = "{
5 "appid": "wxd678efh567hg6787",
6 "mchid": "1230000109",
7 "out_trade_no": "20150806125346",
8 "transaction_id": "1000320306201511078440737890",
9 "sub_order_no": "20150806125346",
10 "customs": "SHANGHAI_ZS",
11 "merchant_customs_no": "123456",
12 "duty": 888,
13 "order_fee": 888,
14 "transport_fee": 888,
15 "product_fee": 888
16}";
17 HttpPatch httpPatch = new HttpPatch("https://apihk.mch.weixin.qq.com/v3/global/customs/orders");
18 httpPatch.addHeader("Accept", "application/json");
19 httpPatch.addHeader("Content-type", "application/json; charset=utf-8");
20 httpPatch.setEntity(new StringEntity(modifyCustomsDeclarationBody));
21 CloseableHttpResponse response = httpClient.execute(httpPatch);
22
23 }
24
Code example-Go

1
2
3func modifyCustomsDeclarartion() {
4 modifyCustomsDeclarartionBody := `
5{
6 "appid": "wxd678efh567hg6787",
7 "mchid": "1230000109",
8 "out_trade_no": "20150806125346",
9 "transaction_id": "1000320306201511078440737890",
10 "sub_order_no": "20150806125346",
11 "customs": "SHANGHAI_ZS",
12 "merchant_customs_no": "123456",
13 "duty": 888,
14 "order_fee": 888,
15 "transport_fee": 888,
16 "product_fee": 888
17}
18`
19 result, err := client.Patch(ctx, "https://apihk.mch.weixin.qq.com/v3/global/customs/orders", modifyCustomsDeclarartionBody)
20 if err != nil {
21
22 }
23 log.Printf("%s", result.Response.Body)
24}
Code example-PHP

1
2
3public function modifyCustomsDeclarartion($instance){
4 try {
5 $resp = $instance
6 ->chain('/v3/global/customs/orders')
7 ->patch([
8 'json' => [
9 'appid' => 'wxd678efh567hg6787',
10 'mchid' => '1230000109',
11 'out_trade_no' => '20150806125346',
12 'transaction_id' => '1000320306201511078440737890',
13 'customs' => 'SHANGHAI_ZS',
14 'merchant_customs_no' => '123456',
15 'duty' => 888,
16 'sub_order_no' => '20150806125346',
17 'order_fee' => 888,
18 'transport_fee' => 888,
19 'product_fee' => 888
20 ]
21 ]);
22
23 echo $resp->getStatusCode(), PHP_EOL;
24 echo $resp->getBody(), PHP_EOL;
25 } catch (\Exception $e) {
26
27 }
28}
Please refer to the API document for ordering by scanning code for other critical parameters.
Procedure: This interface allows merchants to query the additional customs declaration information submitted, as well as the status of customs declaration.
Code example-JAVA

1
2
3 public void queryCustomsDeclarationTest() throws IOException {
4 HttpGet httpGet = new HttpGet("https://apihk.mch.weixin.qq.com/v3/global/customs/orders?appid=wxd678efh567hg6787&mchid=mchid&order_type=transaction_id&order_no=1000320306201511078440737890&customs=SHANGHAI_ZS&offset=1&limit=20");
5 httpGet.addHeader("Accept", "application/json");
6 httpGet.addHeader("Content-type", "application/json; charset=utf-8");
7 CloseableHttpResponse response = httpClient.execute(httpGet);
8
9 }
10
Code example-Go

1
2
3func queryCustomsDeclaration() {
4 result, err := client.Get(ctx, "https://apihk.mch.weixin.qq.com/v3/global/customs/orders?appid=wxd678efh567hg6787&mchid=mchid&order_type=transaction_id&order_no=1000320306201511078440737890&customs=SHANGHAI_ZS&offset=1&limit=20")
5 if err != nil {
6
7 }
8 log.Printf("%s", result.Response.Body)
9}
Code example-PHP

1
2
3public function queryCustomsDeclaration($instance){
4 try {
5 $resp = $instance
6 ->chain('/v3/global/customs/orders')
7 ->get([
8 'query' => [
9 'mchid' => '1900000000',
10 'appid' => 'wxd678efh567hg6787',
11 'order_type' => 'transaction_id',
12 'order_no' => '1000320306201511078440737890',
13 'customs' => 'SHANGHAI_ZS',
14 'offset' => 1,
15 'limit' => 20
16 ]
17 ]);
18 echo $resp->getStatusCode(), PHP_EOL;
19 echo $resp->getBody(), PHP_EOL;
20 } catch (\Exception $e) {
21
22 }
23}
Please refer to the API document for ordering by scanning code for other critical parameters.
Procedure: When an order has been declared and the Customs requires the merchant to re-push the declaration information, this interface allows the merchant to re-send the declaration information to the Customs.
Code example-JAVA

1
2
3 public void repushCustomsDeclarartionTest() throws IOException {
4 String repushBody = """
5{
6 "appid": "wxd678efh567hg6787",
7 "mchid": "1230000109",
8 "out_trade_no": "20150806125346",
9 "transaction_id": "1000320306201511078440737890",
10 "sub_order_no": "20150806125346",
11 "sub_order_id": "1000320306201511078440737891",
12 "customs": "SHANGHAI_ZS",
13 "merchant_customs_no": "123456"
14}
15""";
16 HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/customs/redeclare");
17 httpPost.addHeader("Accept", "application/json");
18 httpPost.addHeader("Content-type", "application/json; charset=utf-8");
19 httpPost.setEntity(new StringEntity(repushBody));
20 CloseableHttpResponse response = httpClient.execute(httpPost);
21
22 }
23
Code example-Go

1
2
3func repushCustomsDeclarartion() {
4 repushBody := `
5{
6 "appid": "wxd678efh567hg6787",
7 "mchid": "1230000109",
8 "out_trade_no": "20150806125346",
9 "transaction_id": "1000320306201511078440737890",
10 "sub_order_no": "20150806125346",
11 "sub_order_id": "1000320306201511078440737891",
12 "customs": "SHANGHAI_ZS",
13 "merchant_customs_no": "123456"
14}
15`
16 result, err := client.Post(ctx, "https://apihk.mch.weixin.qq.com/v3/global/customs/redeclare", repushBody)
17 if err != nil {
18
19 }
20 log.Printf("%s", result.Response.Body)
21}
Code example-PHP

1
2
3public function repushCustomsDeclarartion($instance){
4 try {
5 $resp = $instance
6 ->chain('v3/global/customs/redeclare')
7 ->post([
8 'json' => [
9 'mchid' => '1230000109',
10 'appid' => 'wxd678efh567hg6787',
11 'out_trade_no' => '20150806125346',
12 'transaction_id' => '1000320306201511078440737890',
13 'sub_order_no' => '20150806125346',
14 'sub_order_id' => '1000320306201511078440737891',
15 'customs' => 'SHANGHAI_ZS',
16 'merchant_customs_no' => '123456'
17 ]
18 ]);
19 echo $resp->getStatusCode(), PHP_EOL;
20 echo $resp->getBody(), PHP_EOL;
21 } catch (\Exception $e) {
22
23 }
24}
Please refer to the API document for ordering by scanning code for other critical parameters.