Setting the file. One moment.
Subchapter 114.41
use-cases/meeting-details-with-events.mdMarkdown21 KBView on GitHub
Retrieve meeting details and subscribe to real-time meeting events.
References
App TypesA common integration pattern: get meeting information via REST API, then receive real-time updates via webhooks when meeting events occur (started, ended, participants join/leave).
For implementation-heavy orchestration patterns (token refresh locks, retries, queue-based webhook handling, circuit-breaker and reconciliation fallbacks), see:
| Order | Skill | Purpose |
|---|---|---|
| 1 | zoom-rest-api | Retrieve meeting details |
| 2 | webhooks | Subscribe to and receive meeting events |
┌─────────────────────────────────────────────────────────────────────────┐
│ COMPLETE INTEGRATION FLOW │
└─────────────────────────────────────────────────────────────────────────┘
SETUP PHASE (One-time):
┌─────────────────────────────────────────────────────────────────────────┐
│ 1. Configure Event Subscriptions (Marketplace Portal or API) │
│ └── Subscribe to: meeting.started, meeting.ended, │
│ meeting.participant_joined, meeting.participant_left │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
RUNTIME PHASE:
┌─────────────────────────────────────────────────────────────────────────┐
│ 2. GET Meeting Details (zoom-rest-api) │
│ └── GET /meetings/{meetingId} │
│ └── Store meeting info (topic, host, settings, join_url) │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ 3. Receive Meeting Events (webhooks) │
│ └── meeting.started → Update status, notify users │
│ └── meeting.participant_joined → Track attendance │
│ └── meeting.participant_left → Log departure time │
│ └── meeting.ended → Finalize records, trigger post-processing │
└─────────────────────────────────────────────────────────────────────────┘meeting:read (for REST API)https://yourapp.com/webhooks/zoommeeting.startedmeeting.endedmeeting.participant_joinedmeeting.participant_leftEvent subscriptions are configured at app creation time in the Marketplace portal. However, you can verify your subscription status via API:
// List webhook subscriptions for your app
const response = await fetch(
'https://api.zoom.us/v2/webhooks',
{
headers: { 'Authorization': `Bearer ${accessToken}` }
}
);
const webhooks = await response.json();
console.log('Active webhooks:', webhooks);const axios = require('axios');
/**
* Get meeting details from Zoom REST API
* @param {string} meetingId - The meeting ID
* @param {string} accessToken - Valid OAuth access token
* @returns {Promise<Object>} Meeting details
*/
async function getMeetingDetails(meetingId, accessToken) {
try {
const response = await axios.get(
`https://api.zoom.us/v2/meetings/${meetingId}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
const meeting = response.data;
return {
id: meeting.id,
uuid: meeting.uuid,
topic: meeting.topic,
type: meeting.type,
status: meeting.status,
start_time: meeting.start_time,
duration: meeting.duration,
timezone: meeting.timezone,
host_id: meeting.host_id,
host_email: meeting.host_email,
join_url: meeting.join_url,
password: meeting.password,
settings: meeting.settings
};
} catch (error) {
if (error.response?.status === 404) {
throw new Error(`Meeting ${meetingId} not found`);
}
if (error.response?.status === 401) {
throw new Error('Invalid or expired access token');
}
throw error;
}
}
// Usage
const meeting = await getMeetingDetails('123456789', accessToken);
console.log(`Meeting: ${meeting.topic}`);
console.log(`Join URL: ${meeting.join_url}`);
console.log(`Host: ${meeting.host_email}`);const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// Store meeting state (use database in production)
const meetingState = new Map();
/**
* Verify Zoom webhook signature
*/
function verifyWebhookSignature
/**
* Complete example: Meeting Dashboard Integration
*
* Skills used:
* 1. zoom-rest-api - Get meeting details
* 2. webhooks - Real-time event updates
*/
const express = require('express');
const axios = require('axios');
const crypto = require('crypto');
const app = express();
app.use
| Event | Trigger | Key Payload Fields |
|---|---|---|
meeting.started | Host starts meeting | id, topic, host_id, start_time |
meeting.ended | Meeting ends | id, end_time, duration |
meeting.participant_joined | User joins | participant.user_id, participant.user_name, participant.join_time |
meeting.participant_left | User leaves | participant.user_id, participant.leave_time |
meeting.sharing_started | Screen share begins | participant, sharing_details |
meeting.sharing_ended | Screen share ends | participant |
| Error | Cause | Solution |
|---|---|---|
| 404 on GET /meetings | Invalid meeting ID | Verify meeting ID exists |
| 401 on API call | Expired token | Refresh access token |
| Invalid webhook signature | Wrong secret or modified payload | Verify WEBHOOK_SECRET matches app config |
| Missing events | Subscription not active | Check Event Subscriptions in Marketplace |
async function getMeetingWithRetry(meetingId, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await getMeetingDetails(meetingId);
} catch (error) {
if (error.response?.status === 429) {
// Rate limited - wait and retry
const retryAfter = error.response.headers['retry-after'] || 1;
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
if (error.response?.status === 401 && attempt < maxRetries) {
// Token expired - refresh and retry
await refreshAccessToken();
continue;
}
throw error;
}
}
}