
Setup Zoom Webhooks
- 1.4k installs
- 23.1k repo stars
- Updated July 28, 2026
- anthropics/knowledge-work-plugins
setup-zoom-webhooks is an agent skill for reference skill for zoom webhooks. use after routing to an event-driven workflow when implementing subscriptions, signature verification, delivery handling, retries, or.
About
The setup-zoom-webhooks skill is designed for reference skill for Zoom webhooks. Use after routing to an event-driven workflow when implementing subscriptions, signature verification, delivery handling, retries, or. /setup-zoom-webhooks Background reference for Zoom event delivery over HTTP. Prefer workflow skills first, then use this file for verification, subscription, and delivery details. Invoke when the user asks about setup zoom webhooks or related SKILL.md workflows.
- Zoom app with Event Subscriptions enabled.
- HTTPS endpoint to receive webhooks.
- Webhook secret token for verification.
- references/events.md - Complete event types reference.
- references/verification.md - Webhook URL validation.
Setup Zoom Webhooks by the numbers
- 1,412 all-time installs (skills.sh)
- +81 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #257 of 1,896 Design & UI/UX skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
setup-zoom-webhooks capabilities & compatibility
- Capabilities
- zoom app with event subscriptions enabled · https endpoint to receive webhooks · webhook secret token for verification · references/events.md complete event types refe
- Use cases
- frontend
What setup-zoom-webhooks says it does
Reference skill for Zoom webhooks. Use after routing to an event-driven workflow when implementing subscriptions, signature verification, delivery handling, retries, or event-type
Reference skill for Zoom webhooks. Use after routing to an event-driven workflow when implementing subscriptions, signature verification, delivery handling, ret
npx skills add https://github.com/anthropics/knowledge-work-plugins --skill setup-zoom-webhooksAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.4k |
|---|---|
| repo stars | ★ 23.1k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 28, 2026 |
| Repository | anthropics/knowledge-work-plugins ↗ |
How do I reference skill for zoom webhooks. use after routing to an event-driven workflow when implementing subscriptions, signature verification, delivery handling, retries, or?
Reference skill for Zoom webhooks. Use after routing to an event-driven workflow when implementing subscriptions, signature verification, delivery handling, retries, or.
Who is it for?
Developers using setup zoom webhooks workflows documented in SKILL.md.
Skip if: Skip when the task falls outside setup-zoom-webhooks scope or needs a different stack.
When should I use this skill?
User asks about setup zoom webhooks or related SKILL.md workflows.
What you get
Completed setup-zoom-webhooks workflow with documented commands, files, and expected deliverables.
- Preflight checklist results
- Signature verification config
Files
/setup-zoom-webhooks
Background reference for Zoom event delivery over HTTP. Prefer workflow skills first, then use this file for verification, subscription, and delivery details.
Prerequisites
- Zoom app with Event Subscriptions enabled
- HTTPS endpoint to receive webhooks
- Webhook secret token for verification
Need help with authentication? See the [zoom-oauth](../oauth/SKILL.md) skill for OAuth setup.
Quick Start
// Express.js webhook handler
const crypto = require('crypto');
// Capture raw body for signature verification (avoid re-serializing JSON).
app.use(require('express').json({
verify: (req, _res, buf) => { req.rawBody = buf; }
}));
app.post('/webhook', (req, res) => {
// Verify webhook signature
const signature = req.headers['x-zm-signature'];
const timestamp = req.headers['x-zm-request-timestamp'];
const body = req.rawBody ? req.rawBody.toString('utf8') : JSON.stringify(req.body);
const payload = `v0:${timestamp}:${body}`;
const hash = crypto.createHmac('sha256', WEBHOOK_SECRET)
.update(payload).digest('hex');
if (signature !== `v0=${hash}`) {
return res.status(401).send('Invalid signature');
}
// Handle event
const { event, payload } = req.body;
console.log(`Received: ${event}`);
res.status(200).send();
});Common Events
| Event | Description |
|---|---|
meeting.started | Meeting has started |
meeting.ended | Meeting has ended |
meeting.participant_joined | Participant joined meeting |
recording.completed | Cloud recording ready |
user.created | New user added |
Detailed References
- [references/events.md](references/events.md) - Complete event types reference
- [references/verification.md](references/verification.md) - Webhook URL validation
- [references/subscriptions.md](references/subscriptions.md) - Event subscriptions API
Troubleshooting
- [RUNBOOK.md](RUNBOOK.md) - 5-minute preflight checks before deep debugging
- [troubleshooting/common-issues.md](troubleshooting/common-issues.md) - Signature verification, retries, URL validation
Sample Repositories
Official (by Zoom)
| Type | Repository | Stars |
|---|---|---|
| Node.js | webhook-sample | 34 |
| PostgreSQL | webhook-to-postgres | 5 |
| Go/Fiber | Go-Webhooks | - |
| Header Auth | zoom-webhook-verification-headers | - |
Community
| Language | Repository | Description |
|---|---|---|
| Laravel | binary-cats/laravel-webhooks | Laravel webhook handler |
| AWS Lambda | splunk/zoom-webhook-to-hec | Serverless to Splunk HEC |
| Node.js | Will4950/zoom-webhook-listener | Webhook forwarder |
| Express+Redis | ojusave/eventSubscriptionPlayground | Socket.io + Redis |
Multi-Language Samples (by tanchunsiong)
Full list: See general/references/community-repos.md
Resources
- Webhook docs: https://developers.zoom.us/docs/api/webhooks/
- Event reference: https://developers.zoom.us/docs/api/rest/reference/zoom-api/events/
- Developer forum: https://devforum.zoom.us/
Environment Variables
- See references/environment-variables.md for standardized
.envkeys and where to find each value.
Zoom Webhooks Environment Variables
Standard .env keys
| Variable | Required | Used for | Where to find |
|---|---|---|---|
ZOOM_WEBHOOK_SECRET | Yes | HMAC signature verification for webhook payloads | Zoom Marketplace -> Event Subscriptions -> Secret Token |
WEBHOOK_SECRET_TOKEN | Alias | Same secret token under alternate naming | Same as above |
ZOOM_VERIFICATION_TOKEN | Legacy only | Legacy endpoint verification | Marketplace legacy field (older app configs) |
Notes
- Prefer
ZOOM_WEBHOOK_SECRET/ Secret Token for current implementations. - Keep webhook secret in server-side secret storage only.
Webhooks - Events
Complete reference of Zoom webhook events.
Overview
Zoom sends webhook events for various actions across meetings, users, recordings, and more.
Meeting Events
| Event | Description |
|---|---|
meeting.created | Meeting created |
meeting.updated | Meeting updated |
meeting.deleted | Meeting deleted |
meeting.started | Meeting started |
meeting.ended | Meeting ended |
meeting.participant_joined | Participant joined |
meeting.participant_left | Participant left |
meeting.sharing_started | Screen share started |
meeting.sharing_ended | Screen share ended |
Recording Events
| Event | Description |
|---|---|
recording.started | Recording started |
recording.stopped | Recording stopped |
recording.paused | Recording paused |
recording.resumed | Recording resumed |
recording.completed | Recording ready for download |
recording.trashed | Recording moved to trash |
recording.deleted | Recording permanently deleted |
User Events
| Event | Description |
|---|---|
user.created | User created |
user.updated | User updated |
user.deleted | User deleted |
user.activated | User activated |
user.deactivated | User deactivated |
Webinar Events
| Event | Description |
|---|---|
webinar.created | Webinar created |
webinar.updated | Webinar updated |
webinar.deleted | Webinar deleted |
webinar.started | Webinar started |
webinar.ended | Webinar ended |
Event Payload Structure
{
"event": "meeting.started",
"event_ts": 1234567890,
"payload": {
"account_id": "account_id",
"object": {
"id": "meeting_id",
"topic": "Meeting Topic",
"host_id": "host_user_id",
"start_time": "2024-01-15T10:00:00Z"
}
}
}Resources
- Events reference: https://developers.zoom.us/docs/api/rest/reference/zoom-api/events/
Signature Verification
This content lives in verification.md (URL validation + request signature verification).
- See: verification.md
Webhooks - Subscriptions
Configure webhook event subscriptions for real-time notifications.
Overview
Subscribe to Zoom events to receive real-time notifications at your endpoint. This enables:
- Real-time meeting tracking (started, ended, participant changes)
- Automated recording processing pipelines
- User lifecycle management
- Skill chaining: Combine REST API calls with event-driven workflows
Configuring Subscriptions
Method 1: Via Marketplace Portal (Recommended for Setup)
1. Go to your app in Marketplace 2. Navigate to Feature → Event Subscriptions 3. Add subscription name and endpoint URL 4. Select events to subscribe to 5. Save and activate
Method 2: Via API (Programmatic Management)
Use the Webhook Subscriptions API for programmatic subscription management.
Create Subscription
POST /webhooks/options{
"notification_endpoint_url": "https://your-server.com/zoom/webhook",
"events": [
"meeting.started",
"meeting.ended",
"meeting.participant_joined",
"recording.completed"
]
}Get Subscription
GET /webhooks/optionsResponse:
{
"notification_endpoint_url": "https://your-server.com/zoom/webhook",
"events": [
"meeting.started",
"meeting.ended",
"meeting.participant_joined",
"recording.completed"
]
}Update Subscription
PATCH /webhooks/options{
"events": [
"meeting.started",
"meeting.ended",
"recording.completed",
"user.created"
]
}Subscription Settings
| Setting | Description | Required |
|---|---|---|
| notification_endpoint_url | Your HTTPS endpoint (must be publicly accessible) | Yes |
| events | Array of event types to subscribe to | Yes |
Event Categories
Meeting Events
| Event | Trigger |
|---|---|
meeting.created | Meeting scheduled |
meeting.updated | Meeting settings changed |
meeting.deleted | Meeting deleted |
meeting.started | Meeting begins |
meeting.ended | Meeting ends |
meeting.participant_joined | Participant joins |
meeting.participant_left | Participant leaves |
meeting.sharing_started | Screen share begins |
meeting.sharing_ended | Screen share ends |
Recording Events
| Event | Trigger |
|---|---|
recording.started | Cloud recording begins |
recording.stopped | Cloud recording paused/stopped |
recording.paused | Cloud recording paused |
recording.resumed | Cloud recording resumed |
recording.completed | Recording processed and available |
recording.trashed | Recording moved to trash |
recording.deleted | Recording permanently deleted |
recording.recovered | Recording restored from trash |
User Events
| Event | Trigger |
|---|---|
user.created | New user added |
user.updated | User details changed |
user.deleted | User removed |
user.deactivated | User deactivated |
user.activated | User activated |
Webinar Events
| Event | Trigger |
|---|---|
webinar.created | Webinar scheduled |
webinar.started | Webinar begins |
webinar.ended | Webinar ends |
webinar.registration_created | New registration |
Subscription Object Schema
{
"notification_endpoint_url": "string (HTTPS URL)",
"events": ["array of event type strings"],
"secret_token": "string (for signature verification)"
}Code Examples
JavaScript - Express Webhook Handler with Subscription Check
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const app = express();
app.use(express.json());
// Verify webhook signature
function verifyWebhookSignature(req, secret) {
const message = `v0:${req.headers['x-zm-request-timestamp']}:${JSON.stringify(req.body)}`;
const hashForVerify = crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
const signature = `v0=${hashForVerify}`;
return signature === req.headers['x-zm-signature'];
}
// Handle webhook events
app.post('/zoom/webhook', (req, res) => {
const WEBHOOK_SECRET = process.env.ZOOM_WEBHOOK_SECRET;
if (!verifyWebhookSignature(req, WEBHOOK_SECRET)) {
return res.status(401).send('Unauthorized');
}
const { event, payload } = req.body;
switch (event) {
case 'meeting.started':
console.log(`Meeting started: ${payload.object.topic}`);
break;
case 'meeting.ended':
console.log(`Meeting ended: ${payload.object.uuid}`);
break;
case 'recording.completed':
processRecording(payload.object);
break;
}
res.status(200).send('OK');
});JavaScript - Manage Subscriptions via API
async function updateWebhookSubscription(accessToken, events) {
const response = await axios.patch(
'https://api.zoom.us/v2/webhooks/options',
{ events },
{
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
}
// Add new events to subscription
await updateWebhookSubscription(token, [
'meeting.started',
'meeting.ended',
'recording.completed',
'user.created', // New event
'user.deleted' // New event
]);Multiple Subscriptions
You can create multiple subscriptions to:
- Send different events to different endpoints
- Separate production and development endpoints
- Organize by event type
- Route events to different microservices
Skill Chaining
Webhooks are commonly combined with REST API in skill chains:
| Chain | Pattern | Use Case |
|---|---|---|
| REST API → Webhooks | Create meeting, subscribe to events | Track meeting lifecycle |
| Webhooks → REST API | Receive event, fetch details | Recording download on completion |
| Users API → Webhooks | Create user, subscribe to user events | User lifecycle tracking |
Example: Meeting creation with event tracking
// Step 1: Subscribe to meeting events (one-time setup)
await updateWebhookSubscription(token, ['meeting.started', 'meeting.ended']);
// Step 2: Create meeting via REST API
const meeting = await createMeeting(token, { topic: 'Team Standup', type: 2 });
// Step 3: When meeting.started webhook arrives, track it
// Step 4: When meeting.ended webhook arrives, process attendanceSee meeting-details-with-events.md for complete skill chaining patterns.
Testing Webhooks
1. Local development: Use ngrok to expose local endpoint
ngrok http 30002. Webhook logs: Check Marketplace portal → App → Webhooks → Logs 3. Test endpoint: Validate signature handling before going live 4. Retry behavior: Zoom retries failed webhooks (5xx responses) up to 3 times
Required Scopes
| Scope | Operations |
|---|---|
webhook:read:admin | View webhook settings |
webhook:write:admin | Modify webhook settings |
Resources
- Webhooks overview: https://developers.zoom.us/docs/api/rest/webhook-reference/
- Event types: https://developers.zoom.us/docs/api/rest/reference/zoom-api/events/
- Signature verification: See signature-verification.md
Webhooks - Verification
Verify webhook authenticity and handle URL validation.
Overview
Zoom provides two verification mechanisms: 1. URL Validation - Verify your endpoint during setup 2. Request Signature - Verify each webhook request
URL Validation
When you configure a webhook endpoint, Zoom sends a validation request:
{
"event": "endpoint.url_validation",
"payload": {
"plainToken": "random_token_string"
}
}Response Required
Hash the token with your webhook secret and respond:
const crypto = require('crypto');
app.post('/webhook', (req, res) => {
const { event, payload } = req.body;
if (event === 'endpoint.url_validation') {
const hashForValidation = crypto
.createHmac('sha256', WEBHOOK_SECRET_TOKEN)
.update(payload.plainToken)
.digest('hex');
return res.json({
plainToken: payload.plainToken,
encryptedToken: hashForValidation
});
}
// Handle other events...
res.status(200).send();
});Request Signature Verification
Verify each webhook request is from Zoom:
Headers
| Header | Description |
|---|---|
x-zm-signature | Request signature |
x-zm-request-timestamp | Request timestamp |
Verification Code
const crypto = require('crypto');
function verifyWebhook(req) {
const signature = req.headers['x-zm-signature'];
const timestamp = req.headers['x-zm-request-timestamp'];
// Prefer raw body bytes captured by your framework to avoid JSON re-serialization mismatches.
const body = req.rawBody ? req.rawBody.toString('utf8') : JSON.stringify(req.body);
const message = `v0:${timestamp}:${body}`;
const hash = crypto
.createHmac('sha256', WEBHOOK_SECRET_TOKEN)
.update(message)
.digest('hex');
const expectedSignature = `v0=${hash}`;
return signature === expectedSignature;
}Security Best Practices
1. Always verify signatures 2. Check timestamp to prevent replay attacks 3. Use HTTPS endpoints only 4. Keep webhook secret secure
Resources
- Webhook verification: https://developers.zoom.us/docs/api/rest/webhook-reference/#verify-webhook-events
Webhooks 5-Minute Preflight Runbook
Use this before deep debugging. It catches common webhook failures quickly.
Skill Doc Standard Note
- Agent-skill standard entrypoint is
SKILL.md. - This runbook is an operational convention (recommended), not a required skill file.
SKILL.mdis also a navigation convention for larger skill docs.
1) Confirm Endpoint Reachability
- Public HTTPS endpoint is reachable from Zoom.
- Reverse proxy routes to the correct service path.
2) Confirm Signature Verification
- Verify
x-zm-signaturewith raw request body. - Use
x-zm-request-timestampand reject stale timestamps. - Do not re-serialize parsed JSON for signature material.
Signature Formula Reminder
payload = "v0:" + x-zm-request-timestamp + ":" + raw_body
expected = "v0=" + HMAC_SHA256(webhook_secret, payload)If raw_body differs from original bytes (pretty print/re-stringify), verification fails.
3) Confirm URL Validation Handling
- Handle
endpoint.url_validationchallenge correctly. - Return expected
plainTokenand computedencryptedTokenwhen required.
URL Validation Reminder
On event = endpoint.url_validation, hash payload.plainToken with your webhook secret and return both values exactly.
4) Confirm Event Subscription Setup
- Feature/Event subscriptions enabled in app config.
- Required event types selected and saved.
5) Confirm Processing Pattern
- Respond HTTP 200 quickly.
- Process business logic asynchronously.
- Make handlers idempotent for retries.
6) Quick Probes
- Local test payload verifies signature path.
- Zoom test event reaches endpoint and is logged.
- No repeated non-200 responses in logs.
Copy/Paste Validation Commands
# 1) Reachability check (replace with your webhook route)
curl -sS -i "https://your-domain.example/webhook"
# 2) Check service logs quickly while sending test events
# (replace command with your runtime: pm2/docker/systemd)
pm2 logs your-service --lines 100
# 3) Basic endpoint health check if available
curl -sS -i "https://your-domain.example/health"Expected: endpoint is reachable over HTTPS, events appear once, and responses are consistently 2xx.
7) Fast Decision Tree
- No events received -> endpoint unreachable or wrong subscription.
- 401 invalid signature -> raw body mismatch/secret mismatch.
- Duplicate events -> no idempotency or delayed responses.
8) Retry and Idempotency Guardrail
- Treat webhook delivery as at-least-once.
- Deduplicate by event ID/timestamp/resource key before side effects.
- Keep handlers safe to re-run.
Common Issues
Quick diagnostics for Zoom Webhooks integrations.
Signature Verification Fails (401 / "Invalid signature")
Common causes:
- You are computing the HMAC over a re-serialized body (different whitespace/key order).
- You are using the wrong secret (webhook secret vs OAuth secret).
- You are not including the
v0:{timestamp}:{body}prefix exactly.
Fix:
- Verify signatures using the exact raw request body bytes (capture raw body before JSON parsing).
- Validate both
x-zm-signatureandx-zm-request-timestampand reject stale timestamps (replay protection).
See: verification.md
Timeouts / Retries / Duplicate Events
Symptom: Zoom retries delivery, you process the same event multiple times.
Fix:
- Respond fast (acknowledge ASAP, then enqueue work).
- Make handlers idempotent (dedupe by event ID/timestamp + payload identifiers).
URL Validation Fails
Symptom: You can’t enable the webhook endpoint in Marketplace; validation fails.
Fix:
- Implement
endpoint.url_validationresponse correctly (plainToken + encryptedToken).
See: verification.md
Related skills
FAQ
What does setup-zoom-webhooks do?
Reference skill for Zoom webhooks. Use after routing to an event-driven workflow when implementing subscriptions, signature verification, delivery handling, retries, or.
When should I use setup-zoom-webhooks?
User asks about setup zoom webhooks or related SKILL.md workflows.
Is setup-zoom-webhooks safe to install?
Review the Security Audits panel on this page before installing in production.