WeChat Official Account
Each school connects its own WeChat Service Account. Subscription Accounts do not have the messaging APIs we need — make sure you have a Service Account before starting.
Connecting
Open Integrations → WeChat → Connect. You'll need four values from your Official Account Platform (mp.weixin.qq.com):
| Field | Where on mp.weixin.qq.com |
|---|---|
| AppID | Settings → Official Account Settings → Account Details |
| AppSecret | Settings → Basic Configuration (regenerate if lost) |
| Server Token | Settings → Basic Configuration → Server Configuration (you choose this string) |
| EncodingAESKey (optional) | Same page — required only for "Safe Mode" message encryption |
After save, Kinderpedia calls GET /cgi-bin/token?grant_type=client_credential&appid=…&secret=… to validate. If the access token mints, the row goes status = connected.
Webhook configuration
Your webhook URL is /api/integrations/wechat/webhook/{school_id} on your Kinderpedia domain (replace {school_id} with your school's Kinderpedia ID, shown on the integration tile). Paste it into Server Configuration → URL.
WeChat's webhook signature is sha1(sort([token, timestamp, nonce])). The handler validates this on every inbound. Misconfigured callbacks always get back 200 success (or the echoed echostr on the initial GET probe) — WeChat retries aggressively on non-200s and we'd rather drop than throttle the connection.
48-hour customer-service window
WeChat's customer-service window is 48 hours (vs WhatsApp's 24h). Inside the window: free-form text/media/voice. Outside: template messages only.
The window check runs server-side on every reply attempt. Same fallback as WhatsApp — outside the window, the UI flips to the template picker.
OpenID, not phone number
WeChat doesn't expose phone numbers to Official Accounts. Each follower has a per-OA OpenID (a UUID-like string, scoped to your OA only — the same person has a different OpenID on a different OA).
To send to a parent, we need their OpenID. There are two ways it gets captured:
Per-lead QR codes (the main flow)
PublicForm.vue renders a WeChat QR code after submit when the school has WeChat connected. The QR carries a scene string l<leadId> or l<leadId>p<parentId> (≤64 chars). When the parent scans it:
- Their WeChat app prompts them to follow your OA (if not already).
- The OA receives a
subscribeevent (new follow) orSCANevent (already a follower) with the scene string. - The webhook handler decodes the scene string, looks up the lead + parent, and binds the WeChat OpenID to that parent's profile.
From then on, that parent is reachable on WeChat. The QR ticket is short-lived (24h) — generated on-demand via /cgi-bin/qrcode/create.
Manual entry
Admins can paste a known OpenID directly on the parent record (the legacy path). Rare, but supported.
Templates
Templates are authored at Function → Template Messages on the OA platform. Approval is manual and OA-platform-specific — usually 1-2 business days. Approved templates sync into Kinderpedia via Sync templates on the Integrations row.
WeChat variables are named, not positional:
{{first.DATA}} <- header
{{name.DATA}} <- placeholder
{{date.DATA}} <- placeholder
{{remark.DATA}} <- footerThe picker renders one labelled input per name. first and remark are special-cased as header/footer styling.
Media
WeChat needs an extra step compared to WhatsApp: media must be uploaded to WeChat first via /cgi-bin/media/upload to get a media_id, then referenced when sending. Kinderpedia handles this transparently in WeChatClient.
Size caps:
- Image: 2 MB
- Voice: 10 MB, ≤60s
- Video: 10 MB, must be MP4
Inbound media uses temporary URLs scoped to the OA's access token (anyone else gets a 401). We proxy inbound media server-side so the browser can render without exposing the OA token.
Bulk send
Bulk Actions → Bulk WeChat on the roster works the same as bulk WhatsApp: select up to 100 leads, pick a template, dry-run, confirm. Recipients without an openid on their parent record are auto-skipped.
Why no Subscription Account support?
Subscription Accounts sit under a "Subscriptions" folder in WeChat's UI and lack the messaging API surface we need (template messages, customer-service messages, media upload). If you have one, upgrade to a Service Account before connecting.
Common errors
| Symptom | Likely cause |
|---|---|
| "Invalid IP" on save | WeChat IP whitelist not configured (Server Configuration → IP Whitelist). Add your Kinderpedia server IPs. |
| Webhook events not arriving | Server Token mismatch, or webhook URL not "Enabled" on OA platform. |
| QR doesn't trigger follow | Scene-string ticket expired (24h limit). Re-fetch on next page load. |
Template send returns 40001 | Access token stale — auto-refresh on next request, retry. |
Send to a parent returns 48001 | The parent has unfollowed the OA. OpenID stays in our DB but messaging dies. |