“woman wearing beanie with smartphone on ear” by Fezbot2000 on Unsplash

Purpose: To help you avoid those rabbit holes and set up WeChat payment on your WeChat mini-program.

Prerequisites:

Basic Knowledge of Node.js

Basic Knowledge of WeChat Mini-program

WeChat Mini-Program Account(Apply here: https://mp.weixin.qq.com/)

WeChat Merchant Account

Important Credentials Needed:

Miniprogram’s App ID

Miniprogram’s App Secret

Merchat ID

Vendor Key(or Merchant Key or Partner Key)

Important Note: Never expose these credential in public repositories. Use environment variables.

In a nutshell:

Source: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3

Overwhelmed? No worries. Let’s break it down.

Get user’s OpenID

On Miniprogram side:

wx.login({
success (res) {
if (res.code) {
 wx.request({
url: 'http://your-back-end.com/login',
data: {
code: res.code
}
})
} else {
// Handle failed request to Tencent API
}
}
})

On Your Backend Server

router.get('/getOpenID/:code', async (req, res) => {
 const { code } = req.params;
 const url = `https://api.weixin.qq.com/sns/jscode2session? appid=${your_miniprogram_app_id}&secret=${your_miniprogram_app_secret}&js_code=${code}&grant_type=authorization_code`;
 // Use axios, request, or whatever to make a GET request to this endpoint then it should return the OpenID and Session of the user
});

Bonus tip: You could use wx.setStorage() to storage the OpenID and Session of the user.

Place an order on Tencent Server

The easy way:

Download npm module here: https://www.npmjs.com/package/wechat-pay

In your backend writes:

var order = {
body: 'Product Title',
attach: '{"Stringified":"Object"}',
out_trade_no: 'kfc' + (+new Date),
total_fee: 10 * 100,
spbill_create_ip: req.ip,
openid: req.user.openid,
trade_type: 'JSAPI'
};
payment.getBrandWCPayRequestParams(order, function(err, payargs){
res.json(payargs);
});

At your miniprogram:

Use the payargs from the backend, use the wx.requestPayment as such

wx.requestPayment({
timeStamp: '',
nonceStr: '',
package: '',
signType: 'MD5',
paySign: '',
success (res) { },
fail (res) { }
})

The hard way(If you are a curious cat):

In your backend:

  1. Generate signature

Concatenate all params into string by alphabetically order of the params keys

Add WeChat Payment Key at the end like “&key=your_key_here”

Hash the whole string with MD5 or HMAC-SHA256

Params(Bold params are required):

appid, mch_id, device_info, nonce_str, sign, sign_type, body, detail, attach, out_trade_no, fee_type, total_fee, spbill_create_ip, time_start, time_expire, goods_tag, notify_url, trade_type, product_id, limit_pay, openid

Definitions:

mch_id: Merchat ID / Vendor Key(or Merchant Key or Partner Key)

nonce_str: Random String

sign: Signature

sign_type: MD5 or HMAC-SHA256

body: Product title(Usually the name of the product)

detail: Product Description(Usually the quantity and specs)

attach: Extra data stringified

fee_type: Currency type

total_fee: Payment amount. Note: Fee is one hundredth of the value. Example: total_fee: 1 = 0.01 RMB

spbill_create_ip: IP of your server

goods_tag: Used for WeChat coupons

notify_url: The callback url for Tencent server to notify your server

trade_type: Should be JSAPI. You will deal will other types if you are building native apps

out_trade_no: An unique order identification. Alphanumeric. Limited to 32 characters.

Can include _-|*

2. Send it in XML strings as Form Data

3. Make a POST request to this endpoint: https://api.mch.weixin.qq.com/pay/unifiedorder

4. Use the prepay_id from tencent server and generate the signature on our own server the second time

5. params to put into signature:

appId: appid,

nonceStr: nonceStr,

package: package,

signType: signType,

timeStamp: timeStamp

6. Return the params above with the signature to miniprogram

Setup Callback Url for Payment Result

  1. We get the result of the payment in notify_url in rawBody in XML format
  2. Validate if signature matches to prevent fake notification

Using the wechat-pay npm module, you can

var middleware = require('wechat-pay').middleware;
app.use('<notifyUrl>', middleware(initConfig).getNotify().done(function(message, req, res, next) {
var openid = message.openid;
var order_id = message.out_trade_no;
var attach = {};
try{
attach = JSON.parse(message.attach);
// Do something on your own server about the successful payment
}catch(e){
// If there's error, reply with, if you don't Tencent server will ping you server three more times
res.reply(new Error(e));
}
res.reply('success');
}));

Common Pitfall

The first time that I was doing this, I kept receiving invalid signature from Tencent server. It made me question my life’s choices for two days.

Then I realized my client has given me the wrong vendor key. Because the signature is comprised of several params, you must make sure every params are correct.

Vendor key is not the App key. Reset the vendor key if you have to.

Beware of the 32 character limits of out_trade_no

Hardcode the total_fee so you don’t accidentally pay too much for testing

Documents

To test signature: https://pay.weixin.qq.com/wiki/tools/signverify/

Official WeChat Miniprogram Doc

Official WeChat Payment Doc

Still confused?

If WeChat development is fresh to you, here’s a free glossary to get you up to speed. 1 Billion of WeChat’s user awaits.


How to integrate WeChat payment? was originally published in China Software Development on Medium, where people are continuing the conversation by highlighting and responding to this story.