关于 wecom
通过 curl 和 jq 调用 WeCom 自建应用服务端 API 的技能,面向需要管理企业通讯录、消息、文档、日程和会议的工作流。它提供令牌处理与操作示例,并要求发送消息或创建日程、会议前取得明确确认。
主要功能
- 01获取并缓存访问令牌
- 02读取部门与成员资料
- 03发送应用消息和群聊消息
- 04创建及读取 WeDoc 文档
- 05管理日程与会议
适用场景
- 01查找成员并解析 userid
- 02向指定同事发送通知
- 03创建项目文档或智能表格
- 04安排日程或会议
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ acedatacloud/ skills --skill wecom安装后在 Claude Code 中输入/wecom确认已加载。
详细介绍
我们使用 curl + jq 作为自建应用来调用企业微信服务端 API
(https://qyapi.weixin.qq.com)。
设置: 请参阅企业微信身份验证,了解如何创建自建应用、 收集 CorpID / Secret / AgentId,并授予通讯录 / 文档 / 日历 / 会议 权限。此技能会从环境中读取
WECOM_CORP_ID、WECOM_CORP_SECRET和WECOM_AGENT_ID;在 AceDataCloud 上,这些变量由企业微信连接器自动注入。
企业微信采用两步令牌流程(形式与微信公众号 API 相同):
- 使用
CorpID + Secret换取access_token(有效期 7200s)。 - 在其他每次调用中,将此
access_token作为查询字符串参数传入。
绝不要记录或回显 $WECOM_CORP_SECRET——请将其视为密码。
响应以 JSON 格式返回,且 HTTP 状态码为 200;errcode == 0 表示成功。若 errcode 非零,
请将原始 errmsg 原样显示给用户(参见设置文档中的错误表)。
操作示例
步骤 0 — 获取 access_token(首先执行,并缓存结果)
以下每个操作示例都假定 $AT 中保存了此步骤获取的有效令牌。
# Fail loudly if credentials are missing/blank. WECOM_AGENT_ID must be a plain
# integer because message/meeting recipes pass it to jq via --argjson (numeric JSON).
: "${WECOM_CORP_ID:?WECOM_CORP_ID not set}" "${WECOM_CORP_SECRET:?WECOM_CORP_SECRET not set}"
case "${WECOM_AGENT_ID:?WECOM_AGENT_ID not set}" in *[!0-9]*|"") echo "WECOM_AGENT_ID must be an integer" >&2; exit 1;; esac
# Cache to $TMPDIR so subsequent calls in the same session reuse it (WeCom
# rate-limits gettoken). Refresh 5 minutes early to avoid edge-of-window failures.
TOKEN_CACHE="${TMPDIR:-/tmp}/wecom-token-${WECOM_CORP_ID}-${WECOM_AGENT_ID}.json"
NOW=$(date +%s)
if [ -f "$TOKEN_CACHE" ] && [ "$(jq -r '.exp_at // 0' "$TOKEN_CACHE")" -gt "$((NOW + 300))" ]; then
AT=$(jq -r '.access_token' "$TOKEN_CACHE")
else
RESP=$(curl -sS "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${WECOM_CORP_ID}&corpsecret=${WECOM_CORP_SECRET}")
AT=$(echo "$RESP" | jq -r 'if .errcode == 0 then .access_token else empty end')
if [ -z "$AT" ]; then
echo "Failed to fetch access_token: $RESP" >&2
exit 1
fi
EXPIRES=$(echo "$RESP" | jq -r '.expires_in // 7200')
echo "$RESP" | jq --argjson now "$NOW" --argjson ttl "$EXPIRES" \
'{access_token, exp_at: ($now + $ttl)}' > "$TOKEN_CACHE"
chmod 600 "$TOKEN_CACHE"
fi
使用一个小型辅助函数可以让操作示例更简洁——附加令牌并执行 GET 请求,若 errcode 非零则报错:
wc_get() { curl -sS "https://qyapi.weixin.qq.com/cgi-bin/$1&access_token=${AT}" \
| jq 'if .errcode == 0 then . else error("WeCom \(.errcode): \(.errmsg)") end'; }
wc_post() { curl -sS -X POST "https://qyapi.weixin.qq.com/cgi-bin/$1?access_token=${AT}" \
-H 'Content-Type: application/json' -d "$2" \
| jq 'if .errcode == 0 then . else error("WeCom \(.errcode): \(.errmsg)") end'; }
通讯录 Contacts(读取)
读取真实姓名 / 手机号需要应用具有通讯录读取权限;否则姓名 会被屏蔽。应用可见范围外的成员会返回
errcode 60011/81013。
列出部门树(根部门 id 为 1):
wc_get "department/list?id=1" | jq '[.department[] | {id, name, parentid}]'
首选枚举方式——user/list_id(游标)。 这是列出成员的稳健方式:
仅持有自建应用自身 Secret 时也能使用。user/simplelist / user/list 在应用的可见范围内仍然
可用,但企业微信一直在收紧这些接口的限制(2022‑08‑15 的变更禁止
新添加的通讯录同步 IP 调用这些接口),因此应优先使用 user/list_id,只有在需要一次性获取姓名时才回退到 simplelist。
wc_post "user/list_id" '{"cursor":"","limit":10000}' \
| jq '{next_cursor, userids: [.dept_user[] | .userid] | unique}'
获取某位成员的完整资料——可用于将姓名 → userid,以便发送消息:
wc_get "user/get?userid=USERID" \
| jq '{userid, name, department, position, mobile, email, status}'
一次调用列出某部门的成员(便捷方式;需要拥有该部门的通讯录查看权限——
若返回 60011,请改用上文的 user/list_id + user/get):
wc_get "user/simplelist?department_id=1&fetch_child=1" \
| jq '[.userlist[] | {userid, name, department}]'
按姓名搜索——稳健方式(枚举 id,然后读取每份资料并筛选):
for uid in $(wc_post "user/list_id" '{"cursor":"","limit":10000}' | jq -r '.dept_user[].userid' | sort -u); do
wc_get "user/get?userid=${uid}" | jq -c '{userid, name}'
done | jq -s --arg q "张三" '[.[] | select(.name | contains($q))]'
快捷方式:当应用可以使用
simplelist时:wc_get "user/simplelist?department_id=1&fetch_child=1" | jq --arg q "张三" '[.userlist[] | select(.name | contains($q)) | {userid, name}]'。
应用消息 App messages(发送)— 受控操作
message/send 会从你的应用向成员推送通知。必须提供 agentid,其值来自
$WECOM_AGENT_ID。touser 是以 | 连接的 userid 列表(使用 @all 表示范围内的所有人);
toparty / totag 用于指定部门 / 标签。
发送消息会将内容推送给真实用户。运行
message/send/appchat/send之前,务必向用户展示确切的收件人和内容,并取得明确确认,即使指令说 “直接发送”也不例外。
向一位或多位成员发送文本消息:
wc_post "message/send" "$(jq -nc --arg to "USERID1|USERID2" --argjson agent "${WECOM_AGENT_ID}" \
--arg content "构建已通过,请查看。" \
'{touser:$to, msgtype:"text", agentid:$agent, text:{content:$content}, safe:0}')" \
| jq '{msgid, invaliduser}'
发送 Markdown 卡片(格式更丰富,仅限成员):
wc_post "message/send" "$(jq -nc --arg to "@all" --argjson agent "${WECOM_AGENT_ID}" \
--arg md "**发布通知**\n>版本:v1.2.0\n>状态:<font color=\"info\">成功</font>" \
'{touser:$to, msgtype:"markdown", agentid:$agent, markdown:{content:$md}}')" \
| jq '{msgid}'
发送可点击的文本卡片:
wc_post "message/send" "$(jq -nc --arg to "USERID1" --argjson agent "${WECOM_AGENT_ID}" \
'{touser:$to, msgtype:"textcard", agentid:$agent,
textcard:{title:"周报已生成", description:"点击查看本周汇总", url:"https://example.com/report", btntxt:"详情"}}')" \
| jq '{msgid}'
应用群聊 App group chat
创建一个归应用所有的群聊,然后向其中推送消息。chatid 是你选择的自定义 id(之后可重复使用)。
# Create (owner + members are userids). Omit chatid to let WeCom assign one.
wc_post "appchat/create" '{"name":"项目组","owner":"USERID1","userlist":["USERID1","USERID2","USERID3"],"chatid":"proj_alpha"}' \
| jq '{chatid}'
# Send into it (same GATED confirmation rule as app messages).
wc_post "appchat/send" '{"chatid":"proj_alpha","msgtype":"text","text":{"content":"今晚 8 点线上同步。"}}' \
| jq '{errcode, errmsg}'
# Inspect a group the app created.
wc_get "appchat/get?chatid=proj_alpha" | jq '.chat_info | {name, owner, userlist}'
企业微信文档 WeDoc(文档与智能表格)
需要应用拥有 文档 (WeDoc) 权限。doc_type:3 = 文档,4 = 表格,
10 = 智能表格。
创建文档并获取编辑 URL:
wc_post "wedoc/create_doc" "$(jq -nc --arg name "项目周报 2026-07" \
'{doc_type:3, doc_name:$name}')" \
| jq '{docid, url}'
获取现有文档的可分享链接:
wc_post "wedoc/doc_share" '{"docid":"DOCID"}' | jq '{share_url: .share_url}'
读取文档的结构化内容。WeCom 返回一个 document 对象(以 document_id 而非
doc_id 为键),其正文是由类型化区块组成的树,不是 Markdown — 请先检查实际结构,再依赖内部字段名称:
wc_post "wedoc/document/get" '{"docid":"DOCID"}' \
| jq '{document_id: .document.document_id, top_level_keys: (.document | keys)}'
智能表格的子表、字段和记录使用
wedoc/smartsheet/*端点 (get_sheet、get_fields、get_records、add_records等)— 使用相同的wc_post模式,以docid+sheet_id为键。用户要求读取或写入智能表格的行时,请使用这些端点。
日程 Schedule(日程)
需要应用拥有 日历/日程 权限。时间是 epoch 秒;使用 GNU date 转换:
START=$(date -d "2026-07-10 15:00" +%s); END=$(date -d "2026-07-10 16:00" +%s)
创建日程(组织者和参会者均为 userid):
wc_post "oa/schedule/add" "$(jq -nc --arg org "USERID1" --argjson s "$START" --argjson e "$END" \
'{schedule:{organizer:$org, start_time:$s, end_time:$e, summary:"项目评审",
description:"评审 v1.2 需求", location:"会议室 A",
attendees:[{userid:"USERID2"},{userid:"USERID3"}],
reminders:{is_remind:1, remind_before_event_secs:900}}}')" \
| jq '{schedule_id}'
按 ID 读取日程并取消日程:
wc_post "oa/schedule/get" '{"schedule_id_list":["SCHEDULE_ID"]}' \
| jq '[.schedule_list[] | {schedule_id, summary, start_time, end_time, organizer}]'
wc_post "oa/schedule/del" '{"schedule_id":"SCHEDULE_ID"}' | jq '{errcode, errmsg}'
若要列出某位成员即将参加的日程,需要其日历 ID(
cal_id)以及oa/schedule/get_by_calendar— 请先通过oa/calendar/*端点创建或查询日历。
会议 Meeting(会议)
需要应用拥有 会议 权限。meeting_start 是 epoch 秒,meeting_duration 是秒。
创建已安排的会议:
wc_post "meeting/create" "$(jq -nc --arg admin "USERID1" --argjson start "$(date -d '2026-07-11 10:00' +%s)" \
'{admin_userid:$admin, title:"周例会", meeting_start:$start, meeting_duration:3600,
description:"同步本周进展", invitees:{userid:["USERID2","USERID3"]}}')" \
| jq '{meetingid}'
列出某位成员的会议、读取详情并取消会议(get_user_meetingid 是一个带游标请求体的 POST,
与 WeCom 的其他 get_user_*_id 列表端点相同):
wc_post "meeting/get_user_meetingid" '{"userid":"USERID1","cursor":"","limit":100}' \
| jq '{meetingid_list, next_cursor}'
wc_post "meeting/get_info" '{"meetingid":"MEETINGID"}' \
| jq '.meeting_info | {title, meeting_start, meeting_duration, state}'
wc_post "meeting/cancel" '{"meetingid":"MEETINGID"}' | jq '{errcode, errmsg}'
安全规则
- 绝不输出
$WECOM_CORP_SECRET。 它等同于完整的应用访问权限。 - 执行任何对外操作前都要确认 —
message/send、appchat/send、oa/schedule/add和meeting/create都会通知真实同事。请展示确切的收件人/参会者和内容,获得明确批准,然后再调用。绝不能从含糊措辞中推断用户同意。 - 消息、日程和会议操作使用的是 userids,而非显示名称 — 请先使用联系人查询方式将姓名解析为 userid;如果姓名有歧义,还要确认具体对象。
- 遇到
errcode 48002(API 禁止)或60011/301002(无权限)时,表示应用缺少某项权限,或目标位于其可见范围之外 — 请告知用户需要授予哪项能力,不要盲目重试。
此处不支持的功能
- 读取收到的聊天记录(会话内容存档 / msgaudit)— 这是单独收费的功能,需要专用 Secret、RSA 密钥 和原生 WeCom Finance SDK,无法在此沙盒中运行。此技能可以发送消息,但无法读取成员的私人对话。
- 通用待办 CRUD — WeCom 开放 API 未向自建应用提供此功能;请改用 日程创建有时间限制的提醒。