Skip to content
newThe webhook.co MCP server is live — turn any webhook into an agent event. Read the docs
test locally

Test Zoom webhooks locally

Zoom's webhook setup has a gate in it: your endpoint has to answer a challenge-response check before Zoom will let you save the subscription at all — and it re-runs that check every 72 hours.

The loop

Create an endpoint and it prints a permanent ingest URL. Everything sent there is captured whole — headers, body, the exact bytes — before anything else happens. Stream those events to a port on your machine, and replay any one of them as often as you like while you fix the handler. Forwarding runs from your own machine, so it isn't a billable delivery.

wbhkzoom
$ wbhk endpoints create zoom-dev
https://wbhk.my/whep_…
$ wbhk listen <endpoint-id> --forward http://localhost:3000/webhooks
$ wbhk replay <event-id> --forward http://localhost:3000/webhooks

What's different about Zoom

Zoom won't let you save an event subscription until your URL answers a challenge. Click Validate and Zoom POSTs an endpoint.url_validation event carrying a plainToken; you have three seconds to return 200 or 204 with a JSON body echoing that plainToken plus encryptedToken, an HMAC SHA-256 of it salted with your webhook secret token, output in hex. A 200 on its own doesn't pass. And it isn't a one-time hurdle: Zoom re-runs the check every 72 hours, emails you after two and after four consecutive failures, and disables the subscription after six in a row.

Where the URL goes

In the Zoom App Marketplace, click Manage, open your app from Created Apps, and go to Features then Access. Under General Features, enable Event Subscriptions and add a new subscription. Choose your event types, paste the capture URL into the Event notification endpoint URL field, and click Validate — Zoom refuses to save the subscription until validation succeeds. Then Save.

Zoom's docs describe no send-test-event control. The only request Zoom fires on demand is the Validate button, which sends endpoint.url_validation and nothing else. Everything past that means performing the real action in Zoom — scheduling or starting a meeting — and letting the subscription fire on its own. To confirm what Zoom actually sent, the Get webhook logs API returns webhook call logs from the past seven days.

What Zoom sends

Almost every Zoom event is dot-separated resource.action — lowercase resource, snake_case action. The exception worth knowing is app_deauthorized, which carries no resource prefix and is delivered to a separate Deauthorization Notification Endpoint URL rather than to your event subscription.

  • meeting.created
  • meeting.started
  • meeting.participant_joined
  • meeting.ended
  • recording.completed
  • endpoint.url_validation

Worth knowing first

Three seconds, then it's a failure

Zoom counts a notification delivered only if your endpoint returns 200 or 204 within three seconds of the request. Anything slower is a failed delivery, regardless of what your handler eventually did with the payload. Acknowledge first and process afterwards — everything you do before responding is inside that budget.

A 4xx is never retried

Zoom retries three times: five minutes after the initial delivery attempt, twenty minutes after that retry, then sixty after the second. But only for responses of 500 and above, plus a set of Zoom-internal negative codes. Redirects and 4xx responses get no retry at all, and after three failures Zoom sends no further webhooks for that event.

No replay, a seven-day log

Nothing in Zoom's docs offers a redeliver control, so an event that burns through its three retries is gone. What you do get is the Get webhook logs API, which returns webhook call logs for an app from the past seven days — enough to see what was sent, not enough to send it again.

Verify signatures, don't allowlist IPs

Zoom signs each request with x-zm-signature, formed as v0= followed by an HMAC over the string v0:timestamp:body, where the timestamp comes from x-zm-request-timestamp. Zoom publishes its IP ranges in a support article but recommends signature verification instead, because those ranges can change at any time.

Twenty subscriptions, and duplicates

An app can hold up to twenty event subscriptions, and Zoom notes that subscriptions can carry duplicate events — the same event type selected in two of them means one action produces more than one POST. The endpoint itself must be a publicly reachable HTTPS FQDN on TLS 1.2 or later with a CA-issued certificate chain.

Signature checking is handled for you once the secret is registered — you can also check a captured signature by hand in the signature verifier.

Zoom webhooks: common questions

Can I send a test Zoom webhook without starting a meeting?

Only the validation request. Clicking Validate makes Zoom POST its URL validation challenge to your endpoint, and Zoom's docs describe no other on-demand send. For a meeting or recording event you have to perform the real action in Zoom and let the subscription fire the way it normally would.

Why won't Zoom let me save my event subscription?

Zoom blocks the save until the endpoint passes its challenge-response check. The URL has to answer the validation POST within three seconds with a 200 or 204 and a JSON body containing the plainToken it received plus encryptedToken, the hex HMAC SHA-256 of that token salted with your webhook secret token.

Does Zoom stop sending webhooks if my endpoint goes down?

Yes, eventually. Validation re-runs every 72 hours; Zoom emails you after two consecutive failures and again after four, then disables the event subscription after six in a row. Individual events also stop after three failed delivery attempts.

Can I replay a Zoom webhook my server missed?

Not from Zoom. No redeliver control appears in the docs, and a delivery that exhausts the three retries is not sent again. The Get webhook logs API shows what was sent in the past seven days, but reading a log is not the same as receiving the event again.

Why isn't my Zoom app receiving deauthorization events?

Those don't go to your event notification endpoint at all. Zoom delivers them to a separate Deauthorization Notification Endpoint URL, and they only fire for publicly published apps — private apps and apps still in development do not trigger deauthorization notifications.

Point a webhook at it. Watch it land.

Start free: a permanent URL, full inspection, one-command replay — and outbound delivery, because every feature is on every plan. Move up when you need more events.