# 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](/docs/api/meetings/#tag/cloud-recording/GET/meetings/{meetingId}/recordings). ### 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](/docs/api/meetings/#tag/meetings/GET/users/{userId}/meetings) endpoint to get a list of all the meetings that were held during the week, to then call the [Get meeting recordings](/docs/api/meetings/#tag/cloud-recording/GET/meetings/{meetingId}/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`](/docs/api/meetings/events/#tag/recording/POSTrecording.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](https://smartproxy.com/blog/curl-get-request) 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](/docs/api/meetings/#tag/cloud-recording/GET/meetings/{meetingId}/recordings) 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](/docs/api/meetings/#tag/cloud-recording/GET/meetings/{meetingId}/recordings) 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](/docs/api/meetings/events/#tag/recording/POSTrecording.transcript_completed) and [phone.recording_completed](/docs/api/phone/events/#tag/phone/POSTphone.recording_completed). - You can refer to the [this blog post](/blog/using-ngrok-to-receive-zoom-events/) "Using ngrok to receive Zoom Events\*\* if you are new to webhooks. Thanks for reading and using Zoom APIs!