跪拜 Guibai
← Back to the summary

WeChat Pay V3 for Mini Programs: A Complete Node.js Integration Walkthrough

Mini Program WeChat Pay V3 Integration Practical Manual: From Merchant Configuration to Frontend and Backend Implementation

If you have already applied for a WeChat Pay merchant account and want to integrate payment capabilities into your mini program, this article will walk you through the process step by step according to the official V3 interface standard, from account binding and platform configuration to frontend and backend code implementation, joint debugging, and launch. The entire process is based on the Node.js technology stack, the code can be directly reused, and a high-frequency pitfall checklist is attached at the end.

1. Pre-Start Preparation

1.1 Core Parameter Checklist

First, organize the following parameters. You will need them throughout the entire process, saving you the trouble of switching back and forth between platforms to find them.

Parameter Name Meaning Location
appid Mini Program Unique Identifier WeChat Official Accounts Platform → Development Management → Developer ID
mchid WeChat Pay Merchant Number Top of WeChat Pay Merchant Platform Homepage
apiV3Key APIv3 Symmetric Encryption Key Merchant Platform → Account Center → API Security → APIv3 Key
Merchant Certificate Serial Number API Certificate Number Merchant Platform → Account Center → API Security → Certificate Management
Merchant Private Key apiclient_key.pem Certificate File Inside the API certificate zip package downloaded from the Merchant Platform
notify_url Asynchronous Payment Result Callback Address Self-deployed backend HTTPS interface

1.2 Prerequisite Checks

Confirm these points first to avoid wasted effort:

2. Binding the Merchant Account to the Mini Program AppID

This step is the core prerequisite. Without binding, the mini program has no permission to call the payment capabilities of this merchant account.

2.1 Initiating Authorization from the Merchant Platform

  1. Log in to the WeChat Pay Merchant Platform with the merchant account's super administrator account.
  2. Go to the left navigation: 'Product Center → Account Association (AppID Binding)', and click 'Add Authorized AppID' on the right.
  3. Accurately fill in the mini program's AppID, read and sign the authorization agreement, and submit.
    • If the merchant account and mini program entity are the same: Just wait for confirmation from the mini program side after submission.
    • If the entities are different: You need to additionally fill in the mini program's verified entity name and sign the 'Joint Operation Commitment Letter'.

2.2 Confirming Authorization in the Mini Program Backend

  1. Log in to the WeChat Official Accounts Platform (mini program account).
  2. Go to the left navigation: 'Features → WeChat Pay → Merchant Account Management', find the corresponding application in the 'Pending Associated Merchant Accounts' list.
  3. Click 'Confirm Authorization' to complete the binding.

You can also directly select 'Existing Merchant Account, Quick Binding' on the 'WeChat Pay' page in the mini program backend; the process and effect are the same.

2.3 Verifying the Binding Result

Go back to the 'Account Association' page on the Merchant Platform. When the corresponding AppID status shows 'Authorized', it is complete.

3. Merchant Platform API Security Configuration

The API Security page has four configuration items. For mini program V3 payment, you only need to configure two of them; the remaining two do not need to be touched.

3.1 Merchant API Certificate (Must Configure)

When the backend calls all V3 interfaces, it must use the merchant private key in the certificate to sign the request to prove the merchant's identity. This is mandatory.

Steps:

  1. Enter the Merchant Platform 'Account Center → API Security → Merchant API Certificate', and click 'Apply for Certificate'.
  2. Follow the on-page instructions to generate a certificate request file, submit it, and download the certificate zip package.
  3. After decompression, you get two core files:
    • apiclient_key.pem: The merchant private key, the core credential for backend signing. Do not leak it.
    • apiclient_cert.pem: The merchant public key certificate.

You can find the corresponding certificate serial number on the certificate details page; note it down for later use.

3.2 APIv3 Key (Must Configure)

This is commonly known as apiV3Key, a 32-bit symmetric encryption key used to decrypt WeChat Pay callback notifications and download platform certificates.

Generation Rules

Three Quick Generation Methods

Pick whichever is convenient:

Method 1: Browser Console (Zero Dependencies, Fastest) Open any webpage, press F12 to open Developer Tools, switch to the Console tab, and execute the following code to get the result directly:

btoa(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(24))))
  .replace(/[^a-zA-Z0-9]/g, '')
  .slice(0, 32)

Method 2: Node.js Command Line

