WeChat Mini Program Server API

raw JSON →
1.8.18 verified Tue May 12 auth: no python install: stale quickstart: stale

Server-side Python SDK for WeChat (Weixin) Mini Programs. Handles the backend half of Mini Program interactions: login verification (jscode2session), access token management, template messages, and encrypted data decryption. The dominant community SDK is wechatpy — no official Tencent Python SDK exists. Mini Program frontend runs in WeChat's JavaScript runtime (WXML/WXSS); Python handles server-side API calls only.

pip install 'wechatpy[cryptography]'
error ValueError: Padding is incorrect and cannot be removed.
cause This error often occurs during encrypted data decryption (e.g., Mini Program user data) if the session key, IV, or encrypted data is corrupted, malformed, or does not match the expected format.
fix
Ensure the session_key and iv obtained from the jscode2session API are correctly passed to the decryption function, and that the encrypted_data is the exact string received from the Mini Program frontend without alteration.
error {"errcode":40001,"errmsg":"invalid credential"}
cause This is a WeChat API response indicating that the `appid` or `appsecret` used in your `wechatpy` client initialization is incorrect, expired, or does not have the necessary permissions for the requested operation.
fix
Verify that your WeChat Mini Program's AppID and AppSecret are correctly configured in your WeChatClient or MiniProgramClient initialization, and that they are up-to-date and valid.
error wechatpy.exceptions.InvalidSignatureException
cause This exception is raised when `wechatpy` fails to verify the signature of an incoming WeChat message or event, meaning the token configured in your WeChat developer console does not match the token used by your `wechatpy` application.
fix
Check that the WeChat 'Token' configured in your Mini Program/Official Account backend developer settings is exactly the same as the token parameter used when initializing your WeChatClient or WeChatServer.
error {"errcode":40029,"errmsg":"invalid code"}
cause This WeChat API response specifically for `jscode2session` indicates that the JS Code provided by the Mini Program frontend is invalid, expired, or has already been used to exchange for a session key.
fix
Ensure the JS Code sent from the Mini Program frontend is fresh (generated just before the request) and used only once per jscode2session call. It expires very quickly.
breaking Phone number retrieval API changed in base library 2.21.2. Old pattern (encryptedData + iv AES decrypt using session_key) still works but is deprecated. New pattern: frontend button callback returns a `code`, server exchanges it via POST /wxa/business/getuserphonenumber. The two codes (wx.login code vs phone code) are NOT interchangeable.
fix Use the code-exchange pattern. Never mix wx.login() code with getPhoneNumber code. Old AES decrypt pattern is in 90% of tutorials but deprecated.
breaking getPhoneNumber and getRealtimePhoneNumber components are paid since August 28, 2023. Standard price: ¥0.03/call (quick verification) and ¥0.04/call (real-time verification). Each Mini Program account gets 1000 free calls for development. Production usage requires prepaid balance on WeChat Open Platform.
fix Pre-purchase call quota at mp.weixin.qq.com → Payment Management before going live.
breaking `unionid` is NOT always returned by jscode2session. It only appears if the Mini Program is bound to a WeChat Open Platform account AND the user has authorized it. Many tutorials assume unionid is always present, causing KeyError in production.
fix Always use .get('unionid') not ['unionid']. Bind your Mini Program to an Open Platform account if cross-app user identity is needed.
breaking access_token is a global credential with a 2-hour TTL and a 2000 calls/day refresh limit. Calling getAccessToken on every request will exhaust the daily quota and lock out all users. wechatpy caches it in-process but does NOT share across multiple server instances.
fix Store access_token in Redis or a shared cache and check expiry before refreshing. Use wechatpy's session storage: WeChatMiniProgram(appid, secret, session=RedisStorage(redis_client)).
gotcha session_key must NEVER be sent to the frontend or logged. It is used server-side to decrypt sensitive user data. If session_key leaks, attackers can decrypt all encrypted user data. WeChat will invalidate session_key on wx.login() re-call.
fix Generate your own opaque session token (e.g. UUID) and map it to openid + session_key server-side.
gotcha Phone number API requires Mini Program registered as non-individual entity with WeChat verification. Individual developer accounts (个人开发者) cannot access getPhoneNumber even with balance. Overseas entities (non-China business registration) are also blocked.
fix Requires Chinese business entity + WeChat verification. Overseas businesses must use a Chinese registered subsidiary or partner.
gotcha wechatpy v1.8.18 is the last PyPI release and the package is effectively in maintenance mode (Snyk flags it as inactive). Core APIs remain functional but new WeChat features may not be supported.
fix For newer APIs not in wechatpy, call the WeChat API directly via requests using client.access_token.
gotcha WeChatClient (for Official Accounts/MP) and WeChatMiniProgram (for Mini Programs) are different classes with different API surfaces. Official Account tutorials are the majority online — importing the wrong client causes silent failures or wrong endpoint calls.
fix from wechatpy.miniprogram import WeChatMiniProgram — not WeChatClient.
breaking The `wechatpy.miniprogram` module, which contains `WeChatMiniProgram`, is fundamental for Mini Program development. A `ModuleNotFoundError` for this module, despite `wechatpy` (e.g., version 1.8.18) being reported as successfully installed, indicates a problem with the Python environment where the package was installed versus where the script is executed, or a corrupted installation.
fix Ensure the Python interpreter running the script has `wechatpy` installed and is properly configured to access it (e.g., using a virtual environment). Try reinstalling `wechatpy` in a clean virtual environment. Verify the contents of the installed `wechatpy` package to confirm `wechatpy/miniprogram/__init__.py` exists.
breaking wechatpy-1.8.18, despite installing successfully, fails to import 'wechatpy.miniprogram' on Python 3.13 environments (e.g., python:3.13-alpine). This indicates a potential incompatibility or packaging issue with newer Python versions, as wechatpy is in maintenance mode and may not support Python 3.13.
fix Use an officially supported Python version (e.g., Python 3.8-3.11) with wechatpy-1.8.18, or consider migrating to a more actively maintained WeChat SDK for Python 3.13.
pip install wechatpy
python os / libc variant status wheel install import disk
3.10 alpine (musl) cryptography - - - -
3.10 alpine (musl) wechatpy - - - -
3.10 slim (glibc) cryptography - - - -
3.10 slim (glibc) wechatpy - - - -
3.11 alpine (musl) cryptography - - - -
3.11 alpine (musl) wechatpy - - - -
3.11 slim (glibc) cryptography - - - -
3.11 slim (glibc) wechatpy - - - -
3.12 alpine (musl) cryptography - - - -
3.12 alpine (musl) wechatpy - - - -
3.12 slim (glibc) cryptography - - - -
3.12 slim (glibc) wechatpy - - - -
3.13 alpine (musl) cryptography - - - -
3.13 alpine (musl) wechatpy - - - -
3.13 slim (glibc) cryptography - - - -
3.13 slim (glibc) wechatpy - - - -
3.9 alpine (musl) cryptography - - - -
3.9 alpine (musl) wechatpy - - - -
3.9 slim (glibc) cryptography - - - -
3.9 slim (glibc) wechatpy - - - -

