brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
zoom-apiIntegrates Zoom API v2 (Meetings, Webinars, Recordings, Phone, Users) using the zoom-python-client SDK v0.2+ with Server-to-Server OAuth, proper pagination, and rate-limit handling.
Independent GitHub snapshot · Automated classification · Original documentation governs
name: zoom-api description: Integrates Zoom API v2 (Meetings, Webinars, Recordings, Phone, Users) using the zoom-python-client SDK v0.2+ with Server-to-Server OAuth, proper pagination, and rate-limit handling. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: coding triggers: zoom, zoom api, zoom meetings, create zoom meeting, zoom sdk, zoom webinars, zoom recording, zoom-python archetypes:
Integrates the Zoom API v2 — Meetings, Webinars, Recordings, Phone, and Users management — using the zoom-python-client SDK v0.2+ with Server-to-Server OAuth authentication. When loaded, this skill makes the model implement Zoom API operations with proper token management, pagination for list endpoints, rate-limit handling, and webhook event processing.
ZoomApiClient from environment variables using ZoomApiClient.init_from_env() — never hardcode credentialsnext_page_token in list endpoint responses to iterate all pagesrequests.exceptions.HTTPError with status code inspectionX-RateLimit-Limit and X-RateLimit-Remaining headerstopic, start_time, duration for meetings; topic for webinars2026-05-23T15:00:00Z) for all datetime parametersZoom meetings and webinars programmatically
Zoom RTMS SDK (Real-Time Media Streams) instead
ZoomApiClient from environment variables (ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET). The SDK handles token caching and refresh automatically. Checkpoint: Verify authentication by calling zoom_client.users.get_user("me") — this returns the authenticated accounts owner details.; Identify the Target Resource: Determine user ID or email address (for user-scoped endpoints), or use the API root for account-scoped operations. User IDs can be me (the authenticated user), an email address, or the numeric user ID. Checkpoint: Confirm the user exists with get_user() before creating meetings for them.; Execute the API Operation: Call the appropriate method: create_meeting(), get_meeting(), list_recordings(), etc. Pass required parameters as keyword arguments. For list endpoints, implement pagination using next_page_token from the response. Checkpoint: Validate the response contains expected fields — for meetings, check join_url and id are present.; Handle Errors and Rate Limits: Catch requests.exceptions.HTTPError and inspect the status code: 400 (bad request / validation), 401 (bad auth / token expired), 404 (resource not found), 429 (rate limited). For 429, implement exponential backoff using the Retry-After header. Checkpoint: Log the response payload for 400s to capture validation error details.; Process Webhooks: Zoom sends event notifications to your webhook endpoint as JSON POST bodies. Validate the webhook using the Authorization header (Bearer token comparison). Acknowledge by returning HTTP 200 immediately. Checkpoint: Return 200 within 3 seconds — Zoom retries for 24 hours if you do not acknowledge.import os
from datetime import datetime, timedelta
from zoom_python_client.zoom_api_client import ZoomApiClient
import requests
# ❌ BAD — JWT token (deprecated), hardcoded credentials, no error handling
import jwt
token = jwt.encode({"iss": "API_KEY", "exp": datetime.now() + timedelta(hours=1)}, "API_SECRET")
headers = {"Authorization": f"Bearer {token}"}
resp = requests.post(
"https://api.zoom.us/v2/users/me/meetings",
headers=headers,
json={"topic": "My Meeting", "type": 2, "start_time": "2026-05-23T15:00:00Z", "duration": 60},
)
print(resp.json())
# ✅ GOOD — Server-to-Server OAuth, env-based config, typed parameters, error handling
import logging
logger = logging.getLogger(__name__)
# Initialize from environment variables
# Requires: ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET
zoom_client = ZoomApiClient.init_from_env()
def create_scheduled_meeting(
topic: str,
start_time: str,
duration_minutes: int,
settings: dict | None = None,
password: str | None = None,
) -> dict:
"""Create a scheduled Zoom meeting and return meeting details."""
meeting_data: dict = {
"topic": topic,
"type": 2, # 1=instant, 2=scheduled, 3=recurring, 8=webinar
"start_time": start_time, # ISO 8601: "2026-05-23T15:00:00Z"
"duration": duration_minutes,
"timezone": "UTC",
"settings": settings or {
"host_video": True,
"participant_video": True,
"join_before_host": False,
"mute_upon_entry": True,
"approval_type": 0, # 0=auto approve, 1=manual, 2=no registration
"audio": "voip",
"auto_recording": "none",
},
}
if password:
meeting_data["password"] = password
try:
result = zoom_client.meetings.create_meeting(meeting_data)
meeting = result.json() if hasattr(result, "json") else result
logger.info("Meeting created", extra={"id": meeting.get("id"), "topic": topic, "join_url": meeting.get("join_url")})
return {
"id": meeting.get("id"),
"join_url": meeting.get("join_url"),
"start_url": meeting.get("start_url"),
"password": meeting.get("password"),
"start_time": meeting.get("start_time"),
}
except requests.exceptions.HTTPError as exc:
status = exc.response.status_code if exc.response else 0
body = exc.response.json() if exc.response and exc.response.content else {}
logger.error("Zoom meeting creation failed", extra={"status": status, "response": body})
if status == 429:
retry_after = exc.response.headers.get("Retry-After", "60")
raise RuntimeError(f"Rate limited. Retry after {retry_after}s") from exc
elif status == 401:
raise RuntimeError("Zoom authentication failed — check credentials") from exc
elif status == 404:
raise RuntimeError("User not found") from exc
raise
import os
import requests
# ❌ BAD — no pagination, only fetches first page (max 30 records)
result = zoom_client.meetings.list_meetings("me")
print(result.json())
# ✅ GOOD — full pagination, typed response, resource cleanup
def list_all_recordings(
user_id: str = "me",
page_size: int = 300,
from_date: str | None = None,
to_date: str | None = None,
) -> list[dict]:
"""List all cloud recordings for a user, handling pagination."""
all_recordings: list[dict] = []
next_page_token: str | None = None
while True:
params: dict = {
"user_id": user_id,
"page_size": min(page_size, 300),
}
if next_page_token:
params["next_page_token"] = next_page_token
if from_date:
params["from"] = from_date
if to_date:
params["to"] = to_date
try:
response = zoom_client.meetings.list_recordings(params)
data = response.json() if hasattr(response, "json") else response
meetings = data.get("meetings", [])
all_recordings.extend(meetings)
next_page_token = data.get("next_page_token")
logger.info("Fetched recordings page", extra={"count": len(meetings), "total_so_far": len(all_recordings)})
if not next_page_token:
break
except requests.exceptions.HTTPError as exc:
logger.error("Failed to list recordings", extra={"status": exc.response.status_code if exc.response else 0})
raise
return all_recordings
import os
import requests
# ❌ BAD — no input validation, no user action filtering, no pagination
result = zoom_client.users.get_user("someone@example.com")
print(result.json())
# ✅ GOOD — user lookup with validation, action options, error handling
from typing import Literal
UserAction = Literal["activate", "deactivate", "suspend", "unsuspend"]
def get_or_create_user(email: str, first_name: str, last_name: str) -> dict:
"""Look up a Zoom user or create them if they do not exist."""
try:
result = zoom_client.users.get_user(email)
user = result.json() if hasattr(result, "json") else result
logger.info("User found", extra={"email": email, "id": user.get("id")})
return {
"id": user.get("id"),
"email": user.get("email"),
"first_name": user.get("first_name"),
"last_name": user.get("last_name"),
"status": user.get("status"),
"created": user.get("created_at"),
}
except requests.exceptions.HTTPError as exc:
if exc.response and exc.response.status_code == 404:
# User does not exist — create them
return create_user(email, first_name, last_name)
raise
def create_user(email: str, first_name: str, last_name: str) -> dict:
"""Create a new Zoom user."""
user_data = {
"action": "create", # "create", "autoCreate", "custCreate", "ssoCreate"
"user_info": {
"email": email,
"first_name": first_name,
"last_name": last_name,
"type": 1, # 1=basic (free), 2=pro, 3=corporate
},
}
try:
result = zoom_client.users.create_user(user_data)
user = result.json() if hasattr(result, "json") else result
logger.info("User created", extra={"email": email, "id": user.get("id")})
return user
except requests.exceptions.HTTPError as exc:
body = exc.response.json() if exc.response and exc.response.content else {}
logger.error("User creation failed", extra={"email": email, "response": body})
raise
def update_user_status(email: str, action: UserAction) -> bool:
"""Update a Zoom users status (suspend/unsuspend)."""
try:
zoom_client.users.update_user(email, {"action": action})
logger.info("User status updated", extra={"email": email, "action": action})
return True
except requests.exceptions.HTTPError as exc:
logger.error("Status update failed", extra={"email": email, "action": action, "status": exc.response.status_code if exc.response else 0})
return False
account_id + client_id + client_secret) for authentication — Zoom deprecated JWT tokens in September 2023ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET — never hardcode them2026-05-23T15:00:00Z) for all start_time parametersnext_page_token for responses exceeding page_size (default 30, max 300)topic max 200 chars, start_time must be in the future, duration minimum 10 minutesnext_page_tokenme for the authenticated userAuthorization header on incoming webhooks to prevent unauthorized event injectionWhen implementing Zoom API code, the output must follow this structure:
ZoomApiClient.init_from_env() reading ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRETme; meeting/webinar ID validated before operationstopic, start_time (ISO 8601), duration (minutes), type, and settingsrequests.exceptions.HTTPErrorwhile next_page_token: loop for all list endpointsid, join_url, start_url, password from responsesZoom for meeting notification via SMS |
| coding-slack-api | Team messaging — send Zoom meeting links and recording notifications to Slack channels |
| coding-sendgrid-api | Transactional email — use for meeting confirmation and recording delivery emails |
Authoritative documentation links for this skill's domain. The model follows markdown links at load time to resolve external references and inline content.