
Zoom Webhook Events 事件类型全参考从订阅配置到事件处理的实战指南【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins本篇文章以 knowledge-work-plugins 仓库中 zoom-plugin 的 webhooks 技能文档events.md为核心系统梳理 Zoom 通过 Webhook 推送的各类事件类型会议、录制、用户、网络研讨会及其 JSON 载荷结构。读者将掌握如何订阅事件、验证事件真实性、解析事件载荷并结合仓库内完整的 Express 处理示例与故障排查清单快速落地一套可靠的事件驱动集成。概述Zoom Webhook 事件机制Zoom 会在会议、用户、录制、网络研讨会等对象发生状态变化时向配置的 HTTPS 端点实时推送 Webhook 事件。这是与 Zoom REST API 互补的两种集成方式REST API主动拉取数据如查询会议详情Webhook 事件被动接收通知如会议开始、录制完成实现事件驱动的自动化。在仓库中这一机制由 webhooks 技能 完整承载它提供事件订阅配置、签名校验、投递与重试处理、事件类型选择等全流程参考并建议先使用工作流技能再回到该技能查阅验证、订阅和投递细节。每个事件都包含三个层面的信息事件名event如meeting.started用于路由分发时间戳event_ts事件产生时间可用于去重与防重放载荷payloadaccount_id与具体业务对象object承载事件的详细数据。事件载荷结构所有 Zoom Webhook 事件都遵循统一的外层信封结构。以下为 events.md 给出的标准载荷示例{ 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 } } }各字段的实践解读字段含义实战提示event事件类型标识服务端据此做switch/路由分发event_ts事件产生时间戳Unix 秒级结合x-zm-request-timestamp头做重放防护与事件去重payload.account_id事件所属 Zoom 账号 ID多账号/多租户场景下的第一级隔离键payload.object业务实体数据不同事件类型的object字段各不相同见下文各分类值得注意object.id是会议/录制等实体的标识。对于周期性会议meeting-details-with-events.md 建议优先使用uuid而非id做状态跟踪因为id在重复会议中可复用而uuid每次实例唯一更可靠。会议事件Meeting Eventsevents.md 列出了 9 个会议生命周期事件EventDescriptionmeeting.createdMeeting createdmeeting.updatedMeeting updatedmeeting.deletedMeeting deletedmeeting.startedMeeting startedmeeting.endedMeeting endedmeeting.participant_joinedParticipant joinedmeeting.participant_leftParticipant leftmeeting.sharing_startedScreen share startedmeeting.sharing_endedScreen share ended结合 subscriptions.md 的事件分类表可进一步明确各事件的触发时机与关键载荷字段EventTrigger关键载荷字段meeting.created会议被创建/预约id、topic、host_id、start_timemeeting.updated会议设置被修改id、topic、settingsmeeting.deleted会议被删除id、host_idmeeting.started会议开始id、topic、host_id、start_timemeeting.ended会议结束id、end_time、durationmeeting.participant_joined参与者入会participant.user_id、participant.user_name、participant.join_timemeeting.participant_left参与者离会participant.user_id、participant.leave_timemeeting.sharing_started屏幕共享开始participant、sharing_detailsmeeting.sharing_ended屏幕共享结束participant典型应用场景包括实时会议状态看板、参会考勤统计、会后自动触发下游处理流程。录制事件Recording Events云端录制从开始到可下载会经历多个阶段events.md 记录的 7 个事件完整覆盖了这一生命周期EventDescriptionrecording.startedRecording startedrecording.stoppedRecording stoppedrecording.pausedRecording pausedrecording.resumedRecording resumedrecording.completedRecording ready for downloadrecording.trashedRecording moved to trashrecording.deletedRecording permanently deleted其中最有工程价值的是recording.completed它代表录制文件已经处理完成、可以下载。这也是 SKILL.md 触发器清单中明确列出的高频事件recording completed webhook常用于构建录制完成 → 自动下载 → 转写/归档的自动化流水线可参见仓库中 recording-download-pipeline.md 与 recording-transcription.md 用例。subscriptions.md 还补充了recording.recovered从回收站恢复事件使录制事件族在completed → trashed → deleted/recovered的完整状态机中保持闭合。用户事件User Events用户生命周期事件用于账号治理与合规审计EventDescriptionuser.createdUser createduser.updatedUser updateduser.deletedUser deleteduser.activatedUser activateduser.deactivatedUser deactivated结合 subscriptions.md 的触发语义user.created在新用户添加时触发user.deactivated/user.activated对应账号停用与恢复。这些事件可与用户生命周期跟踪如创建用户后订阅其事件、按状态同步到内部目录结合使用。网络研讨会事件Webinar Events针对大规模对外活动events.md 提供了 5 个核心事件EventDescriptionwebinar.createdWebinar createdwebinar.updatedWebinar updatedwebinar.deletedWebinar deletedwebinar.startedWebinar startedwebinar.endedWebinar endedsubscriptions.md 额外补充了webinar.registration_created新报名注册事件可用于报名人数实时统计、参会提醒邮件等营销自动化场景。订阅事件两种配置方式要让上述事件真正推送到你的端点必须先完成事件订阅。仓库提供两种方式详见 subscriptions.md。方式一Marketplace 门户配置推荐用于初始搭建进入 Marketplace 中的应用配置页导航到Feature → Event Subscriptions添加订阅名称与端点 URL勾选需要订阅的事件类型保存并激活。方式二Webhook Subscriptions API程序化管理通过 REST API 可以程序化地创建、查询、更新订阅请求需携带webhook:read:admin/webhook:write:admin作用域令牌# 创建订阅 POST /webhooks/options{ notification_endpoint_url: https://your-server.com/zoom/webhook, events: [ meeting.started, meeting.ended, meeting.participant_joined, recording.completed ] }# 查询订阅 GET /webhooks/options{ notification_endpoint_url: https://your-server.com/zoom/webhook, events: [ meeting.started, meeting.ended, meeting.participant_joined, recording.completed ] }# 更新订阅PATCH 仅提交需要变更的字段 PATCH /webhooks/options{ events: [ meeting.started, meeting.ended, recording.completed, user.created ] }订阅对象的核心设置如下SettingDescriptionRequirednotification_endpoint_url你的 HTTPS 端点必须公网可达Yesevents要订阅的事件类型数组Yessecret_token用于签名验证的密钥建议启用JavaScript 程序化更新订阅的完整示例来自 subscriptions.mdasync 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; } // 为订阅追加新事件 await updateWebhookSubscription(token, [ meeting.started, meeting.ended, recording.completed, user.created, // New event user.deleted // New event ]);多订阅拆分可以创建多个订阅来实现不同事件推送到不同端点、生产与开发端点隔离、按事件类型组织、将事件路由到不同微服务。事件的验证机制收到事件后必须先验证其真实性。Zoom 提供两道验证详见 verification.md入口摘要见 signature-verification.md1. 端点 URL 验证配置阶段配置端点时Zoom 会发送endpoint.url_validation挑战请求{ event: endpoint.url_validation, payload: { plainToken: random_token_string } }服务端需用 Webhook Secret 对plainToken做 HMAC-SHA256 哈希并原样返回plainToken与encryptedTokenconst 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 }); } // 处理其他事件... res.status(200).send(); });2. 请求签名验证每次投递每个事件请求都携带两个头HeaderDescriptionx-zm-signature请求签名x-zm-request-timestamp请求时间戳验证公式为payload v0: x-zm-request-timestamp : raw_body expected v0 HMAC_SHA256(webhook_secret, payload)验证代码来自 verification.mdconst crypto require(crypto); function verifyWebhook(req) { const signature req.headers[x-zm-signature]; const timestamp req.headers[x-zm-request-timestamp]; // 优先使用框架捕获的原始请求体字节避免 JSON 重序列化导致不一致 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; }关键陷阱HMAC 必须基于原始请求体字节计算。如果在 Express 中用express.json()先解析再JSON.stringify(req.body)空白、键顺序的任何变化都会导致签名不一致。正确做法是用verify回调捕获原始 Bufferapp.use(require(express).json({ verify: (req, _res, buf) { req.rawBody buf; } }));环境变量与密钥管理仓库将 Webhook 相关密钥标准化为.env键见 environment-variables.mdVariableRequiredUsed forWhere to findZOOM_WEBHOOK_SECRETYesWebhook 载荷的 HMAC 签名验证Marketplace → Event Subscriptions → Secret TokenWEBHOOK_SECRET_TOKENAlias同一密钥的别名写法同上ZOOM_VERIFICATION_TOKENLegacy only旧版端点验证Marketplace 遗留字段老应用配置注意事项新实现优先使用ZOOM_WEBHOOK_SECRET/ Secret TokenWebhook Secret 只能存放在服务端密钥存储中切勿写入前端代码或公开仓库。完整事件处理示例将事件订阅、URL 验证、签名校验、事件分发串起来的最小可运行 Express 处理器如下综合 SKILL.md 与 meeting-details-with-events.mdconst express require(express); const crypto require(crypto); const app express(); // 捕获原始请求体用于签名验证避免重序列化 JSON app.use(express.json({ verify: (req, _res, buf) { req.rawBody buf; } })); // URL 验证挑战响应 function handleUrlValidation(req, res, webhookSecret) { const hashForValidation crypto .createHmac(sha256, webhookSecret) .update(req.body.payload.plainToken) .digest(hex); return res.json({ plainToken: req.body.payload.plainToken, encryptedToken: hashForValidation }); } // 签名验证 function verifyWebhookSignature(req, webhookSecret) { 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 expectedSignature v0${crypto .createHmac(sha256, webhookSecret) .update(payload) .digest(hex)}; return signature expectedSignature; } app.post(/webhook, (req, res) { const WEBHOOK_SECRET process.env.ZOOM_WEBHOOK_SECRET; // 1. 处理 URL 验证挑战 if (req.body.event endpoint.url_validation) { return handleUrlValidation(req, res, WEBHOOK_SECRET); } // 2. 校验签名 if (!verifyWebhookSignature(req, WEBHOOK_SECRET)) { return res.status(401).send(Invalid signature); } // 3. 分发事件 const { event, payload } req.body; console.log(Received event: ${event}); 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 meeting.participant_joined: console.log(${payload.object.participant.user_name} joined); break; case recording.completed: processRecording(payload.object); break; } res.status(200).send(); }); app.listen(3000, () { console.log(Webhook server running on port 3000); });Skill Chaining事件与 REST API 的编排Webhook 事件常与 REST API 组合成技能链见 subscriptions.md 与 meeting-details-with-events.mdChainPatternUse CaseREST API → Webhooks创建会议后订阅事件跟踪会议生命周期Webhooks → REST API收到事件后拉取详情录制完成时触发下载Users API → Webhooks创建用户并订阅用户事件用户生命周期跟踪典型的先取详情、再订阅事件编排// Step 1: 订阅会议事件一次性配置 await updateWebhookSubscription(token, [meeting.started, meeting.ended]); // Step 2: 通过 REST API 创建会议 const meeting await getMeetingDetails(123456789, accessToken); // Step 3: meeting.started 事件到达 → 更新状态、通知与会者 // Step 4: meeting.ended 事件到达 → 落库考勤、触发会后处理投递可靠性重试、幂等与预检重试与幂等Zoom 对失败的 Webhook5xx 响应最多重试 3 次事件投递语义是至少一次at-least-once同一事件可能重复到达处理方应快速返回 200先应答、后异步处理业务逻辑并对副作用操作按事件 ID/时间戳/资源键去重处理程序必须保持可重入、可安全重复执行。5 分钟预检清单RUNBOOK.md 提供了深入调试前应先完成的预检流程端点可达性公网 HTTPS 端点可被 Zoom 访问反向代理正确路由到服务签名验证使用原始请求体验证x-zm-signature校验x-zm-request-timestamp并拒绝过期时间戳URL 验证正确处理endpoint.url_validation返回匹配的plainToken与encryptedToken订阅配置应用配置中已启用事件订阅且已选择并保存所需事件类型处理模式快速返回 200、异步执行业务逻辑、处理器幂等快速探测本地测试载荷验证签名链路Zoom 测试事件到达并被记录日志中无连续非 200 响应。配套的验证命令将域名替换为你的 Webhook 路由# 1) 可达性检查 curl -sS -i https://your-domain.example/webhook # 2) 发送测试事件时查看服务日志按你的运行时替换 pm2/docker/systemd pm2 logs your-service --lines 100 # 3) 基础健康检查 curl -sS -i https://your-domain.example/health快速决策树症状排查方向收不到事件端点不可达或订阅配置错误401 Invalid signature原始请求体不一致或密钥不匹配事件重复缺乏幂等处理或响应延迟常见故障troubleshooting/common-issues.md 归纳了三类高频问题签名验证失败401常见原因是基于重序列化的 body 计算 HMAC空白/键顺序变化、使用了错误的密钥Webhook Secret 与 OAuth Secret 混淆、或v0:{timestamp}:{body}前缀拼写不精确。修复用原始请求体字节验证并同时校验时间戳防重放超时/重试/重复事件响应过慢导致 Zoom 重试、同一事件被多次处理。修复快速应答并异步入队、按事件 ID/时间戳与载荷标识去重URL 验证失败未正确实现endpoint.url_validation响应。修复按规范返回plainTokenencryptedToken。本地测试与作用域本地联调本地开发可用 ngrok 暴露端点ngrok http 3000在 Marketplace 门户 → App → Webhooks → Logs 查看投递日志上线前先验证签名处理链路牢记 Zoom 对 5xx 响应最多重试 3 次的投递行为。所需作用域ScopeOperationswebhook:read:admin查看 Webhook 设置webhook:write:admin修改 Webhook 设置若涉及 OAuth 鉴权配置可参考仓库中的 oauth 技能。延伸阅读webhooks/SKILL.mdWebhook 技能入口含快速上手代码与事件清单webhooks/references/events.md本文核心完整事件类型参考webhooks/references/verification.mdURL 验证与请求签名验证webhooks/references/subscriptions.md事件订阅 API 与事件分类表webhooks/references/environment-variables.md标准化.env密钥键webhooks/RUNBOOK.md5 分钟预检运行手册webhooks/troubleshooting/common-issues.md签名、重试、URL 验证故障排查general/use-cases/meeting-details-with-events.mdREST API 与 Webhook 事件编排的完整实战用例。【免费下载链接】knowledge-work-pluginsOpen source repository of plugins primarily intended for knowledge workers to use in Claude Cowork项目地址: https://gitcode.com/GitHub_Trending/kn/knowledge-work-plugins创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考