Install
openclaw skills install zoom-admin-apiZoom Admin API integration with managed OAuth. Manage users, meetings, webinars, recordings, and account settings with admin-level access. Use this skill when users want to list users, create or manage meetings, view recordings, check user/account settings, or administer a Zoom workspace. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Security: The MATON_API_KEY authenticates with Maton.ai but grants NO access to Zoom by itself. Zoom access requires explicit OAuth authorization by the user through Maton's connect flow. Access is strictly scoped to the Zoom account the user has authorized. All API requests are proxied through Maton's gateway, which handles OAuth token management. Only connect the intended Zoom account and revoke the connection when no longer needed. Requires network access and valid Maton API key.
openclaw skills install zoom-admin-apiAccess the Zoom API with managed OAuth authentication and admin-level scopes. Manage users, meetings, webinars, recordings, and account settings.
# List users in your Zoom account
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoom-admin/v2/users?status=active&page_size=30')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://api.maton.ai/zoom-admin/{native-api-path}
Replace {native-api-path} with the actual Zoom API endpoint path (e.g., v2/users, v2/meetings/123). The gateway proxies requests to api.zoom.us and automatically injects your OAuth token.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Zoom Admin OAuth connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=zoom-admin&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'zoom-admin'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "zoom-admin",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple Zoom Admin connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoom-admin/v2/users?status=active')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
GET /zoom-admin/v2/users?status=active&page_size=30
Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
status | string | active | active, inactive, or pending |
page_size | integer | 30 | Max: 2000 |
next_page_token | string | Pagination token (15-min expiry) | |
role_id | string | Filter by role ID |
Response:
{
"page_size": 30,
"total_records": 1,
"next_page_token": "",
"users": [
{
"id": "a-IOECePRV265Gy_wotUdQ",
"first_name": "Richard",
"last_name": "Song",
"display_name": "Richard Song",
"email": "user@example.com",
"type": 1,
"pmi": 6862513852,
"timezone": "America/Los_Angeles",
"verified": 1,
"status": "active",
"created_at": "2025-03-21T21:52:50Z",
"last_login_time": "2026-05-01T01:01:08Z",
"role_id": "0"
}
]
}
User type values: 1 = Basic, 2 = Licensed, 4 = Unassigned, 99 = None.
GET /zoom-admin/v2/users/{userId}
Use me for the authenticated user, or a user ID / email address.
Response:
{
"id": "a-IOECePRV265Gy_wotUdQ",
"first_name": "Richard",
"last_name": "Song",
"display_name": "Richard Song",
"email": "user@example.com",
"type": 1,
"role_name": "Owner",
"pmi": 6862513852,
"use_pmi": false,
"personal_meeting_url": "https://us05web.zoom.us/j/6862513852?pwd=...",
"timezone": "America/Los_Angeles",
"status": "active",
"account_id": "ciah2jjMRgedBSqxO8bOjA",
"role_id": "0",
"login_types": [100, 1],
"created_at": "2025-03-21T21:52:50Z",
"last_login_time": "2026-05-01T01:01:08Z"
}
GET /zoom-admin/v2/users/{userId}/settings
Query Parameters:
| Param | Type | Description |
|---|---|---|
option | string | meeting_authentication, recording_authentication, or meeting_security |
Returns detailed settings grouped into sections: schedule_meeting, in_meeting, email_notification, recording, telephony, feature, whiteboard, audio_conferencing, etc.
GET /zoom-admin/v2/users/{userId}/meetings?type=scheduled&page_size=30
Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
type | string | live | scheduled, live, upcoming, upcoming_meetings, previous_meetings |
page_size | integer | 30 | Max: 300 |
next_page_token | string | Pagination token (15-min expiry) |
Response:
{
"page_size": 30,
"total_records": 11,
"next_page_token": "B4Tr0tLbJKQMnChspbYH7UUvt7g0UeDQNh2",
"meetings": [
{
"uuid": "SukzvlkXQO2rNcNPKUGCpw==",
"id": 89560318205,
"host_id": "a-IOECePRV265Gy_wotUdQ",
"topic": "Team Standup",
"type": 2,
"start_time": "2026-03-30T18:00:00Z",
"duration": 30,
"timezone": "America/Los_Angeles",
"created_at": "2026-03-29T18:01:40Z",
"join_url": "https://us05web.zoom.us/j/89560318205?pwd=..."
}
]
}
Meeting type values: 1 = Instant, 2 = Scheduled, 3 = Recurring (no fixed time), 4 = PMI, 8 = Recurring (fixed time).
GET /zoom-admin/v2/meetings/{meetingId}
Query Parameters:
| Param | Type | Description |
|---|---|---|
occurrence_id | string | For recurring meetings |
show_previous_occurrences | boolean | Show previous occurrences |
Returns full meeting details including settings, recurrence, occurrences, join_url, start_url, password, etc.
POST /zoom-admin/v2/users/{userId}/meetings
Content-Type: application/json
{
"topic": "Weekly Team Sync",
"type": 2,
"start_time": "2026-05-02T10:00:00Z",
"duration": 30,
"timezone": "America/Los_Angeles",
"agenda": "Discuss project updates",
"settings": {
"host_video": true,
"participant_video": true,
"join_before_host": false,
"mute_upon_entry": true,
"waiting_room": false,
"auto_recording": "none",
"audio": "voip"
}
}
Key Request Fields:
| Field | Type | Description |
|---|---|---|
topic | string | Meeting topic |
type | integer | 1 = Instant, 2 = Scheduled, 3 = Recurring (no fixed), 8 = Recurring (fixed) |
start_time | string | ISO 8601 datetime (required for type 2 and 8) |
duration | integer | Duration in minutes |
timezone | string | e.g., America/New_York |
password | string | Up to 10 characters |
agenda | string | Max 2000 characters |
recurrence | object | Required for type 8 |
settings | object | Meeting settings |
Returns the created meeting object (same as Get Meeting).
PATCH /zoom-admin/v2/meetings/{meetingId}
Content-Type: application/json
{
"topic": "Updated Meeting Topic",
"duration": 45
}
All fields are optional. Returns 204 No Content on success.
DELETE /zoom-admin/v2/meetings/{meetingId}
Query Parameters:
| Param | Type | Description |
|---|---|---|
occurrence_id | string | Delete specific occurrence of recurring meeting |
schedule_for_reminder | boolean | Notify host about cancellation |
cancel_meeting_reminder | string | Notify registrants (true/false) |
Returns 204 No Content on success.
GET /zoom-admin/v2/past_meetings/{meetingId}
Use the meeting ID or UUID. If the UUID starts with / or contains //, it must be double-URL-encoded.
Response:
{
"uuid": "/LAYgqiEQ8CW4NlhkyOvVA==",
"id": 89560318205,
"host_id": "a-IOECePRV265Gy_wotUdQ",
"type": 2,
"topic": "Team Standup",
"user_name": "Richard Song",
"user_email": "user@example.com",
"start_time": "2026-03-30T18:02:25Z",
"end_time": "2026-03-30T18:09:50Z",
"duration": 8,
"total_minutes": 22,
"participants_count": 3,
"source": "Calendly for Zoom"
}
GET /zoom-admin/v2/past_meetings/{meetingId}/instances
Response:
{
"meetings": [
{
"uuid": "/LAYgqiEQ8CW4NlhkyOvVA==",
"start_time": "2026-03-30T18:02:25Z"
}
]
}
Webinar endpoints require a Webinar plan on the Zoom account.
GET /zoom-admin/v2/users/{userId}/webinars?page_size=30
Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
type | string | scheduled | scheduled or upcoming |
page_size | integer | 30 | Max: 300 |
next_page_token | string | Pagination token |
Response:
{
"page_size": 30,
"total_records": 0,
"next_page_token": "",
"webinars": [
{
"uuid": "...",
"id": 12345678901,
"host_id": "...",
"topic": "Product Launch Webinar",
"type": 5,
"start_time": "2026-05-15T14:00:00Z",
"duration": 60,
"timezone": "America/Los_Angeles",
"join_url": "https://us05web.zoom.us/j/..."
}
]
}
Webinar type values: 5 = Webinar, 6 = Recurring (no fixed time), 9 = Recurring (fixed time).
GET /zoom-admin/v2/webinars/{webinarId}
Returns full webinar details including settings, recurrence, and registration info.
GET /zoom-admin/v2/users/{userId}/recordings?from=2026-04-01&to=2026-04-30&page_size=30
Query Parameters:
| Param | Type | Description |
|---|---|---|
from | string | Start date (yyyy-mm-dd). Max range: 1 month. Max past: 6 months |
to | string | End date (yyyy-mm-dd) |
page_size | integer | Max: 300 |
next_page_token | string | Pagination token |
trash | boolean | List trashed recordings |
Response:
{
"from": "2026-04-01",
"to": "2026-04-30",
"total_records": 0,
"next_page_token": "",
"meetings": [
{
"uuid": "...",
"id": 12345678901,
"host_id": "...",
"topic": "Meeting Topic",
"start_time": "2026-04-15T10:00:00Z",
"duration": 45,
"total_size": 52428800,
"recording_count": 2,
"recording_files": [
{
"id": "...",
"file_type": "MP4",
"file_extension": "MP4",
"file_size": 41943040,
"play_url": "https://...",
"download_url": "https://...",
"recording_type": "shared_screen_with_speaker_view",
"status": "completed"
}
]
}
]
}
GET /zoom-admin/v2/meetings/{meetingId}/recordings
Use the meeting ID or UUID. If the UUID starts with / or contains //, it must be double-URL-encoded.
Query Parameters:
| Param | Type | Description |
|---|---|---|
include_fields | string | download_access_token for JWT download token |
ttl | integer | Token TTL in seconds (0–604800, default: 172800) |
Returns the meeting's recording files with download URLs.
GET /zoom-admin/v2/accounts/{accountId}/settings
Use me for the connected account. Requires a paid Zoom plan.
Query Parameters:
| Param | Type | Description |
|---|---|---|
option | string | meeting_authentication, recording_authentication, security, meeting_security |
Returns account-level settings grouped into sections: security, schedule_meeting, in_meeting, recording, telephony, feature, chat, etc.
Zoom uses token-based pagination via next_page_token. Tokens expire after 15 minutes.
# First page
GET /zoom-admin/v2/users?page_size=30
# Next page
GET /zoom-admin/v2/users?page_size=30&next_page_token={next_page_token}
Response includes pagination fields:
{
"page_size": 30,
"total_records": 100,
"next_page_token": "B4Tr0tLbJKQMnChspbYH7UUvt7g0UeDQNh2"
}
When next_page_token is empty, there are no more pages. Do not reuse expired tokens — start from the first page if a token expires.
const response = await fetch(
'https://api.maton.ai/zoom-admin/v2/users?status=active&page_size=10',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
response = requests.get(
'https://api.maton.ai/zoom-admin/v2/users',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
params={'status': 'active', 'page_size': 10}
)
data = response.json()
zoom-admin app uses admin-level OAuth scopes that grant access to all users in the Zoom account/ or containing // must be double-URL-encoded when used in path parameters/v2/accounts/me/settings) requires a paid Zoom plancurl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Missing Zoom Admin connection or invalid request |
| 401 | Invalid or missing Maton API key |
| 404 | Resource not found (meeting, user, recording) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Zoom API |
| Category | Pro Plan | Business+ |
|---|---|---|
| LIGHT | 4/sec, 6,000/day | 30/sec |
| MEDIUM | 2/sec, 2,000/day | 20/sec |
| HEAVY | 1/sec, 1,000/day | 10/sec |
Rate-limited responses include a Retry-After header.
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
zoom-admin. For example:https://api.maton.ai/zoom-admin/v2/usershttps://api.maton.ai/v2/users