Windows CMD/PowerShell has issues parsing nested quotes, use this version:

node -e "const c=require('crypto');console.log(c.randomBytes(24).toString('base64').replace(/[^a-zA-Z0-9]/g,'').slice(0,32))"

Method 3: Local Script File (Fully System Compatible, Most Stable) Create a new genkey.js file, write the following code, and execute node genkey.js in the terminal:

const crypto = require('crypto');
const apiV3Key = crypto.randomBytes(24)
  .toString('base64')
  .replace(/[^a-zA-Z0-9]/g, '')
  .slice(0, 32);
console.log('Generated APIv3 Key:', apiV3Key);
console.log('Length Check:', apiV3Key.length);

Note: After generating the key, save it permanently immediately. Once set in the WeChat backend, the plaintext cannot be viewed. If lost, it can only be reset, which will affect online callback decryption.

3.3 Explanation of the Two Items Not Requiring Configuration

The remaining two configuration items do not need attention; don't waste time:

4. Mini Program Backend Basic Configuration

Two things to do, and then you can start writing code.

  1. Configure Server Domain Name Enter the mini program backend 'Development Management → Development Settings → Server Domain Name', and add the domain name corresponding to the backend interface in the 'request legal domain names'.

    Note: Mini program payment does not require configuring a payment authorization directory. This is a core difference from Official Account JSAPI payment; don't waste time looking for this option.

  2. Payment Capability Check On the 'WeChat Pay' page in the mini program backend, if you can see the bound merchant account and its status is 'Normal', it means the payment permission is active.

5. Backend Service Development (Node.js + V3 Interface)

5.1 Complete Payment Flow

First, clarify the entire interaction logic; don't write the sequence in reverse:

  1. The user clicks to pay in the mini program, and the frontend obtains the login code and passes it to the backend.
  2. The backend exchanges the code for the user's openid.
  3. The backend generates a unique merchant order number, calls the WeChat JSAPI unified order placement interface, and obtains the prepay_id.
  4. The backend generates the signature parameters required for the frontend to invoke payment based on the prepay_id and returns them to the mini program.
  5. The mini program calls wx.requestPayment to bring up the payment cashier.
  6. After the user completes payment, WeChat asynchronously calls back the backend notify_url, and the backend updates the order status.
  7. In the frontend payment callback, request the backend to query the real order status, then display the final result.

Don't think this flow is too verbose. Many people skip steps and end up spending ages troubleshooting problems.

5.2 Dependency Installation and Initialization

It is recommended to use the wechatpay-node-v3 SDK, so you don't have to write the signature logic yourself, avoiding 90% of the pitfalls.

Install dependencies:

npm install wechatpay-node-v3 axios

Initialize payment configuration:

const WxPay = require('wechatpay-node-v3');
const fs = require('fs');
const path = require('path');

// Read the merchant private key file
const privateKey = fs.readFileSync(
  path.join(__dirname, './cert/apiclient_key.pem'),
  'utf8'
);

const wxPay = new WxPay({
  appid: 'Your Mini Program appid',
  mchid: 'Your Merchant Number mchid',
  privateKey: privateKey,
  serial_no: 'Your Merchant Certificate Serial Number',
  apiv3_private_key: 'Your APIv3 Key',
});

5.3 JSAPI Unified Order Placement Interface

/**
 * JSAPI Unified Order Placement
 * @param {string} openid User openid
 * @param {string} outTradeNo Merchant order number (globally unique)
 * @param {number} total Payment amount, unit: cents
 * @param {string} description Product description
 */
async function createOrder(openid, outTradeNo, total, description) {
  const params = {
    description: description,
    out_trade_no: outTradeNo,
    notify_url: 'https://your-domain/api/pay/notify',
    amount: {
      total: total,
      currency: 'CNY',
    },
    payer: {
      openid: openid,
    },
  };

  const result = await wxPay.transactions_jsapi(params);
  
  // Generate the complete signature parameters needed for the frontend to invoke payment
  const payParams = await wxPay.getSignParams(result.prepay_id);
  return payParams;
}

5.4 Asynchronous Payment Result Callback Handling

Callback interface requirements: A publicly accessible HTTPS address, supports POST requests, cannot contain port numbers or parameters.

Core logic: First verify the signature and decrypt, then process the order, and finally must return a success response to WeChat, otherwise WeChat will continuously retry the callback.

