раздел 04

Вебхуки: события Zoom

Вебхук - это когда не вы спрашиваете Zoom, а Zoom сам присылает POST на ваш URL, как только что-то произошло. Не нужно опрашивать API по таймеру в надежде, что запись наконец готова - Zoom сообщит сам.

Зачем

  • recording.completed - облачная запись обработана и готова к скачиванию. Главное событие для пайплайнов вокруг записей.
  • meeting.started / meeting.ended - встреча началась или закончилась. Удобно для статусов и уведомлений.
  • Десятки других событий: участник вошёл, встреча создана, изменена и т.д.

Как настроить

1
Поднять endpoint
Публичный HTTPS-URL на вашем сервере, который принимает POST с JSON. Это адрес, куда Zoom будет слать события.
2
Указать его в приложении
В настройках приложения (вкладка Feature / Event Subscriptions) включите вебхуки, впишите URL и отметьте нужные события - например, recording.completed.
3
Пройти валидацию endpoint
Zoom проверит, что URL действительно ваш: пришлёт challenge, на который надо ответить корректно (см. ниже про secret token и CRC).
4
Обрабатывать события
Дальше на каждое событие приходит POST с телом, где есть тип события и данные. Разбирайте по полю event.

Валидация endpoint: secret token и CRC

У приложения есть secret token. При настройке (и периодически) Zoom шлёт на ваш URL событие проверки endpoint.url_validation с полем plainToken. Вы должны вернуть подтверждение: посчитать HMAC-SHA256 от plainToken на вашем secret token и отдать обратно plainToken и полученный хэш. Эта проверка называется CRC (challenge-response check). Без корректного ответа Zoom не активирует вебхук.

import hashlib
import hmac

SECRET_TOKEN = "..."  # из настроек приложения

def handle_validation(plain_token: str):
    signature = hmac.new(
        SECRET_TOKEN.encode(),
        plain_token.encode(),
        hashlib.sha256,
    ).hexdigest()
    return {"plainToken": plain_token, "encryptedToken": signature}

Пример тела события

Когда запись готова, на ваш endpoint придёт примерно такое (структура - идея, поля упрощены):

{
  "event": "recording.completed",
  "payload": {
    "account_id": "ACCOUNT_ID",
    "object": {
      "id": 123456789,
      "topic": "Демо для клиента",
      "recording_files": [
        {
          "file_type": "MP4",
          "download_url": "https://...",
          "status": "completed"
        }
      ]
    }
  }
}