# 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](https://marketplace.zoom.us/) 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 ```bash POST /webhooks/options ``` ```json { "notification_endpoint_url": "https://your-server.com/zoom/webhook", "events": [ "meeting.started", "meeting.ended", "meeting.participant_joined", "recording.completed" ] } ``` #### Get Subscription ```bash GET /webhooks/options ``` **Response:** ```json { "notification_endpoint_url": "https://your-server.com/zoom/webhook", "events": [ "meeting.started", "meeting.ended", "meeting.participant_joined", "recording.completed" ] } ``` #### Update Subscription ```bash PATCH /webhooks/options ``` ```json { "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 ```json { "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 ```javascript 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 ```javascript 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** ```javascript // 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 attendance ``` See [meeting-details-with-events.md](../../general/use-cases/meeting-details-with-events.md) for complete skill chaining patterns. ## Testing Webhooks 1. **Local development**: Use [ngrok](https://ngrok.com/) to expose local endpoint ```bash ngrok http 3000 ``` 2. **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](signature-verification.md)