Generated banner for Build Zoom Rest API App
Generated logo for Build Zoom Rest API App

Build Zoom Rest API App

OpenAIOfficialCreated by ZoomDistributed by OpenAI

  • Skill
  • Tool integration
  • Software development
  • MIT
  • Medium risk

From the author

Use when calling REST APIs.
— the description by Zoom

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured approach to interacting with the Zoom REST API. It offers guidance on selecting appropriate authentication flows, managing resources such as meetings and users, and implementing robust API interaction patterns like pagination and rate-limit handling. It includes reference documentation for various Zoom product areas, including account management and AI Companion services, to assist developers in building API-integrated applications.

What it does

  • Provides endpoint inventories for Zoom API product areas.
  • Outlines authentication requirements for user-level, account-level, and server-to-server workflows.
  • Defines patterns for implementing API wrappers with pagination and retry logic.
  • Offers guidance on webhook processing, including signature verification.
  • Assists in troubleshooting common API issues like scope mismatches and rate limits.

When to use it

  • When developing applications that need to programmatically manage Zoom meetings, users, or recordings.
  • When integrating Zoom account settings or dashboard metrics into custom software.
  • When setting up event-driven workflows using Zoom webhooks.
  • When debugging authentication or scope-related errors during Zoom API integration.

Advantages

  • Centralizes access to official Zoom API endpoint documentation.
  • Standardizes the implementation of API interaction patterns.
  • Clarifies the selection of correct authentication scopes for different API operations.
  • Provides a clear methodology for handling API rate limits and resource management.

Usage examples

“How do I list meeting participants using the Zoom API?”
The agent provides the correct endpoint path from the dashboard references and explains the necessary OAuth scopes and pagination requirements.
“What authentication should I use for an account-level Zoom integration?”
The agent guides you through the account-level OAuth flow requirements as defined in the authentication documentation.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/openai/build-zoom-rest-api-app/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip build-zoom-rest-api-app.zip -d .agents/skills

Documentation by Zoom

Build Zoom REST API App

Use this skill when the task needs deterministic Zoom API calls or resource management from application code.

Workflow

  1. Define the resource and actor: user, meeting, webinar, recording, docs, chat, phone, account, or admin-level workflow.

  2. Select the endpoint and required scopes from the reference files before coding.

  3. Confirm auth fit: user-level OAuth for user-owned resources, account-level OAuth for admin workflows, and only use server-to-server OAuth where the target API documents support for it.

  4. Implement narrow API wrappers with explicit pagination, retry, idempotency, and rate-limit handling.

  5. Treat webhook processing as a separate event-ingestion path with signature verification and replay protection.

  6. Debug by checking token audience, missing scopes, resource ownership, account settings, API enablement, and rate-limit headers.

References

Files

references/rate-limits.md

REST API - Rate Limits

Understanding and handling Zoom API rate limits for reliable integrations.

Overview

Zoom APIs enforce rate limits to ensure fair usage. Limits vary by endpoint category, account type, and are shared across all apps on an account.

Rate Limit Categories

Main REST API
CategoryFreeProBusiness+
Light4/sec, 6,000/day30/sec80/sec
Medium2/sec, 2,000/day20/sec60/sec
Heavy1/sec, 1,000/day10/sec*40/sec*
Resource-Intensive10/min, 30,000/day10/min*20/min*

* Daily limits (shared):

  • Pro: 30,000/day (Heavy + Resource-Intensive combined)

  • Business+: 60,000/day (Heavy + Resource-Intensive combined)

Zoom Phone API
CategoryProBusiness+
Light20/sec40/sec
Medium10/sec20/sec
Heavy5/sec, 15,000/day*10/sec, 30,000/day*
Resource-Intensive5/min, 15,000/day*10/min, 30,000/day*
Zoom Contact Center API
CategoryProBusiness+
Light20/sec40/sec
Medium10/sec20/sec
Heavy5/sec, 15,000/day*10/sec, 30,000/day*

* Daily limit shared with Resource-Intensive APIs

