{"id":82,"library":"wechatpayv3","title":"WeChat Pay Python SDK","description":"Community Python SDK for WeChat Pay API v3 — the de-facto standard for WeChat Pay v3 integration in Python. Covers direct merchant mode and service provider (partner) mode. Handles RSA signature generation, platform certificate auto-download and rotation, sensitive field encryption, and callback verification/decryption automatically. IMPORTANT: Multiple competing packages exist on PyPI (wechat_pay, pywechatpay, wechatpy, pywe-pay). Only 'wechatpayv3' targets the v3 API and is actively maintained. NOTE: This is a community SDK — WeChat Pay has no official Python SDK.","status":"active","version":"2.0.1","language":"python","source_language":"zh-CN","source_url":"https://github.com/minibear2021/wechatpay-python","tags":["wechat-pay","wechatpay","china","payments","v3","qr-code","jsapi","miniprogram","cnypayments","asian-payments"],"install":[{"cmd":"pip install wechatpayv3","lang":"bash","label":"Standard install"},{"cmd":"pip install wechatpayv3==2.0.1","lang":"bash","label":"Pinned install (recommended — v2.0.0 had breaking changes from v1.x)"},{"cmd":"pip install wechatpayv3[async]","lang":"bash","label":"With async support (FastAPI / asyncio)"}],"dependencies":[{"reason":"Required. Used for sync HTTP transport.","package":"requests","optional":false},{"reason":"Required. RSA signing, certificate handling, sensitive field encryption.","package":"cryptography","optional":false},{"reason":"Required for async variant only.","package":"httpx","optional":true}],"imports":[{"note":"The wrong import pulls from 'wechat_pay', a v2-era abandoned package with a completely different API.","wrong":"from wechatpay import WeChatPay","symbol":"WeChatPay, WeChatPayType","correct":"from wechatpayv3 import WeChatPay, WeChatPayType"}],"quickstart":{"code":"import os\nfrom wechatpayv3 import WeChatPay, WeChatPayType\n\n# Required credentials — all must be obtained from WeChat Pay Merchant Platform\nMCHID = os.environ['WECHAT_MCHID']               # Merchant ID\nPRIVATE_KEY = os.environ['WECHAT_PRIVATE_KEY']   # RSA private key (PEM string)\nCERT_SERIAL_NO = os.environ['WECHAT_CERT_SERIAL_NO']  # Certificate serial number\nAPPID = os.environ['WECHAT_APPID']               # WeChat App ID\nAPIV3_KEY = os.environ['WECHAT_APIV3_KEY']       # API v3 key (32 bytes)\nNOTIFY_URL = os.environ['WECHAT_NOTIFY_URL']     # Publicly accessible HTTPS endpoint\n\n# Initialize — cert_dir caches platform certificates locally\nwxpay = WeChatPay(\n    wechatpay_type=WeChatPayType.NATIVE,  # QR code pay\n    mchid=MCHID,\n    private_key=PRIVATE_KEY,\n    cert_serial_no=CERT_SERIAL_NO,\n    apiv3_key=APIV3_KEY,\n    appid=APPID,\n    notify_url=NOTIFY_URL,\n    cert_dir='./cert'  # Set to None during initial debug only\n)\n\n# Native pay (QR code) — returns code_url, convert to QR for user to scan\ncode, message = wxpay.pay(\n    description='Order description',\n    out_trade_no='YOUR_UNIQUE_ORDER_ID',\n    amount={'total': 100},  # Amount in fen (1 CNY = 100 fen)\n    pay_type=WeChatPayType.NATIVE\n)\n\n# JSAPI pay (in WeChat app / WeChat browser) — requires user openid\ncode, message = wxpay.pay(\n    description='Order description',\n    out_trade_no='YOUR_UNIQUE_ORDER_ID',\n    amount={'total': 100},\n    pay_type=WeChatPayType.JSAPI,\n    payer={'openid': 'USER_OPENID'}\n)\n\n# Query order\ncode, message = wxpay.query(out_trade_no='YOUR_UNIQUE_ORDER_ID')\n\n# Refund\ncode, message = wxpay.refund(\n    out_refund_no='YOUR_UNIQUE_REFUND_ID',\n    out_trade_no='YOUR_UNIQUE_ORDER_ID',\n    amount={'refund': 100, 'total': 100, 'currency': 'CNY'}\n)\n\n# Async usage (FastAPI example)\nfrom wechatpayv3 import AsyncWeChatPay, WeChatPayType\n\nasync def create_payment():\n    wxpay = AsyncWeChatPay(\n        wechatpay_type=WeChatPayType.NATIVE,\n        mchid=MCHID,\n        private_key=PRIVATE_KEY,\n        cert_serial_no=CERT_SERIAL_NO,\n        apiv3_key=APIV3_KEY,\n        appid=APPID,\n        notify_url=NOTIFY_URL\n    )\n    code, message = await wxpay.pay(\n        description='Order description',\n        out_trade_no='YOUR_UNIQUE_ORDER_ID',\n        amount={'total': 100},\n        pay_type=WeChatPayType.NATIVE\n    )\n    return code, message","lang":"python","description":"All amounts are in fen (smallest CNY unit). 100 fen = 1 CNY. NOTIFY_URL must be a publicly accessible HTTPS endpoint — localhost will not work. cert_dir should point to a persistent directory in production to avoid re-downloading platform certificates on every restart."},"warnings":[{"fix":"Verify merchant eligibility before starting integration. If you are a non-Chinese business, engage a WeChat Pay licensed partner. Integration code will work once valid credentials are obtained.","message":"WeChat Pay requires a Chinese business entity or a licensed overseas merchant partner to obtain merchant credentials (MCHID, API keys, certificates). Individual developers and non-Chinese companies cannot register directly. Overseas merchants must integrate via an authorized payment service provider (e.g. Stripe, Adyen, or a local aggregator) who handles the WeChat Pay merchant relationship.","severity":"breaking","affected_versions":"all"},{"fix":"Pin to 2.0.1: pip install wechatpayv3==2.0.1. Review changelog at github.com/minibear2021/wechatpay-python before upgrading from v1.x.","message":"v2.0.0 (Jul 2025) introduced breaking changes from v1.3.x. The jump from 1.3.11 to 2.0.0 occurred in a single day (Jul 29–30, 2025) with no deprecation period.","severity":"breaking","affected_versions":"< 2.0.0"},{"fix":"Install only 'wechatpayv3'. Verify with: pip show wechatpayv3 — author should be 'minibear'.","message":"Multiple PyPI packages share similar names: 'wechat_pay' (v2-era, abandoned), 'pywechatpay' (community v3, different API), 'wechatpy' (WeChat platform SDK, not Pay-specific), 'pywe-pay' (unmaintained). Only 'wechatpayv3' targets the v3 API and is actively maintained.","severity":"gotcha","affected_versions":"all"},{"fix":"Use a real domain with valid TLS in production. For local development use ngrok or similar tunneling.","message":"NOTIFY_URL must be a publicly accessible HTTPS URL. WeChat Pay servers will POST payment results to this endpoint. HTTP (non-TLS) is rejected. localhost, 127.0.0.1, and private IPs will silently fail — your callback will never fire.","severity":"gotcha","affected_versions":"all"},{"fix":"Always convert to fen before passing to the SDK: amount_fen = int(amount_cny * 100).","message":"All monetary amounts are in fen (分), the smallest CNY unit. 1 CNY = 100 fen. Passing amounts in CNY (e.g. 10.00 instead of 1000) will result in payments 100x smaller than intended with no error thrown.","severity":"gotcha","affected_versions":"all"},{"fix":"Use the Chinese docs at pay.weixin.qq.com as the source of truth. For error codes, refer to the zh-CN error code reference directly.","message":"Official WeChat Pay documentation is Chinese-first (zh-CN). The English translation at pay.weixin.qq.com lags behind and is incomplete — some v3 endpoints and error codes are only documented in Chinese.","severity":"gotcha","affected_versions":"all"},{"fix":"Always set cert_dir to a persistent directory path in production. In serverless (Lambda, Cloud Run), use a shared volume or pre-cache certificates at build time.","message":"cert_dir set to None disables local certificate caching. On every WeChatPay instantiation, the SDK will re-download platform certificates from WeChat servers. In production or serverless environments with frequent cold starts, this causes latency and risks hitting WeChat's certificate download rate limits.","severity":"gotcha","affected_versions":"all"},{"fix":"Ensure all required environment variables (WECHAT_MCHID, WECHAT_SERIAL_NO, WECHAT_APIV3_KEY, WECHAT_PRIVATE_KEY) are correctly set before running the application. Alternatively, pass these credentials directly to the WeChatPay constructor during initialization.","message":"The SDK requires merchant credentials (MCHID, serial_no, apiv3_key, private_key) to be provided at runtime, typically via environment variables or a configuration file. Failing to set these will result in a KeyError or similar configuration error, preventing the SDK from initializing.","severity":"breaking","affected_versions":"all"},{"fix":"Ensure that all necessary WeChat Pay credentials (MCHID, API key, certificate and private key paths) are correctly configured and accessible to your application, either through environment variables (as expected by the script) or other secure configuration methods.","message":"Essential credentials such as MCHID (Merchant ID), API key, and certificate path are required for the SDK to initialize. These are typically loaded from environment variables (e.g., WECHAT_MCHID) or a configuration file. Failure to provide them will result in a KeyError or similar configuration error upon application startup.","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T07:54:50.612Z","next_check":"2026-05-28T00:00:00.000Z","problems":[],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.34,"mem_mb":7,"disk_size":"37.6M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.31,"mem_mb":5.7,"disk_size":"37.6M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.35,"mem_mb":7,"disk_size":"40.6M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.25,"mem_mb":7,"disk_size":"38M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.21,"mem_mb":5.7,"disk_size":"38M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.24,"mem_mb":7,"disk_size":"41M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.63,"mem_mb":7.8,"disk_size":"40.1M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.57,"mem_mb":6,"disk_size":"40.1M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.63,"mem_mb":7.8,"disk_size":"43.8M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.52,"mem_mb":7.8,"disk_size":"40M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.49,"mem_mb":6,"disk_size":"40M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.52,"mem_mb":7.8,"disk_size":"44M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.43,"mem_mb":7.6,"disk_size":"31.7M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.41,"mem_mb":5.7,"disk_size":"31.7M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.44,"mem_mb":7.6,"disk_size":"35.3M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":7.6,"disk_size":"32M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.45,"mem_mb":5.7,"disk_size":"32M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":7.6,"disk_size":"36M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.42,"mem_mb":7.3,"disk_size":"31.4M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.37,"mem_mb":5.3,"disk_size":"31.4M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.41,"mem_mb":7.3,"disk_size":"34.7M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.45,"mem_mb":7.3,"disk_size":"32M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.39,"mem_mb":5.3,"disk_size":"32M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.43,"mem_mb":7.3,"disk_size":"35M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.3,"mem_mb":6.9,"disk_size":"37.7M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.27,"mem_mb":5.7,"disk_size":"37.7M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.3,"mem_mb":6.9,"disk_size":"40.6M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.28,"mem_mb":6.9,"disk_size":"38M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.28,"mem_mb":5.7,"disk_size":"38M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"async","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.28,"mem_mb":6.9,"disk_size":"41M"}]},"quickstart_checks":{"last_tested":"2026-05-12","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}