Use WeChatMiniProgram (not WeChatClient) for Mini Programs. Cache access_token in Redis across server instances — it has a 2hr TTL and a 2000 calls/day refresh limit. Never send session_key to the frontend.

from wechatpy.miniprogram import WeChatMiniProgram
import requests

APPID = 'your_appid'
SECRET = 'your_appsecret'

# Initialize client
client = WeChatMiniProgram(APPID, SECRET)

# Step 1: Exchange wx.login() code for openid + session_key
# Frontend calls wx.login() and sends the code to your server
def login(js_code):
    result = client.code_to_session(js_code)
    # result = {'openid': '...', 'session_key': '...', 'unionid': '...' (if linked)}
    openid = result['openid']
    session_key = result['session_key']
    # NEVER send session_key to frontend — generate your own custom token
    return openid, session_key

# Step 2: Get phone number (NEW method, base library >= 2.21.2)
# Frontend button fires bindgetphonenumber event, returns e.detail.code
# Send that code to your server:
def get_phone_number(phone_code):
    # phone_code is different from wx.login() code — do NOT mix them
    resp = requests.post(
        'https://api.weixin.qq.com/wxa/business/getuserphonenumber',
        params={'access_token': client.access_token},
        json={'code': phone_code}
    )
    data = resp.json()
    return data['phone_info']['phoneNumber']  # e.g. '+8613800138000'

# Step 3: Global access_token (cache this — 2hr TTL, shared across all users)
print(client.access_token)  # auto-fetched and cached by wechatpy