Markdown

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