CloudBase WeChat integration guide for Mini Program WeChat Pay, Mini Program virtual payment (虚拟支付, wx.requestVirtualPayment), Official Account JSAPI Pay, Native QR-code Pay, Official Account OAuth, openid handling, payment callbacks, and CloudBase Integration Center generated functions. This skill should be used when users ask to add, debug, or extend WeChat payment, virtual payment, or official-account flows on CloudBase.
Coding
云开发-微信支付
Try itThis skill provides battle-tested guidance for integrating WeChat Mini Program payment and refund flows using Tencent CloudBase. It covers cloud.cloudPay.unifiedOrder() for payments, cloud.cloudPay.refund() for refunds, cloud functions, deployment via CLI, and a catalog of critical pitfalls with fix
What it does
This skill provides battle-tested guidance for integrating WeChat Mini Program payment and refund flows using Tencent CloudBase. It covers cloud.cloudPay.unifiedOrder() for payments, cloud.cloudPay.refund() for refunds, cloud functions, deployment via CLI, and a catalog of critical pitfalls with fixes. Use this skill when building, debugging, or reviewing mini-program payment features on CloudBase — especially when payments go to simulated mode, refunds silently fail, or cloud-call access_token errors surface.
The skill document
CloudBase 微信小程序支付集成
一站式指南:微信支付 + 原路退款 + CloudBase 云开发,含踩坑全记录。
Overview
This skill encodes a full payment-refund integration cycle on CloudBase: unified-order payment → order management → server-side refund → historical order backfill. It covers both the happy path and every trap encountered during a real production build, so future integrations skip the debugging marathon.
When to Use
Trigger this skill when:
- Building a new WeChat Mini Program that needs payment via CloudBase
- Debugging "payment went to simulated mode" or "env vars missing on deploy"
- Implementing refunds and getting
returnCode/resultCodeconfusion - Seeing
-501001 invalid wx openapi access_tokenduring refund calls - Historical orders need backfilled refunds
- Reviewing payment/refund code for correctness
Prerequisites
- WeChat Mini Program with CloudBase (云开发) enabled
- WeChat Pay merchant account (微信支付商户号) associated with the mini program
- CloudBase CLI (
tcb) installed and logged in:npm i -g @cloudbase/cli - Cloud functions:
order,payment(minimum)
Architecture Overview
Mini Program (wx.cloud.callFunction)
↓
order 云函数 (business logic, status management)
↓
payment 云函数 (wraps cloud.cloudPay.* calls)
↓
CloudBase cloud.cloudPay.unifiedOrder() / refund()
↓
WeChat Pay API
Key separation principle
Keep payment calls in a dedicated payment cloud function — never spread
cloud.cloudPay.* across multiple functions. This isolates the cloud-call
context dependency and makes debugging tractable.
Payment Integration Workflow
Step 1: Unified Order (统一下单)
In the payment cloud function, the core call:
const result = await cloud.cloudPay.unifiedOrder({
body: '商品描述',
outTradeNo: orderId, // unique order number
totalFee: 1, // integer fen (分), e.g. 1 = 0.01 CNY
spbillCreateIp: '127.0.0.1',
tradeType: 'JSAPI',
envId: 'your-env-id', // HARDCODE, never DYNAMIC_CURRENT_ENV
functionName: 'payment',
subMchId: '', // omit if not sub-merchant mode
});
Critical:
envIddoes NOT work withcloud.DYNAMIC_CURRENT_ENV— hardcode the environment ID string.- Remove
subAppIdunless in sub-merchant mode. Case mismatches cause cryptic API errors. totalFeeis in fen (分), not yuan.
Step 2: Upload Cloud Functions via CLI (NOT DevTools)
DevTools auto-upload does not carry environment variables
(WX_MCH_ID, etc.) to the cloud → payment silently falls back to simulated
mode (no real charge).
Use CLI deployment:
tcb fn deploy payment --envId
tcb fn deploy order --envId
Verify deployment with:
tcb fn list --envId
Step 3: Environment Variables
In cloudbaserc.json or CloudBase console, ensure:
{
"env": {
"WX_APPID": "wx...",
"WX_MCH_ID": "1...",
"WX_MCH_KEY": "..."
}
}
The payment cloud function must read these at runtime:
const mchId = process.env.WX_MCH_ID;
if (!mchId) {
// This is the symptom of DevTools deploy — abort with clear error
return { code: -1, message: 'WX_MCH_ID not set — use CLI deployment' };
}
Refund Integration Workflow
Step 1: Core Refund Call
In the payment cloud function, add a refund action:
async function handleRefund(orderId, totalFee, refundFee, outRefundNo) {
const result = await cloud.cloudPay.refund({
subMchId: '', // omit if not sub-merchant
transactionId: orderId,
outTradeNo: orderId,
outRefundNo: outRefundNo || generateOutRefundNo(orderId),
totalFee: totalFee, // original total in fen
refundFee: refundFee, // amount to refund in fen
envId: 'your-env-id', // hardcoded, same as payment
functionName: 'payment',
});
return result;
}
Step 2: CRITICAL — Double-Layer Return Check
This is the #1 cause of silent refund failures. The refund return
object has two layers, both must be checked:
const refundResult = await cloud.cloudPay.refund({...});
// Layer 1: CloudBase wrapper
if (refundResult.returnCode !== 'SUCCESS') {
return { code: -1, errMsg: refundResult.returnMsg || 'refund wrapper failed' };
}
// Layer 2: WeChat Pay result
if (refundResult.resultCode !== 'SUCCESS') {
return {
code: -1,
errCode: refundResult.errCode,
errMsg: refundResult.errCodeDes || 'refund payment failed',
};
}
// Only now is the refund truly successful
// Store refundTransactionId from result.refundId or result.transactionId
return {
code: 0,
refundTransactionId: refundResult.refundId,
};
Never check only code and assume success — the old code path that caused
refundTransactionId to be empty did exactly this.
Step 3: Order Status After Refund
The order cloud function should:
- Call
paymentcloud function'srefundaction - Check
returnCodeANDresultCodeon the returned result - Only set
refundTransactionIdandrefundedAtwhen both succeed - If refund fails, DO NOT change status to
user_cancelled— leave as-is and surface the error
// In order cloud function, processRefund action:
const refundRes = await callPaymentCloud('refund', { orderId, totalFee, refundFee });
if (refundRes.returnCode !== 'SUCCESS' || refundRes.resultCode !== 'SUCCESS') {
return { code: -1, errCode: refundRes.errCode, errMsg: refundRes.errCodeDes };
}
// Only now update the order document:
await db.collection('orders').doc(orderId).update({
data: {
status: 'user_cancelled',
refundedAt: new Date(),
refundTransactionId: refundRes.refundId,
},
});
Critical Pitfalls Catalog
For the full pitfall catalog with debugging commands and fix recipes,
load references/gotchas.md.
Quick reference of the top 5 pitfalls:
| # | Pitfall | Symptom | Fix |
|---|---|---|---|
| 1 | DevTools deploy loses env vars | Payment goes to simulated mode, WX_MCH_ID is empty | Use tcb fn deploy CLI |
| 2 | envId: cloud.DYNAMIC_CURRENT_ENV | unifiedOrder returns unexpected data | Hardcode env ID string |
| 3 | subAppId case mismatch | unifiedOrder returns resultCode: FAIL | Remove subAppId if not using sub-merchant |
| 4 | Refund return not checked properly | refundTransactionId stays empty, order marked "refunded" but money never returned | Double-layer check: returnCode + resultCode |
| 5 | CLI tcb fn invoke for refund | -501001 invalid wx openapi access_token | Cloud calls need mini-program context; use wx.cloud.callFunction from mini program side |
Cloud Call Context Rules
cloud.cloudPay.refund() and cloud.cloudPay.unifiedOrder() are
cloud calls (云调用). They require WeChat-side authentication context.
Only these invocation methods carry valid context:
| Method | Works? | Reason |
|---|---|---|
wx.cloud.callFunction from Mini Program | ✅ Yes | Carries user session + WeChat auth |
| Timer trigger (定时触发器) | ✅ Yes | Platform injects context |
| HTTP API trigger | ✅ Yes | Platform injects context |
tcb fn invoke (CLI) | ❌ No | No mini-program session → access_token failure |
| CloudBase console "Test" button | ❌ No | Same reason as CLI |
Rule: Any cloud call needing WeChat Pay access_token must originate from one of the three "✅ Yes" methods. When testing refunds or troubleshooting historical orders, trigger through the Mini Program UI, not CLI.
Deployment Checklist
Before testing payment in production:
- Cloud functions deployed via
tcb fn deploy(not DevTools) -
envIdhardcoded as string in allcloud.cloudPay.*calls -
WX_MCH_ID,WX_APPID,WX_MCH_KEYset as environment variables - Payment cloud function reads env vars and fails fast if missing
-
subAppIdremoved fromunifiedOrderunless sub-merchant mode - Refund code has double-layer
returnCode+resultCodecheck - Historical order backfill uses mini-program-side trigger (not CLI)
Debugging a Failed Refund
When a user reports "order cancelled but money not returned":
-
Query the order document: Check
refundTransactionId— if empty string, refund never executed.tcb db query --envId -c orders --where '{"_id":""}' -
Check order status: If status is
user_cancelledbutrefundTransactionIdis empty, the old bug is confirmed. -
Fix: Add a
force_refundaction in thepaymentcloud function that bypasses status checks, then trigger it from the Mini Program viawx.cloud.callFunction({ name: 'payment', data: { action: 'force_refund', orderId } }). -
Cleanup: After backfilling, remove
force_refundand any related UI buttons — they are temporary fixes, not intended for users.
Resources
references/gotchas.md— Full pitfall catalog with debugging commands, error code reference, and the exact chain of bugs encountered during the real build.
Related skills
Route CloudBase scenarios to the right child skill and enforce the prep-then-implement-then-review workflow.
从零快速搭建一个微信小程序(后端用微信云开发/CloudBase)的脚手架与方法论:单函数 REST 路由、幂等建号/幂等建集合、实时统计、订阅消息+定时触发器、全生命周期坑。Scaffold & methodology for building a WeChat Mini Program on WeChat CloudBase: single-function REST routing, idempotent user/collection seeding, real-time stats, subscribe messages + scheduled triggers, full-lifecycle pitfalls. Use when: 做一个云开发小程序 / 从零搭小程序 / 小程序 MVP / building a WeChat Mini Program MVP. Deployment details → wechat-miniprogram-cloudbase-deploy skill.
微信支付(WeChat Pay)相关问题的统一入口,处理与微信支付接入、产品、开发、运营、品牌经营相关的咨询,提供产品选型、官方示例代码、接入质量评估、答疑与排障。Use when user mentions "微信支付", "微信收款", "WeChat Pay", "JSAPI", "APP支付", "H5支...
WeChat Mini Program deployment onto WeChat CloudBase (云开发): deploy cloud functions via tcb, manually create database collections in the console, and upload the frontend via miniprogram-ci. Covers real-environment pitfalls: CLI cannot create collections, tcb fn invoke returns a Namespace metadata bug, the upload IP-whitelist only accepts IPv4 (so an IPv6 egress is always rejected), and the trial env defaults to ap-shanghai. Trigger when the task involves 部署微信小程序, 云开发, CloudBase, tcb 部署云函数, or miniprogram-ci 上传.
Fast path for a minimal CloudBase Web + database demo (最小前后端 / 最小可用 fullstack / Lovable-like BaaS). Defaults to @cloudbase/js-sdk client CRUD (NoSQL app.database / PG app.rdb), MCP-only schema, preview-first, and forbids cloud functions unless secrets, cron/background jobs, or logic that security rules/RLS cannot express. Use for 搭一套 demo、留言板、Todo、Notes、Kanban, or when users say 带云函数+云数据库 but only need CRUD. NOT for production multi-service backends, CloudRun, WeChat Mini Programs, or tasks that truly need server secrets.