WeChat Pay
Surface BoomPay alongside WeChat Pay in merchant checkout: WeChat Pay handles its own wallet flow, BoomPay handles Boomcoin, and your platform presents both to the customer.
WeChat Pay’s merchant platform does not expose an API for registering third-party settlement rails inside the WeChat Pay wallet flow itself. The workable pattern is presenting WeChat Pay and BoomPay as two distinct options on the same checkout page — WeChat Pay’s JSSDK or QR code handles the WeChat wallet path, and BoomPay’s redirect handles Boomcoin. Your existing WeChat Pay integration is unchanged; BoomPay is additive.
Flow
Checkout prepared
Your server creates a WeChat Pay unified order (unchanged) and a BoomPay intent in parallel, and passes both to the page.
Customer chooses
Checkout renders the WeChat Pay button/QR and a separate Boomcoin button.
BoomPay path
Customer clicks Boomcoin — browser redirects to BoomPay's hosted page.
Customer pays
The customer approves from their Boom wallet.
Signed return
BoomPay redirects to your return URL with paymentIntentId and X-Boom-Signature.
Confirm
Your handler verifies the signature, confirms via getPayment(), and notifies the merchant.
Code
const BoomPay = require('boom-pay-sdk');
// For merchants accepting WeChat Pay, add a BoomPay option in parallel.
// WeChat Pay uses its own JS SDK/JSSDK for the WeChat wallet flow;
// BoomPay uses a plain redirect.
async function prepareCheckout(merchant, order) {
const boomPay = new BoomPay({
apiKey: merchant.boompayApiKey,
sandbox: process.env.NODE_ENV !== 'production',
});
// WeChat Pay: generate your prepay_id / code_url via WeChat Pay's
// Unified Order API as normal. This is unchanged by adding BoomPay.
const wechatOrder = await createWechatOrder(merchant, order);
// BoomPay: create an intent for the Boomcoin option.
const intent = await boomPay.payments.createIntent({
amount: toBmc(order.total, order.currency),
successUrl: `${process.env.PSP_BASE}/boompay/return?status=success&order=${order.id}&mid=${merchant.id}`,
failureUrl: `${process.env.PSP_BASE}/boompay/return?status=failure&order=${order.id}&mid=${merchant.id}`,
label: `${merchant.name} Order ${order.reference}`,
metadata: { orderId: order.id, merchantId: merchant.id },
});
return {
wechatPrepayId: wechatOrder.prepay_id,
wechatCodeUrl: wechatOrder.code_url, // for QR-code display outside WeChat
boompayLink: intent.link,
};
}
function toBmc(amount, currency) {
return amount; // placeholder
}
async function createWechatOrder(merchant, order) {
// Your existing WeChat Pay Unified Order API call -- unchanged.
// Returns { prepay_id, code_url } as normal.
}const crypto = require('crypto');
async function handleBoompayReturn(req, res) {
const { order: orderId, mid, status } = req.query;
const intentId = req.query.paymentIntentId;
const signature = (req.query['X-Boom-Signature'] || '').replace(/ /g, '+');
const merchant = await db.getMerchant(mid);
const expected = crypto.createHmac('sha1', merchant.boompayApiKey)
.update(intentId).digest('base64');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(403).send('Invalid signature');
}
const boomPay = new BoomPay({ apiKey: merchant.boompayApiKey, sandbox: process.env.NODE_ENV !== 'production' });
const payment = await boomPay.payments.getPayment(intentId);
if (status === 'success' && payment.paidAt) {
await db.markOrderPaid(orderId, { provider: 'boompay', reference: intentId });
await notifyMerchant(merchant, 'PAYMENT_COMPLETE', orderId);
return res.redirect(merchant.successUrl);
}
await db.markOrderFailed(orderId);
res.redirect(merchant.failureUrl);
}Go-live checklist
- BoomPay’s hosted page opens in the customer’s default browser — confirm this works correctly from within WeChat’s in-app browser if your checkout is embedded there.
- Implement
toBmc()with a real conversion rate. - Lock the order once either the WeChat Pay flow or BoomPay flow starts, to prevent double-fulfillment.