Loading...
Loading...
Read your WeCom (企业微信 / WeCom / Work Weixin) contacts, send app & group messages, create and read WeDoc docs/smart sheets, and manage schedules (日程) and meetings (会议) via the WeCom server-side API as a self-built app. Use when the user mentions 企业微信, WeCom, 通讯录成员/部门, 应用消息, 群机器人/应用群聊, 企业微信文档/智能表格, 企业微信日程 or 会议, or a qyapi.weixin.qq.com call.
npx skill4agent add acedatacloud/skills wecomhttps://qyapi.weixin.qq.comcurl + jqSetup: see WeCom authentication for how to create the self-built app, collect CorpID / Secret / AgentId, and grant it the contacts / docs / calendar / meeting permissions. The skill reads,WECOM_CORP_IDandWECOM_CORP_SECRETfrom the environment; on AceDataCloud they are injected automatically by the 企业微信 connector.WECOM_AGENT_ID
CorpID + Secretaccess_tokenaccess_token$WECOM_CORP_SECRETerrcode == 0errcodeerrmsg$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"
fierrcodewc_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'; }Reading real names / mobiles requires the app to have 通讯录读取 privilege; otherwise names come back masked. Members outside the app's 可见范围 return/errcode 60011.81013
1wc_get "department/list?id=1" | jq '[.department[] | {id, name, parentid}]'user/list_iduser/simplelistuser/listuser/list_idsimplelistwc_post "user/list_id" '{"cursor":"","limit":10000}' \
| jq '{next_cursor, userids: [.dept_user[] | .userid] | unique}'wc_get "user/get?userid=USERID" \
| jq '{userid, name, department, position, mobile, email, status}'60011user/list_iduser/getwc_get "user/simplelist?department_id=1&fetch_child=1" \
| jq '[.userlist[] | {userid, name, department}]'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))]'Shortcut whenis available to the app:simplelist.wc_get "user/simplelist?department_id=1&fetch_child=1" | jq --arg q "张三" '[.userlist[] | select(.name | contains($q)) | {userid, name}]'
message/sendagentid$WECOM_AGENT_IDtouser|@alltopartytotagSending fans out to real people. Always show the exact recipients + content and get explicit user confirmation before running/message/send, even if the instruction says "just send it".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}'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}'chatid# 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}'doc_type3410wc_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}'documentdocument_iddoc_idwc_post "wedoc/document/get" '{"docid":"DOCID"}' \
| jq '{document_id: .document.document_id, top_level_keys: (.document | keys)}'Smart-sheet (智能表格) sub-tables, fields and records use theendpoints (wedoc/smartsheet/*,get_sheet,get_fields,get_records, …) — sameadd_recordspattern, keyed bywc_post+docid. Reach for them when the user asks to read/write rows of a 智能表格.sheet_id
dateSTART=$(date -d "2026-07-10 15:00" +%s); END=$(date -d "2026-07-10 16:00" +%s)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}'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}'To list a member's upcoming schedules you need their calendar id () andcal_id— create/query calendars via theoa/schedule/get_by_calendarendpoints first.oa/calendar/*
meeting_startmeeting_durationwc_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_meetingidget_user_*_idwc_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_SECRETmessage/sendappchat/sendoa/schedule/addmeeting/createerrcode 4800260011301002