// Payment callback interface
async function payNotify(req, res) {
  try {
    // Verify signature and decrypt the callback message
    const result = wxPay.verifySignAndDecrypt(req.headers, req.body);
    
    if (result.trade_state === 'SUCCESS') {
      // Payment successful, update database order status, handle business logic
      const outTradeNo = result.out_trade_no;
      const transactionId = result.transaction_id;
      
      // Must return a success response, otherwise WeChat will keep retrying
      res.status(200).json({ code: 'SUCCESS', message: 'Success' });
    } else {
      res.status(200).json({ code: 'FAIL', message: 'Payment not successful' });
    }
  } catch (err) {
    console.error('Payment callback processing failed', err);
    res.status(500).json({ code: 'FAIL', message: 'Processing failed' });
  }
}

5.5 Order Query Interface

Key point: Never rely solely on WeChat's asynchronous callback. The frontend must actively query the order status after the payment operation is complete. Callbacks can be delayed, lost, or even forged.

async function queryOrder(outTradeNo) {
  const result = await wxPay.query({ out_trade_no: outTradeNo });
  return result;
}

6. Mini Program Frontend Payment Implementation

6.1 Frontend Payment Flow

  1. Call wx.login() to get a temporary login credential code.
  2. Pass the code to the backend to initiate the order request.
  3. Receive the payment parameters returned by the backend, call wx.requestPayment to bring up the payment interface.
  4. After the payment operation is complete, request the backend to query the real order status and display the result.

6.2 Complete Code Example

Page({
  // Pay button click event
  async handlePay() {
    wx.showLoading({ title: 'Paying...', mask: true });
    
    try {
      // 1. Get login credential code
      const { code } = await wx.login();
      
      // 2. Request backend to place order, get payment parameters
      const payRes = await wx.request({
        url: 'https://your-domain/api/pay/createOrder',
        method: 'POST',
        data: {
          code: code,
          goodsId: 'Product ID',
        },
      });
      
      const payParams = payRes.data.data;
      
      // 3. Bring up WeChat Pay cashier
      const paymentResult = await wx.requestPayment({
        timeStamp: payParams.timeStamp,
        nonceStr: payParams.nonceStr,
        package: payParams.package,
        signType: payParams.signType,
        paySign: payParams.paySign,
      });
      
      // 4. Payment operation complete, actively query order status
      if (paymentResult.errMsg === 'requestPayment:ok') {
        const orderRes = await wx.request({
          url: 'https://your-domain/api/pay/queryOrder',
          data: { outTradeNo: 'Current merchant order number' },
        });
        
        if (orderRes.data.data.tradeState === 'SUCCESS') {
          wx.showToast({ title: 'Payment Successful', icon: 'success' });
          // Business navigation after successful payment
        }
      }
    } catch (err) {
      if (err.errMsg === 'requestPayment:fail cancel') {
        wx.showToast({ title: 'Payment Cancelled', icon: 'none' });
      } else {
        wx.showToast({ title: 'Payment Failed', icon: 'error' });
        console.error('Payment exception', err);
      }
    } finally {
      wx.hideLoading();
    }
  },
});

Note: The payment amount should not be passed from the frontend. The backend should calculate it based on the product ID to prevent tampering.

7. Joint Debugging, Testing, and Launch

7.1 Joint Debugging Notes

7.2 Pre-Launch Checklist

Go through and check off each item; don't miss anything:

8. High-Frequency Pitfall Avoidance Guide

These are all pitfalls encountered in actual projects, listed here to save you from stepping into them:

  1. Incorrect Amount Unit: All WeChat Pay interface amounts are in cents, not yuan. Passing the wrong unit will result in a 100x difference.
  2. Signature Verification Failure: 90% of cases are due to incorrect parameter casing, mismatched certificate serial numbers, or inconsistent APIv3 keys.
  3. Callback Not Triggering: Check if the interface is POST, supports HTTPS, and is not blocked by a firewall. If necessary, whitelist WeChat's official callback IP ranges.
  4. Duplicate Callback Handling: WeChat Pay callbacks may be pushed multiple times. The backend must implement idempotent processing to avoid executing business logic repeatedly.
  5. Cross-Entity Binding Restrictions: If the merchant account and mini program entity are inconsistent, additional review is required, and some payment features are restricted. Prioritize using a merchant account with the same entity.