Endpoint Category Examples

LightMediumHeavy
Add Meeting RegistrantCreate MeetingGet Daily Usage Report
Get A MeetingGet Past Meeting ParticipantsList Devices
Get Meeting RecordingsList All Recordings
Update A MeetingList Meetings
Delete Meeting RecordingsList Webinars

Special Per-User Limits

Meeting/Webinar Operations
OperationLimitReset
Meeting/Webinar Create/Update100/day per user00:00 UTC
Registrant Addition3/day per registrant00:00 UTC
Registrant Status Updates10/day per registrant00:00 UTC

Note: The 100/day limit applies to all Meeting/Webinar IDs hosted by a specific user.

Lock-Key Limits (Concurrent Operations)

Zoom enforces lock-key limits for user resource operations:

ScenarioBehavior
Multiple DELETE on same userIdOnly 1 concurrent DELETE allowed
POST to /v2/usersBlocks GET/PATCH/PUT/DELETE until complete

Error Response:

{
  "code": 429,
  "message": "Too many concurrent requests. A request to disassociate this user has already been made."
}

Response Headers

Every API response includes rate limit headers:

HeaderDescription
X-RateLimit-CategoryLight, Medium, Heavy, or Resource-intensive
X-RateLimit-TypeQPS (per-second) or Daily-limit
X-RateLimit-LimitMaximum requests in current window
X-RateLimit-RemainingRequests remaining in current window
On Per-Second/Minute Limit Hit
HeaderDescription
X-RateLimit-ResetUnix timestamp when limit resets
On Daily Limit Hit
HeaderDescription
Retry-AfterISO8601 datetime when you can retry
Example Headers

Normal response:

X-RateLimit-Category: Medium
X-RateLimit-Type: QPS
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 55

Rate limited (per-second):

HTTP/1.1 429 Too Many Requests
X-RateLimit-Category: Light
X-RateLimit-Type: QPS
X-RateLimit-Limit: 80
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312800

Rate limited (daily):

HTTP/1.1 429 Too Many Requests
X-RateLimit-Category: Heavy
X-RateLimit-Type: Daily-limit
X-RateLimit-Limit: 60000
X-RateLimit-Remaining: 0
Retry-After: 2025-01-20T00:00:00Z

Error Responses

Per-Second Limit
{
  "code": 429,
  "message": "You have reached the maximum per-second rate limit for this API. Try again later."
}
Daily Limit
{
  "code": 429,
  "message": "You have reached the maximum daily rate limit for this API. Refer to the response header for details on when you can make another request."
}

Handling Rate Limits

Basic Retry with Backoff
async function callZoomAPI(url, options, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      // Check for Retry-After (daily limit)
      const retryAfter = response.headers.get('Retry-After');
      if (retryAfter) {
        const retryDate = new Date(retryAfter);
        const waitMs = retryDate - Date.now();
        console.log(`Daily limit hit. Retry after: ${retryAfter}`);
        await sleep(waitMs);
        continue;
      }

      // Per-second limit - use exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      const jitter = delay * 0.2 * Math.random();  // 20% jitter
      console.log(`Rate limited. Retrying in ${delay + jitter}ms`);
      await sleep(delay + jitter);
      continue;
    }

    return response;
  }

  throw new Error('Max retries exceeded');
}
Monitor Rate Limit Headers
async function callAPIWithMonitoring(url, options) {
  const response = await fetch(url, options);

  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
  const limit = parseInt(response.headers.get('X-RateLimit-Limit'));
  const category = response.headers.get('X-RateLimit-Category');
  const type = response.headers.get('X-RateLimit-Type');

  console.log(`[${category}/${type}] ${remaining}/${limit} remaining`);

  // Proactive throttling
  if (remaining < limit * 0.1) {  // Less than 10% remaining
    console.warn('Approaching rate limit - throttling requests');
    await sleep(1000);  // Slow down
  }

  return response;
}
Request Queue Pattern

For high-volume applications:

