Zoom Meeting API querying tips - Download recordings using webhooks

Welcome back to the Zoom API querying tips series, where we take a deep dive into the world of Zoom APIs.

In this specific blog post, we're going review using webhooks to access and download cloud recordings as an alternative to the cloud recording endpoints.

Download recordings using webhooks

When subscribed, you can use Zoom webhooks as a medium to notify third-party applications about events that occur within a Zoom account. In many cases, you can get the same data you would get from Zoom APIs from webhooks, but without querying the API directly.

Here is a sample use case:

Imagine you have a series of meetings that happen every day and you record all of those meetings in the cloud.

By the end of the week, instead of making multiple API calls to List meetings endpoint to get a list of all the meetings that were held during the week, to then call the Get meeting recordings endpoint to get the recordings for each meeting, you can set up a subscription in your application to listen to the event meeting.recordings.completed and this event will be triggered everytime a meeting is recorded, and the recording is ready to download.

So once a recording is ready, you will receive a payload event with a download url and download token generated upon recording completion, and you will be able to download the recording as soon as it is complete and store it in your preferred location.

Here is an example of a payload received after a meeting recording was processed:

{
  "payload": {
    "account_id": "account_id",
    "object": {
      "uuid": "WEz4RT2lSyKx2MD9Z+lYfA==",
      "id": 87565330005,
      "account_id": "account_id",
      "host_id": "host_id",
      "topic": "Recordings download URL/access token 01",
      "type": 2,
      "start_time": "2023-12-01T20:01:56Z",
      "timezone": "America/New_York",
      "host_email": "elisa@tests.com",
      "duration": 1,
      "total_size": 3500663,
      "recording_count": 3,
      "share_url": "https://us02web.zoom.us/rec/share/ZUrD3XZS2qn5nW5IZLynVU",
      "recording_files": [
        {
          "id": "23e2a1b0-b119-4262-a0e4-8eaeecad8b5f",
          "meeting_id": "WEz4RT2lSyKx2MD9Z+lYfA==",
          "recording_start": "2023-12-01T20:02:05Z",
          "recording_end": "2023-12-01T20:03:14Z",
          "file_type": "M4A",
          "file_extension": "M4A",
          "file_size": 1107341,
          "play_url": "https://us02web.zoom.us/rec/play/14q-E-5ZFajTKl7vOJtEeWYUjjogV",
          "download_url": "https://us02web.zoom.us/rec/webhook_download/14q-E-JtEehWe",
          "status": "completed",
          "recording_type": "audio_only"
        },
        {
          "id": "4608677c-357d-439d-bbec-64bb69f5a9da",
          "meeting_id": "WEz4RT2lSyKx2MD9Z+lYfA==",
          "recording_start": "2023-12-01T20:02:05Z",
          "recording_end": "2023-12-01T20:03:14Z",
          "file_type": "MP4",
          "file_extension": "MP4",
          "file_size": 1285981,
          "play_url": "https://us02web.zoom.us/rec/play/1V_tamcytBlEGFy49aEe-YbJDejjF9",
          "download_url": "https://us02web.zoom.us/rec/webhook_download/1V_tamcytBlE9U",
          "status": "completed",
          "recording_type": "shared_screen_with_speaker_view"
        }
      ],
      "password": "password",
      "participant_audio_files": [
        {
          "id": "f47b467c-0cc3-49bf-b45d-f309beda9b1c",
          "recording_start": "2023-12-01T20:02:05Z",
          "recording_end": "2023-12-01T20:03:14Z",
          "file_name": "Audio only - Elisa L",
          "file_type": "M4A",
          "file_extension": "M4A",
          "file_size": 1107341,
          "play_url": "https://us02web.zoom.us/rec/play/yz-n0_izlWqOZ-MQu_5eWHG5-WOz7CF",
          "download_url": "https://us02web.zoom.us/rec/webhook_download/yz-n0_izlWqO97Q",
          "status": "completed"
        }
      ],
      "recording_play_passcode": "passcode",
      "on_prem": false
    }
  },
  "event_ts": 1701461193266,
  "event": "recording.completed",
  "download_token": "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJodHRwczovL2V2ZW50Lnpvb20udXMiLCJhY2NvdW50SWQiOiJsS2hrVklqTlN1eWxoQ1JIczduWnp3IiwiYXVkIjoiaHR0cHM6Ly9vYXV0aC56b29tLnVzIiwibWlkIjoiV0V6NFJUMmxTeUt4Mk1EOVorbFlmQT09IiwiZXhwIjoxNzAxNTQ3NjA4LCJ1c2VySWQiOiI2R3RkaGVaUVNxLWwySmxGVzZ2TEZ3In0.1MTJIH2WB0r1BjyzMd95hg1cnLvG-vGBjqxq1DlY976xIkcqs1P0wvOy9lEaENuHjcePfMvjsepH5mTUkqnDBw"
}

