wecom について
curl と jq で WeCom の自社作成アプリ向けサーバー API を呼び出すスキルです。連絡先、メッセージ、ドキュメント、日程、会議の操作例とトークン処理をまとめ、通知や日程・会議の作成前に明示的な確認を求めます。
主な機能
- 01アクセストークンの取得とキャッシュ
- 02部署とメンバープロフィールの参照
- 03アプリメッセージとグループチャットの送信
- 04WeDoc ドキュメントの作成と参照
- 05日程と会議の管理
活用シーン
- 01メンバーを検索して userid を特定
- 02指定した同僚への通知
- 03プロジェクト文書やスマートシートの作成
- 04日程や会議の設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ acedatacloud/ skills --skill wecomインストール後、Claude Code で/wecomを入力して読み込まれたか確認します。
詳細
WeCom サーバー側 API を
(https://qyapi.weixin.qq.com)、curl + jq を使って**自作アプリ(自建应用)**として操作します。
セットアップ: 自作アプリの作成方法、CorpID / Secret / AgentIdの取得方法、および連絡先/ドキュメント/カレンダー/会議の権限付与については、WeCom 認証を参照してください。このスキルは環境変数から
WECOM_CORP_ID、WECOM_CORP_SECRET、WECOM_AGENT_IDを読み込みます。AceDataCloud では、企业微信 コネクターによって自動的に設定されます。
WeCom のトークン取得は2段階です(WeChat MP API と同じ形式です)。
CorpID + Secretをaccess_tokenと交換します(有効期間は7200秒)。- ほかのすべての呼び出しで、その
access_tokenをクエリ文字列パラメーターとして渡します。
$WECOM_CORP_SECRET をログに記録したり、表示したりしないでください。パスワードと同様に扱ってください。
レスポンスは HTTP 200 で返される JSON です。errcode == 0 は成功を意味します。errcode が0以外の場合は、元の 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 が0以外の場合はエラーにします。
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'; }
通讯录 連絡先(読み取り)
実名/携帯電話番号の読み取りには、アプリに通讯录读取権限が必要です。権限がない場合、名前はマスキングされて返されます。アプリの可視範囲外のメンバーは
errcode 60011/81013を返します。
部署ツリーを一覧表示します(ルート部署の ID は 1 です)。
wc_get "department/list?id=1" | jq '[.department[] | {id, name, parentid}]'
推奨する列挙方法 — user/list_id(カーソル)。 メンバーの一覧表示には、これが最も確実な方法です。独自の Secret のみを持つ自作アプリでも動作します。user/simplelist/user/list もアプリの可視範囲内では引き続き動作しますが、WeCom はこれらの制限を強化しています(2022‑08‑15 の変更により、新たに追加された通讯录同期 IP からの呼び出しがブロックされます)。そのため、まず user/list_id を使い、名前を一度に取得する必要がある場合に限って simplelist にフォールバックしてください。
wc_post "user/list_id" '{"cursor":"","limit":10000}' \
| jq '{next_cursor, userids: [.dept_user[] | .userid] | unique}'
メンバー1人の詳細プロフィールを取得します。これはメッセージ送信時に名前 → useridを解決する方法です。
wc_get "user/get?userid=USERID" \
| jq '{userid, name, department, position, mobile, email, status}'
部署のメンバーを1回の呼び出しで一覧表示します(便利な方法です。その部署の通讯录を参照できる必要があります。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}]'。
应用消息 アプリメッセージ(送信)— 要確認
message/send は、アプリからメンバーに通知を送信します。agentid は必須で、$WECOM_AGENT_ID から取得します。touser は userid を | で連結したリストです(対象範囲内の全員に送信する場合は @all を使用します)。toparty/totag は部署/タグを指定します。
実在する人々にメッセージが送信されます。指示が「そのまま送って」とある場合でも、
message/send/appchat/sendを実行する前に、送信先と内容を正確に提示し、必ずユーザーから明示的な確認を得てください。
1人以上のメンバーにテキストメッセージを送信します。
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}'
应用群聊 アプリグループチャット
アプリが所有するグループを作成し、そのグループにメッセージを送信します。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 オブジェクト(doc_id ではなく document_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、…)を使用します。docid+sheet_idをキーとする同じwc_postパターンです。ユーザーから智能表格の行の読み書きを依頼された場合に使用してください。
日程(Schedule)
アプリの カレンダー/日程 権限が必要です。時刻は エポック秒 です。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 はエポック秒、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は、いずれも実際の同僚に通知を送ります。正確な宛先/参加者と内容を提示し、明示的な承認を得てから呼び出しを実行してください。曖昧な表現から同意を推測してはいけません。 - メッセージ/日程/会議の操作対象は表示名ではなく userid です。まず連絡先のレシピを使って名前を userid に解決し、名前が曖昧な場合は対象者を確認してください。
errcode 48002(API の利用禁止)または60011/301002(権限なし)が返された場合、アプリに権限がないか、対象がそのアプリの可視範囲外です。むやみに再試行せず、ユーザーに付与すべき機能を伝えてください。
ここではサポートされない機能
- 受信したチャット履歴の読み取り(会話内容存档/msgaudit)— 専用の Secret、RSA キー、ネイティブの WeCom Finance SDK が必要な、別料金の機能です。このサンドボックスでは実行できません。このスキルはメッセージを送信できますが、メンバーの非公開の会話を読み取ることはできません。
- 汎用的な todo(待办)の CRUD — WeCom のオープン API は自作アプリ向けにこれを提供していません。時間指定のリマインダーには、代わりに 日程(日程) を使用してください。