Permissions and Constraints
This Skill uses scripts/zoom-s2s.py to call the Zoom Server-to-Server OAuth REST API; it does not implement a "generic REST proxy".
- Declared tools:
Bash(python3:*)(executescripts/zoom-s2s.py)、Bash(ls:*)/Bash(cat:*)(view script output and cache),Read(read credential files and documentation). - Network access: initiate HTTPS requests to
https://zoom.us/oauth/tokenandhttps://api.zoom.us/v2/*; transmission headers includeAuthorization: Bearer <token>。 - File writes: cache the access token in
~/.zoom-s2s-token.json(automaticallychmod 600)。 - Credential reading: read from
.envin the repository rootZOOM_ACCOUNT_ID/ZOOM_CLIENT_ID/ZOOM_CLIENT_SECRET/ZOOM_USER_ID。 - Allowed Actions (whitelist)—constructing arbitrary Zoom REST requests or calling unlisted endpoints is prohibited:
- Meetings:
list_meetings/get_meeting/create_meeting/delete_meeting - Users:
get_user/list_users - Recordings:
recordings
- Meetings:
- Privilege escalation protection: the script does not export
api_callto upper-layer callers; it is prohibited to bypass and call Zoom endpoints outside the whitelist (such asDELETE /users/{id}、PATCH /accounts/{id}and other high-risk endpoints) by modifying scripts, injecting parameters, concatenating URLs, or other means. - Strong human confirmation:
create_meetinganddelete_meetingmust obtain explicit user confirmation before execution;delete_meetingcommands also require appending the--yesparameter.
Credential configuration
Configure in the .env file (chmod 600 only; do not commit to any Git repository):
ZOOM_ACCOUNT_ID=你的AccountID
ZOOM_CLIENT_ID=你的ClientID
ZOOM_CLIENT_SECRET=你的ClientSecret
ZOOM_USER_ID=你的用户邮箱或user_id
⚠️ For the complete security specification, see the next section
## 凭证安全。
Token acquisition method: Server-to-Server OAuth, machine-to-machine, no user-interactive authorization required.
Credential security
.env The ZOOM_CLIENT_SECRET inmustcomply with:
- Add to
.gitignore: this repository.gitignorealready includes.env; also ensure that IDEs, backup tools, and file synchronization services (iCloud / Dropbox / OneDrive / Nutstore) do not automatically upload this file. - Restrict file permissions:
chmod 600 .env;scripts/zoom-s2s.pyThe cached~/.zoom-s2s-token.jsonis equally sensitive (automaticallychmod 600),Do notcopy to the clipboard, chat windows, terminal screenshots, error tickets, AI conversation context, or third-party logging services. - Do not reuse in shared environments: reusing the same credentials in CI runners, public jump hosts, container images, or shared development machines ≈ making the credentials public.
Account ID + Client ID + Client SecretThe triplet can be exchanged for an access token valid for 1 hour. - Least privilege: enable Scopes on demand according to the
## 最小权限配置建议table; do not select corresponding permissions for Actions that are not needed;delete_meetingwrite permissions outside ofmeeting:write:update、user:write:*、account:write:*) should not be enabled by default. - Independent App: create a separate Zoom Server-to-Server App for this Skill;do notreuse the credentials of other business Apps; once leaked, simply rotate that App's credentials without affecting other businesses.
- Credential leak emergency response: delete the App in Zoom Marketplace → recreate and rotate
ACCOUNT_ID/CLIENT_ID/CLIENT_SECRET/USER_IDthe four items →rm -f ~/.zoom-s2s-token.jsonforce re-authentication next time → review the leak path.
Core scripts
scripts/zoom-s2s.py — Pure Python, no external dependencies, compatible with Python 3.7+.
cd ~/.agents/skills/zoom-meeting-admin/scripts
# 获取帮助
python3 zoom-s2s.py help
# 列出即将到来的会议
python3 zoom-s2s.py list_meetings <user> <page_size> upcoming
# 获取单个会议详情
python3 zoom-s2s.py get_meeting <meeting_id>
# 创建会议 (start_time: YYYY-MM-DDTHH:MM:SS)
python3 zoom-s2s.py create_meeting "<主题>" "<start_time>" <时长分钟> [时区] [密码]
python3 zoom-s2s.py create_meeting "煎饼果子讨论会" "2026-05-05T10:00:00" 60 Asia/Shanghai
# 删除会议
python3 zoom-s2s.py delete_meeting <meeting_id>
# 获取云录像
python3 zoom-s2s.py recordings <user> <page_size>
# 获取用户信息
python3 zoom-s2s.py get_user [user]
# 列出账户下所有用户
python3 zoom-s2s.py list_users [page_size]
Token caching
The script automatically caches the Token to ~/.zoom-s2s-token.json(valid for about 50 minutes), so repeated calls do not require re-authentication each time.
Quick reference for common operations
| Operation | Command |
|---|---|
| List the 5 most recent meetings | list_meetings <user> 5 upcoming |
| List the 10 most recent past meetings | list_meetings <user> 10 past |
| Create a meeting for tomorrow at 10 AM | create_meeting "主题" "YYYY-MM-DDT10:00:00" 60 Asia/Shanghai |
| Get meeting details | get_meeting <id> |
| Delete a meeting | delete_meeting <id> --yes |
| Get cloud recordings | recordings <user> 10 |
Recommendations for least-privilege configuration
Enable scopes as needed based on actual usage scenarios; do not authorize features you do not need:
| Feature | Required Scope | Recommendation |
|---|---|---|
| List meetings | meeting:read:list_meetings |
✅ Core |
| View meeting details | meeting:read:meeting |
✅ Core |
| Create meetings | meeting:write:create |
Enable as needed |
| Delete meetings | meeting:write:delete |
⚠️ Enable with caution |
| Read cloud recordings | cloud_recording:read:list_user_recordings |
⚠️ Enable with caution |
| List account users | user:read:list_users |
⚠️ Enable with caution |
It is recommended to create a separate Zoom Server-to-Server App for this Skill, and not reuse the credentials of an existing App.
Agent invocation specification
- Before creating a meeting: Confirm the topic, time, and duration with the user before executing.
- Before deleting a meeting: You must clearly show the meeting information to the user and obtain confirmation; the command must include the
--yesparameter. - Calling beyond scope is prohibited: Only the Actions listed in the documentation are allowed; do not construct arbitrary Zoom REST API requests.
Create recurring meetings
Create type=8(recurring meeting) recurrence parameter description:
| recurrence.type | Description | Available fields | Available |
|---|---|---|---|
| 1 | Daily recurrence | end_date_time or count |
✅ |
| 2 | Weekly recurrence | weekly_days(string), end_date_time or count |
✅ |
| 3 | Monthly recurrence | monthly_day or monthly_weeks + weekly_days |
✅ |
⚠️ Key pitfall to avoid:weekly_days must be a string, not an array!
| Incorrect usage | Correct usage |
|---|---|
"weekly_days": [6] |
"weekly_days": "6" |
"weekly_days": ["6"] |
"weekly_days": "6"(single day) |
"weekly_days": "6,0"(multiple days, Saturday + Sunday) |
weekly_days values: 1=Monday ~ 7=Sunday
Example: Create a recurring meeting for May 23-24 (Saturday and Sunday):
payload = {
"topic": "CSM公开课",
"type": 8,
"start_time": "2026-05-23T08:00:00",
"duration": 540,
"timezone": "Asia/Shanghai",
"recurrence": {
"type": 2,
"repeat_interval": 1,
"weekly_days": "6,0", # 周六+周日,字符串!
"end_date_time": "2026-05-24T00:00:00Z"
},
"settings": {
"host_video": True,
"participant_video": True,
"join_before_host": False,
"mute_upon_entry": False
}
}
Multi-day example(Monday + Wednesday + Friday):
"weekly_days": "1,3,5"
Pitfall log
- Incorrect scope (4711): Some APIs (such as
get_user) require the corresponding scope to be enabled in the App, and likewiselist_meetingsrequires enabling themeeting:read:list_meetingspermission in the App - Token validity period: Server-to-Server Token is valid for 1 hour; the script automatically refreshes and caches it
- User ID: You can use an email, or use
list_usersto look up the user_id weekly_daysmust be a string: The Zoom API requiresweekly_daysis"6"such a string, not[6]an array; passing an array will cause error 300