🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Zoom

by @byungkyu

Zoom API integration with managed OAuth. Manage meetings, webinars, recordings, and user profiles. Use this skill when users want to schedule meetings, manag...

TERMINAL
clawhub install zoom-api

πŸ“– About This Skill


name: zoom description: | Zoom API integration with managed OAuth. Manage meetings, webinars, recordings, and user profiles. Use this skill when users want to schedule meetings, manage webinars, get meeting details, list recordings, or retrieve user information. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway). Requires network access and valid Maton API key. metadata: author: maton version: "1.0" clawdbot: emoji: "πŸ“Ή" homepage: "https://maton.ai" requires: env: - MATON_API_KEY

Zoom

Access the Zoom API with managed OAuth authentication. Manage meetings, webinars, cloud recordings, and user profiles.

Quick Start

# Get current user profile
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoom/v2/users/me')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Base URL

https://gateway.maton.ai/zoom/v2/

All endpoints documented below are accessed under this base URL. The gateway proxies requests to api.zoom.us and automatically injects your OAuth token. Only the endpoints listed in the API Reference section below are supported.

Security & Permissions

  • The Maton API key acts as a credential β€” treat it as a secret and do not expose it in client-side code or public repositories
  • The OAuth connection grants scoped access to meetings, webinars, recordings, and user profiles on the connected Zoom account
  • Read operations (GET) retrieve data from the connected Zoom account
  • Write operations (POST, PATCH, DELETE) create, modify, or delete meetings, webinars, and recordings β€” confirm with the user before destructive actions
  • Access is limited to the Zoom account linked through the OAuth connection
  • Authentication

    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"
    

    Getting Your API Key

    1. Sign in or create an account at maton.ai 2. Go to maton.ai/settings 3. Copy your API key

    Connection Management

    Manage your Zoom OAuth connections at https://ctrl.maton.ai.

    List Connections

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://ctrl.maton.ai/connections?app=zoom&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
    

    Create Connection

    python <<'EOF'
    import urllib.request, os, json
    data = json.dumps({'app': 'zoom'}).encode()
    req = urllib.request.Request('https://ctrl.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
    

    Get Connection

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://ctrl.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": "2026-04-10T00:35:13.470841Z",
        "last_updated_time": "2026-04-10T00:37:08.985792Z",
        "url": "https://connect.maton.ai/?session_token=...",
        "app": "zoom",
        "metadata": {}
      }
    }
    

    Open the returned url in a browser to complete OAuth authorization.

    Delete Connection

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://ctrl.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
    

    Specifying Connection

    If you have multiple Zoom connections, specify which one to use with the Maton-Connection header:

    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://gateway.maton.ai/zoom/v2/users/me')
    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 omitted, the gateway uses the default (oldest) active connection.

    API Reference

    Users

    #### Get Current User

    GET /zoom/v2/users/me
    

    Response:

    {
      "id": "APv5EPHiSvitxgPAw0DbaQ",
      "first_name": "John",
      "last_name": "Doe",
      "display_name": "John Doe",
      "email": "john@example.com",
      "type": 1,
      "role_name": "Owner",
      "pmi": 5017823017,
      "timezone": "America/Los_Angeles",
      "status": "active",
      "created_at": "2023-06-01T19:33:22Z",
      "last_login_time": "2026-04-10T00:35:21Z"
    }
    

    User Types:

  • 1 - Basic
  • 2 - Licensed
  • 3 - On-prem
  • Meetings

    #### List User's Meetings

    GET /zoom/v2/users/me/meetings
    GET /zoom/v2/users/{userId}/meetings
    

    Query Parameters:

    | Parameter | Type | Description | |-----------|------|-------------| | type | string | scheduled, live, upcoming, upcoming_meetings, previous_meetings | | page_size | integer | Results per page (max 300, default 30) | | next_page_token | string | Pagination token | | from | string | Start date (YYYY-MM-DD) | | to | string | End date (YYYY-MM-DD) |

    Response:

    {
      "page_size": 30,
      "total_records": 1,
      "next_page_token": "",
      "meetings": [
        {
          "uuid": "RPrVctdSRxaVmIUTHVUlGQ==",
          "id": 82931897821,
          "host_id": "APv5EPHiSvitxgPAw0DbaQ",
          "topic": "Team Standup",
          "type": 2,
          "start_time": "2026-04-10T00:39:32Z",
          "duration": 30,
          "timezone": "America/Los_Angeles",
          "join_url": "https://us05web.zoom.us/j/82931897821?pwd=..."
        }
      ]
    }
    

    #### Get Upcoming Meetings

    GET /zoom/v2/users/me/upcoming_meetings
    

    Returns meetings scheduled for the future.

    #### Create Meeting

    POST /zoom/v2/users/me/meetings
    POST /zoom/v2/users/{userId}/meetings
    Content-Type: application/json

    { "topic": "Weekly Team Sync", "type": 2, "start_time": "2026-04-15T14:00:00Z", "duration": 60, "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": true } }

    Meeting Types:

  • 1 - Instant meeting
  • 2 - Scheduled meeting
  • 3 - Recurring meeting with no fixed time
  • 8 - Recurring meeting with fixed time
  • Example - Create Meeting:

    python <<'EOF'
    import urllib.request, os, json
    data = json.dumps({
        "topic": "Project Review",
        "type": 2,
        "start_time": "2026-04-15T14:00:00Z",
        "duration": 60,
        "timezone": "America/Los_Angeles",
        "settings": {
            "host_video": True,
            "participant_video": True,
            "waiting_room": True
        }
    }).encode()
    req = urllib.request.Request('https://gateway.maton.ai/zoom/v2/users/me/meetings', data=data, method='POST')
    req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
    req.add_header('Content-Type', 'application/json')
    resp = json.load(urllib.request.urlopen(req))
    print(f"Meeting created! Join URL: {resp['join_url']}")
    EOF
    

    Response:

    {
      "uuid": "RPrVctdSRxaVmIUTHVUlGQ==",
      "id": 82931897821,
      "host_id": "APv5EPHiSvitxgPAw0DbaQ",
      "host_email": "john@example.com",
      "topic": "Project Review",
      "type": 2,
      "status": "waiting",
      "start_time": "2026-04-15T14:00:00Z",
      "duration": 60,
      "timezone": "America/Los_Angeles",
      "start_url": "https://us05web.zoom.us/s/82931897821?zak=...",
      "join_url": "https://us05web.zoom.us/j/82931897821?pwd=...",
      "password": "AX2hsd"
    }
    

    #### Get Meeting

    GET /zoom/v2/meetings/{meetingId}
    

    Path Parameters:

  • meetingId - Meeting ID or UUID (double-encode UUID if it contains / or //)
  • #### Update Meeting

    PATCH /zoom/v2/meetings/{meetingId}
    Content-Type: application/json

    { "topic": "Updated Meeting Title", "duration": 45, "settings": { "waiting_room": false } }

    Example - Update Meeting:

    python <<'EOF'
    import urllib.request, os, json
    data = json.dumps({
        "topic": "Updated Weekly Sync",
        "duration": 45
    }).encode()
    req = urllib.request.Request('https://gateway.maton.ai/zoom/v2/meetings/82931897821', data=data, method='PATCH')
    req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
    req.add_header('Content-Type', 'application/json')
    urllib.request.urlopen(req)
    print("Meeting updated!")
    EOF
    

    #### Delete Meeting

    DELETE /zoom/v2/meetings/{meetingId}
    

    Query Parameters:

  • schedule_for_reminder - Send cancellation email to registrants (boolean)
  • cancel_meeting_reminder - Send cancellation email notification (boolean)
  • Recordings

    #### List User's Cloud Recordings

    GET /zoom/v2/users/me/recordings
    GET /zoom/v2/users/{userId}/recordings
    

    Query Parameters:

    | Parameter | Type | Description | |-----------|------|-------------| | from | string | Start date (YYYY-MM-DD) | | to | string | End date (YYYY-MM-DD) | | page_size | integer | Results per page (max 300, default 30) | | next_page_token | string | Pagination token | | trash | boolean | List trashed recordings | | trash_type | string | meeting_recordings or recording_file |

    Response:

    {
      "from": "2026-04-01",
      "to": "2026-04-10",
      "page_count": 1,
      "page_size": 30,
      "total_records": 2,
      "next_page_token": "",
      "meetings": [
        {
          "uuid": "...",
          "id": 123456789,
          "topic": "Team Meeting",
          "start_time": "2026-04-05T14:00:00Z",
          "duration": 45,
          "total_size": 52428800,
          "recording_count": 2,
          "recording_files": [
            {
              "id": "...",
              "meeting_id": "...",
              "recording_start": "2026-04-05T14:00:00Z",
              "recording_end": "2026-04-05T14:45:00Z",
              "file_type": "MP4",
              "file_size": 50000000,
              "play_url": "https://...",
              "download_url": "https://...",
              "status": "completed",
              "recording_type": "shared_screen_with_speaker_view"
            }
          ]
        }
      ]
    }
    

    #### Get Meeting Recordings

    GET /zoom/v2/meetings/{meetingId}/recordings
    

    #### Delete Meeting Recordings

    DELETE /zoom/v2/meetings/{meetingId}/recordings
    

    Webinars

    Note: Webinar endpoints require a Webinar add-on plan.

    #### List User's Webinars

    GET /zoom/v2/users/me/webinars
    GET /zoom/v2/users/{userId}/webinars
    

    #### Create Webinar

    POST /zoom/v2/users/{userId}/webinars
    Content-Type: application/json

    { "topic": "Product Launch Webinar", "type": 5, "start_time": "2026-05-01T10:00:00Z", "duration": 90, "timezone": "America/Los_Angeles" }

    Webinar Types:

  • 5 - Scheduled webinar
  • 6 - Recurring webinar with no fixed time
  • 9 - Recurring webinar with fixed time
  • #### Get Webinar

    GET /zoom/v2/webinars/{webinarId}
    

    #### Update Webinar

    PATCH /zoom/v2/webinars/{webinarId}
    Content-Type: application/json

    { "topic": "Updated Webinar Title" }

    #### Delete Webinar

    DELETE /zoom/v2/webinars/{webinarId}
    

    Meeting Registrants

    #### List Meeting Registrants

    GET /zoom/v2/meetings/{meetingId}/registrants
    

    #### Add Meeting Registrant

    POST /zoom/v2/meetings/{meetingId}/registrants
    Content-Type: application/json

    { "email": "attendee@example.com", "first_name": "Jane", "last_name": "Smith" }

    Meeting Participants

    #### List Past Meeting Participants

    GET /zoom/v2/past_meetings/{meetingUUID}/participants
    

    Note: Use double-encoded UUID if it contains / or //.

    Pagination

    Zoom uses cursor-based pagination with next_page_token:

    GET /zoom/v2/users/me/meetings?page_size=50
    

    Response includes pagination info:

    {
      "page_size": 50,
      "total_records": 150,
      "next_page_token": "Tva2CuIdTgsv8wAnhyAdU3m06Y2HuLQtlh3",
      "meetings": [...]
    }
    

    Get next page:

    GET /zoom/v2/users/me/meetings?page_size=50&next_page_token=Tva2CuIdTgsv8wAnhyAdU3m06Y2HuLQtlh3
    

    When next_page_token is empty, there are no more pages.

    Code Examples

    JavaScript

    const response = await fetch(
      'https://gateway.maton.ai/zoom/v2/users/me/meetings',
      {
        headers: {
          'Authorization': Bearer ${process.env.MATON_API_KEY}
        }
      }
    );
    const data = await response.json();
    console.log(data.meetings);
    

    Python

    import os
    import requests

    response = requests.get( 'https://gateway.maton.ai/zoom/v2/users/me/meetings', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) meetings = response.json()['meetings']

    Create Meeting and Get Join URL

    import os
    import requests

    headers = { 'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}', 'Content-Type': 'application/json' }

    Create a meeting

    meeting = requests.post( 'https://gateway.maton.ai/zoom/v2/users/me/meetings', headers=headers, json={ 'topic': 'Quick Sync', 'type': 2, 'duration': 30, 'settings': { 'waiting_room': True, 'join_before_host': False } } ).json()

    print(f"Meeting ID: {meeting['id']}") print(f"Join URL: {meeting['join_url']}") print(f"Password: {meeting['password']}")

    Notes

  • Meeting IDs are numeric; UUIDs are base64-encoded strings
  • When using UUID in path, double-encode if it contains / or //
  • User me can be used to reference the authenticated user
  • Some endpoints require admin scopes and may not be available with standard OAuth
  • Webinar endpoints require a Webinar add-on subscription
  • Recordings are only available for cloud recording-enabled accounts
  • Rate limits vary by plan and endpoint category
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing
  • IMPORTANT: When piping curl output to jq, environment variables may not expand correctly in some shells
  • Error Handling

    | Status | Meaning | |--------|---------| | 400 | Bad request or missing required parameter | | 401 | Invalid or missing Maton API key | | 403 | Forbidden - insufficient permissions | | 404 | Resource not found | | 429 | Rate limited | | 4xx/5xx | Passthrough error from Zoom API |

    Common Error Codes

    | Code | Message | |------|---------| | 3001 | Meeting does not exist | | 4711 | Invalid access token, missing required scopes | | 200 (in body) | Feature not available (e.g., Webinar plan missing) |

    Resources

  • Zoom API Documentation
  • Zoom REST API Reference
  • Zoom Meeting API
  • Zoom OAuth Scopes
  • Maton Community
  • Maton Support
  • πŸ’‘ Examples

    # Get current user profile
    python <<'EOF'
    import urllib.request, os, json
    req = urllib.request.Request('https://gateway.maton.ai/zoom/v2/users/me')
    req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
    print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
    EOF
    

    πŸ“‹ Tips & Best Practices

  • Meeting IDs are numeric; UUIDs are base64-encoded strings
  • When using UUID in path, double-encode if it contains / or //
  • User me can be used to reference the authenticated user
  • Some endpoints require admin scopes and may not be available with standard OAuth
  • Webinar endpoints require a Webinar add-on subscription
  • Recordings are only available for cloud recording-enabled accounts
  • Rate limits vary by plan and endpoint category
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing
  • IMPORTANT: When piping curl output to jq, environment variables may not expand correctly in some shells