class RateLimitedQueue {
  constructor(maxConcurrent = 10, minDelayMs = 100) {
    this.queue = [];
    this.running = 0;
    this.maxConcurrent = maxConcurrent;
    this.minDelayMs = minDelayMs;
  }

  async add(requestFn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject });
      this.process();
    });
  }

  async process() {
    if (this.running >= this.maxConcurrent || this.queue.length === 0) {
      return;
    }

    const { requestFn, resolve, reject } = this.queue.shift();
    this.running++;

    try {
      const result = await requestFn();
      resolve(result);
    } catch (error) {
      reject(error);
    } finally {
      this.running--;
      await sleep(this.minDelayMs);
      this.process();
    }
  }
}

// Usage
const queue = new RateLimitedQueue(10, 100);  // 10 concurrent, 100ms min delay

const results = await Promise.all([
  queue.add(() => fetch('/api/users/1')),
  queue.add(() => fetch('/api/users/2')),
  queue.add(() => fetch('/api/users/3')),
  // ... more requests
]);

Best Practices

1. Cache GET Responses
const cache = new Map();
const CACHE_TTL = 60000;  // 1 minute

async function cachedGet(url, options) {
  const cached = cache.get(url);
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const response = await fetch(url, options);
  const data = await response.json();

  cache.set(url, { data, timestamp: Date.now() });
  return data;
}
2. Use Webhooks Instead of Polling

Instead of polling for changes:

// DON'T: Poll every minute
setInterval(async () => {
  const meetings = await getMeetings();  // Uses API quota
}, 60000);

Use webhooks:

// DO: Receive webhook events
app.post('/webhook', (req, res) => {
  const event = req.body;
  if (event.event === 'meeting.started') {
    handleMeetingStarted(event.payload);
  }
  res.status(200).send();
});
3. Batch Operations

Use list endpoints with pagination instead of individual fetches:

// DON'T: Fetch users one by one
for (const userId of userIds) {
  const user = await getUser(userId);  // N API calls
}

// DO: Fetch users in batches
const users = await listUsers({ page_size: 300 });  // 1 API call
4. Use QSS for Quality Data

For Quality of Service data, use QSS (push-based) instead of polling:

  • QSS streams telemetry via webhooks/WebSocket

  • Pushes data 4-6 times per minute

  • Reduces need for Reports API polling

5. Distribute Requests Over Time
// DON'T: Burst all requests at once
await Promise.all(users.map(u => updateUser(u)));  // May hit rate limit

// DO: Distribute over time
for (const user of users) {
  await updateUser(user);
  await sleep(100);  // 100ms between requests
}

Account Type Notes

Rate Limits Are Per-Account
  • Limits are shared by ALL users and ALL apps on the account

  • Upgrading account increases limits for everyone

  • Not per-app - one heavy app can impact others

Business+ Includes
  • Business

  • Education

  • Enterprise

  • Partners

Video SDK Accounts
PlanUses Limits
Pay As You Go (Deprecated)Pro
Annual Prepay Monthly UsagePro
All other plansBusiness+

Event Subscription Limits

  • Maximum 10 event subscriptions per application

  • No limit on events per subscription

  • Event subscription API has Heavy rate limit

  • WebSocket: Only 1 subscription connection at a time (new connection closes previous)

Common Gotchas

IssueSolution
429 on first request of the dayAnother app on account used quota
Different limits than documentedCheck account type (Free/Pro/Business+)
Meeting create fails at 100/dayPer-user limit - use different host
Concurrent DELETE errorsSerialize DELETE operations on same user
Daily limit hit unexpectedlyHeavy + Resource-Intensive share quota

Resources

Requirements and compatibility

Written for: OpenAI Codex

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

What our scanner noticed· Medium risk

  • Possible data-exfiltration endpoints
  • Instructions that use the network

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Zoom
Publisher
OpenAI (Official)
Distributed by
OpenAI
Source
openai/plugins · plugins/zoom/skills/rest-api · commit d420d13
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from plugins/zoom/LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Zoom or OpenAI.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download build-zoom-rest-api-app.zip