WeCom (企业微信)
WeCom self-built app messaging with SHA1 sort + AES-256-CBC callback envelope. The standard channel for enterprise China deployments.
🟡 Outbound-ready, inbound supported, built around the self-built-application path (most common deployment shape). Routes through the same legacy SHA1 + AES envelope WeChat OA uses, so the shared
wxcrypthelper covers both providers.
What you get
- Outbound text messaging via
POST /cgi-bin/message/sendto one or moretouserrecipients (or@allfor the whole agent). - Inbound callback events at
/webhooks/wecom. WeCom signs every callback withmsg_signature(SHA1 over[token, timestamp, nonce, encrypt]sorted lexicographically). Body is AES-256-CBC-encrypted under the 43-charEncodingAESKey. - Per-app
access_tokencached for 2 hours with auto-refresh. - Text only this PR. Image / file upload (via "upload media" endpoint) is a future enhancement.
- 2048-char text limit (4096 for markdown, not yet wired).
Setup
1. Create a self-built application
- Sign in to WeCom admin console
- Go to "Applications & Mini Programs" → "Self-built" → "Create"
- Fill in the application metadata; on the detail page note the AgentID and Secret
- The corp-level CorpID lives under "My Corp" → "Corp Info"
2. Enable callback (optional, for inbound)
- Open the application detail page → "API Receive" → "Set API Receive"
- Set the URL to
https://<your-host>/webhooks/wecom - Fill in a Token (any opaque string) and click "Random" for the EncodingAESKey (must be 43 base64 chars)
- Click "Save". WeCom hits the URL with a GET handshake; Minara decrypts the echostr and echoes it back, finalising the binding.
3. Configure Minara
minara auth messaging add
# pick `wecom`; paste corp id, agent id, secret, default touser,
# callback token, EncodingAESKey.Or set env vars directly:
WECOM_CORP_ID=ww<...>
WECOM_AGENT_ID=1000002
WECOM_SECRET=<application secret>
WECOM_DEFAULT_TOUSER=user1|user2 # or @all
WECOM_CALLBACK_TOKEN=<callback token>
WECOM_CALLBACK_AES_KEY=<43-char EncodingAESKey>WECOM_DEFAULT_TOUSER accepts the WeCom convention: pipe-separated
user ids, or @all for the whole agent's audience.
4. Test
minara auth messaging test wecomEach touser in the default list receives "✅ Minara gateway test ping".
Inbound webhook
WeCom carries the message signature in the URL query, not in headers.
Minara validates msg_signature against
SHA1(sort([token, timestamp, nonce, encrypt]).join("")) (Tencent's
legacy IM scheme) before decrypting the body.
GET URL-verification handshake: WeCom sends
?msg_signature=…×tamp=…&nonce=…&echostr=<base64>.
Minara checks the signature, decrypts echostr with the AES key
(IV = first 16 bytes of the key), and echoes the plaintext. A wrong
token or AES key returns 401 / 500.
Inner XML payload after decryption:
<xml>
<ToUserName>...</ToUserName>
<FromUserName>...</FromUserName>
<CreateTime>...</CreateTime>
<MsgType>text</MsgType>
<Content>...</Content>
<MsgId>...</MsgId>
</xml>Only MsgType=text messages are emitted to the agent today. Image,
voice, and event types are silently dropped.
Limits & caveats
access_tokenand callback token are different. The first is WeCom's per-app OAuth, the second is your shared signing secret for callbacks. Keep them straight in your env file.@allis a frequent pitfall. It blasts a notification to every user in the agent's scope; pinWECOM_DEFAULT_TOUSERto specific user ids for production.- AES key length is mandatory. WeCom rejects keys that do not decode to exactly 32 bytes (43 base64 chars before padding).
Troubleshooting
"Get access token failed (errcode 40013)"
WECOM_CORP_IDdoes not match the corp the secret belongs to.
"Inbound webhook returns 401"
- The
msg_signaturedoes not match. Most common cause: a typo inWECOM_CALLBACK_TOKEN. Less common: your reverse proxy strips the signature query.
"signCallbackParams length mismatch"
WECOM_CALLBACK_AES_KEYis not 43 characters. Re-generate from the WeCom console.
Reference
- Env vars:
WECOM_* - Outbound:
apps/agent/src/messaging/wecom.ts - Inbound spec:
apps/agent/src/messaging/inbound/specs/wecom.ts - Shared crypto helper:
apps/agent/src/messaging/_shared/wxcrypt.ts - WeCom platform: developer.work.weixin.qq.com