Take note that this payload includes various URLs that would be helpful for you:

  • share_url
  • play_url
  • download_url

Additionally, within this event, you will also receive a download_token. This token can be used in conjunction with the download_url to programmatically download the recording file that you want.

Here is a sample curl command using the download_url and download_token that were included in the payload from the event, using the download_token as a bearer token in the authorization header of your HTTP request:

curl --location --request GET '{download_url}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {download_token}' \
--output '/path/to/download.file'

It is important to be aware that the download_token expires after 24 hours so if for any reason, 24 hours have passed after you receive the event and you need to download the recording, you will have query the Get a meeting recording endpoint to do so.

Here is a sample response from the Get meeting recordings endpoint, and you will note how you also get a share_url, play_url and download_url but there is no download_token available in the response:

GET https://api.zoom.us/v2/meetings/87565330005/recordings

{
   "uuid": "WEz4RT2lSyKx2MD9Z+lYfA==",
   "id": 87565330005,
   "account_id": "account_id",
   "host_id": "host_id",
   "topic": "Recordings download URL/access token 01",
   "type": 2,
   "start_time": "2023-12-01T20:01:56Z",
   "timezone": "America/New_York",
   "host_email": "elisa@tests.com",
   "duration": 1,
   "total_size": 3500663,
   "recording_count": 3,
   "share_url": "https://us02web.zoom.us/rec/share/lYLZz5bRCcmgX4",
   "recording_files": [
       {
           "id": "4608677c-357d-439d-bbec-64bb69f5a9da",
           "meeting_id": "WEz4RT2lSyKx2MD9Z+lYfA==",
           "recording_start": "2023-12-01T20:02:05Z",
           "recording_end": "2023-12-01T20:03:14Z",
           "file_type": "MP4",
           "file_extension": "MP4",
           "file_size": 1285981,
           "play_url": "https://us02web.zoom.us/rec/play/3lwWGTDTAhGxP-mY.0DJ5iuk",
           "download_url": "https://us02web.zoom.us/rec/download/3lwWGTDTAhGO9UHg",
           "status": "completed",
           "recording_type": "shared_screen_with_speaker_view"
       },
       {
           "id": "23e2a1b0-b119-4262-a0e4-8eaeecad8b5f",
           "meeting_id": "WEz4RT2lSyKx2MD9Z+lYfA==",
           "recording_start": "2023-12-01T20:02:05Z",
           "recording_end": "2023-12-01T20:03:14Z",
           "file_type": "M4A",
           "file_extension": "M4A",
           "file_size": 1107341,
           "play_url": "https://us02web.zoom.us/rec/play/DZlLSgH.acHBoC5yq_fP4U",
           "download_url": "https://us02web.zoom.us/rec/download/DXrozLSgH.acHBC",
           "status": "completed",
           "recording_type": "audio_only"
       }
   ],
   "password": "password",
   "participant_audio_files": [
       {
           "id": "f47b467c-0cc3-49bf-b45d-f309beda9b1c",
           "recording_start": "2023-12-01T20:02:05Z",
           "recording_end": "2023-12-01T20:03:14Z",
           "file_name": "Audio only - Elisa L",
           "file_type": "M4A",
           "file_extension": "M4A",
           "file_size": 1107341,
           "play_url": "https://us02web.zoom.us/rec/play/exMIYj5UJf1KveYmRVRdlhv",
           "download_url": "https://us02web.zoom.us/rec/download/exMIYj5UJCmarhv",
           "status": "completed"
       }
   ],
   "recording_play_passcode": "passcode"
}

In order to programmatically download a recording using the fields received in the response body from the API, you will need to generate an Oauth access_token and pass it down in the Authorization header:

curl --location --request GET '{download_url}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {access_token}' \
--output '/path/to/download.file'

Important to keep in mind:

  • To have access to cloud recordings, a Pro or higher account plan is required.
  • The download_token received from webhook events, expire after 24 hours.
  • Use the Get meeting recordings endpoint to get the download_url after 24 hours with an Oauth access token.
  • The same behavior occurs for other events where there is a download_token in the payload response, such as recording.transcript.completed and phone.recording_completed.
  • You can refer to the this blog post "Using ngrok to receive Zoom Events** if you are new to webhooks.

Thanks for reading and using Zoom APIs!