Recall.ai has raised a $38M series B!
More resources
Filter by category
View all
Tutorials
Best Practices
Tutorials
Deep Dive
Zoom Developer Forum
.avif) Google Meet Developer Forum
Microsoft Teams Developer Forum
Announcements
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
\ A guide to programmatic screen capture on macOS\ \ Deep Dive](/content/blog/macos-screencapture-api/index.html)
\ Joining multiple simultaneous meetings through the Zoom SDK\ \ Zoom Developer Forum](/content/blog/zoom-sdk-simultaneous-meeting-limitations/index.html)
\ How to get transcripts from Microsoft Teams\ \ Tutorials](/content/blog/how-to-get-transcripts-from-microsoft-teams/index.html)
\ How to Get Recordings and Transcripts from Slack Huddles\ \ Tutorials](/content/blog/get-recordings-and-transcripts-from-slack-huddles-api/index.html)
\ Understanding the Zoom On Behalf Of (OBF) Token\ \ Deep Dive](/content/blog/zoom-obf/index.html)
\ What is a meeting bot?\ \ Deep Dive](/content/blog/what-is-a-meeting-bot/index.html)
\ Zoom SDK Credentials\ \ Deep Dive](/content/blog/zoom-sdk-credentials/index.html)
\ What is a Zoom Access Key (ZAK) token?\ \ Deep Dive](/content/blog/what-is-a-zoom-access-key-zak-token/index.html)
\ How WebSockets cost us $1M on our AWS bill\ \ Deep Dive](/content/blog/how-websockets-cost-us-1m-on-our-aws-bill/index.html)
\ The fix for a segfault that never shipped\ \ Deep Dive](/content/blog/the-fix-for-a-segfault-that-never-shipped/index.html)
\ Postgres Postmaster does not scale\ \ Deep Dive](/content/blog/postgres-postmaster-does-not-scale/index.html)
\ How to access audio streams in the Zoom Web SDK?\ \ Zoom Developer Forum](/content/blog/how-to-access-audio-streams-in-the-zoom-web-sdk/index.html)
\ How to determine if audio is connected on the Zoom Web SDK?\ \ Zoom Developer Forum](/content/blog/how-to-determine-if-audio-is-connected-on-the-zoom-web-sdk/index.html)
\ Recall.ai Series B: The API for Meeting Recording\ \ Announcements](/content/blog/recall-ai-series-b-the-api-for-meeting-recording/index.html)
\ How to build a Microsoft Teams Bot\ \ Tutorials](/content/blog/how-to-build-a-microsoft-teams-bot/index.html)
\ What is the Google Meet Media API?\ \ Best Practices](/content/blog/what-is-the-google-meet-media-api/index.html)
\ Postgres LISTEN/NOTIFY does not scale\ \ Deep Dive](/content/blog/postgres-listen-notify-does-not-scale/index.html)
\ Code Walkthrough: Generating Meeting Action Items With Recall.ai\ \ Tutorials](/content/blog/generating-meeting-action-items-with-recall-ai/index.html)
\ What are speaker labels and how to obtain them\ \ Tutorials](/content/blog/speaker-labels-and-names-explained/index.html)
\ 7 APIs to get Zoom transcripts: A comprehensive guide\ \ Best Practices](/content/blog/7-apis-to-get-zoom-transcripts-a-comprehensive-guide/index.html)
\ How to get transcripts from Zoom\ \ Tutorials](/content/blog/how-to-get-transcripts-from-zoom/index.html)
\ How to record Microsoft Teams\ \ Tutorials](/content/blog/how-to-get-recordings-from-microsoft-teams/index.html)
\ New Recall.ai Pricing for 2026: $0.50 per Hour of Meeting Recording\ \ Announcements](/content/blog/new-recall-ai-pricing-for-2026/index.html)
\ Open source Microsoft Teams recording software\ \ Microsoft Teams Developer Forum](/content/blog/microsoft-teams-recording-software-open-source/index.html)
\ How to pick a meeting note taker\ \ Best Practices](/content/blog/how-to-pick-a-meeting-note-taker/index.html)
\ How to Get a Recording from the Google Meet API\ \ Best Practices](/content/blog/how-to-get-a-recording-from-the-google-meet-api/index.html)
\ How to get Google Meet transcripts programmatically\ \ Best Practices](/content/blog/how-to-get-transcripts-from-google-meet-developer-edition/index.html)
\ What is Zoom RTMS?\ \ Best Practices](/content/blog/what-is-zoom-rtms/index.html)
\ How to build a desktop recording app (Like Granola)\ \ Tutorials](/content/blog/how-to-build-a-desktop-recording-app/index.html)
\ Speaker Diarization: What it is and how to get diarized transcripts\ \ Best Practices](/content/blog/speaker-diarization/index.html)
\ Understanding Zoom RTMS Behavior and Its Constraints\ \ Best Practices](/content/blog/understanding-zoom-rtms-behavior-and-its-constraints/index.html)
\ How to build a meeting notetaker\ \ Tutorials](/content/blog/how-to-build-a-meeting-notetaker/index.html)
\ How to build a meeting bot \ \ Tutorials](/content/blog/how-to-build-a-meeting-bot/index.html)
\ When to build a Microsoft Teams bot with Puppeteer\ \ Microsoft Teams Developer Forum](/content/blog/puppeteer-microsoft-teams-bot/index.html)
\ How to join a Zoom meeting using the Zoom Meeting SDK\ \ Zoom Developer Forum](/content/blog/how-to-join-a-zoom-meeting-using-the-zoom-meeting-sdk/index.html)
\ Microsoft Teams open source bot\ \ Microsoft Teams Developer Forum](/content/blog/microsoft-teams-open-source-bot/index.html)
\ How to Build a Google Meet Bot from Scratch\ \ Tutorials](/content/blog/how-i-built-an-in-house-google-meet-bot/index.html)
.avif)\ Is there open source Google Meet recording software?\ \ Google Meet Developer Forum](/content/blog/is-there-open-source-google-meet-recording-software/index.html)
.avif)\ Puppeteer Google Meet Bot\ \ Google Meet Developer Forum](/content/blog/puppeteer-google-meet-bot/index.html)
\ Zoom recording software open source\ \ Zoom Developer Forum](/content/blog/zoom-recording-software-open-source/index.html)
\ How to build a Chrome recording extension using tabCapture API\ \ Tutorials](/content/blog/how-to-build-a-chrome-recording-extension/index.html)
\ Zoom Signature Invalid\ \ Zoom Developer Forum](/content/blog/zoom-signature-invalid/index.html)
\ How to get automatic recordings from a Zoom bot\ \ Zoom Developer Forum](/content/blog/zoom-bot-automatic-recording/index.html)
\ Retrieving participant names through the Zoom SDK\ \ Zoom Developer Forum](/content/blog/zoom-sdk-retrieving-participant-names/index.html)
\ How to Access Live Transcription Data from Zoom Web SDK (Component View)\ \ Zoom Developer Forum](/content/blog/how-to-access-live-transcription-data-from-zoom-web-sdk-component-view/index.html)
\ How to build a Zoom bot from scratch\ \ Tutorials](/content/blog/how-to-build-a-zoom-bot/index.html)
\ Create a Google Meet Programmatically\ \ Tutorials](/content/blog/create-a-google-meet-programmatically/index.html)
\ How to join Zoom using Puppeteer\ \ Zoom Developer Forum](/content/blog/how-to-join-zoom-using-puppeteer/index.html)
\ Handling Zoom SDK recording permissions\ \ Zoom Developer Forum](/content/blog/zoom-sdk-recording-permissions/index.html)
\ How to Enable a Zoom Bot to Skip the Waiting Room\ \ Zoom Developer Forum](/content/blog/zoom-bot-skip-waiting-room/index.html)
\ How do I sync audio and video when processing raw audio/video from the Zoom SDK?\ \ Zoom Developer Forum](/content/blog/how-do-i-sync-audio-and-video-when-processing-raw-audio-video-from-the-zoom-sdk/index.html)
\ Fixing DLL warnings in the Zoom Windows Meeting SDK\ \ Zoom Developer Forum](/content/blog/fixing-dll-warnings-in-the-zoom-windows-meeting-sdk/index.html)
\ Zoom join tokens for local recording\ \ Best Practices](/content/blog/zoom-join-tokens-for-local-recording/index.html)
\ How to get recordings from Zoom using a Zoom recording bot API\ \ Tutorials](/content/blog/how-to-get-recordings-from-zoom/index.html)
\ How to manage ZAK Tokens for Zoom bots\ \ Zoom Developer Forum](/content/blog/how-to-manage-zak-tokens-for-zoom-bots/index.html)
\ How to build a Zoom notetaker\ \ Tutorials](/content/blog/how-to-build-a-zoom-notetaker/index.html)
\ Recall.ai Announces Participant Emails\ \ Announcements](/content/blog/recall-ai-announces-participant-emails/index.html)
\ How often should I expect to receive the Zoom recording completed webhook for a single meeting?\ \ Zoom Developer Forum](/content/blog/how-often-should-i-expect-to-receive-the-zoom-recording-completed-webhook-for-a-single-meeting/index.html)
\ Why are waiting rooms causing issues with the Zoom Web Meeting SDK?\ \ Zoom Developer Forum](/content/blog/why-are-waiting-rooms-causing-issues-with-the-zoom-web-meeting-sdk/index.html)
\ Why is my Zoom recording completed webhook so delayed?\ \ Zoom Developer Forum](/content/blog/why-is-my-zoom-recording-completed-webhook-so-delayed/index.html)
\ Why aren't transcription webhooks firing for my Zoom meetings?\ \ Zoom Developer Forum](/content/blog/why-arent-transcription-webhooks-firing-for-my-zoom-meetings/index.html)
\ How do I track participants across Zoom breakout rooms?\ \ Zoom Developer Forum](/content/blog/how-do-i-track-participants-across-zoom-breakout-rooms/index.html)
\ Can I identify meeting participants by email on Zoom?\ \ Zoom Developer Forum](/content/blog/can-i-identify-meeting-participants-by-email-on-zoom/index.html)
\ How do I capture participant data in real time on Zoom?\ \ Zoom Developer Forum](/content/blog/how-do-i-capture-participant-data-in-real-time-on-zoom/index.html)
\ Tracking persistent Zoom meeting ID's for participants who leave and rejoin\ \ Zoom Developer Forum](/content/blog/tracking-persistent-zoom-meeting-ids-for-participants-who-leave-and-rejoin/index.html)
\ Debugging issues with automatic cloud recording\ \ Zoom Developer Forum](/content/blog/debugging-issues-with-automatic-cloud-recording/index.html)
\ Tracking Zoom meetings when using Zoom PMI\ \ Zoom Developer Forum](/content/blog/tracking-zoom-meetings-when-using-zoom-pmi/index.html)
\ Encoding raw video from the Zoom SDK to MP4\ \ Zoom Developer Forum](/content/blog/encoding-raw-video-from-the-zoom-sdk/index.html)
\ Handling crashes in the Zoom Windows Meeting SDK\ \ Zoom Developer Forum](/content/blog/handling-crashes-in-the-zoom-windows-meeting-sdk/index.html)
\ Encoding raw video frames from the Zoom SDK to JPEG\ \ Zoom Developer Forum](/content/blog/decoding-raw-video-frames-from-the-zoom-sdk/index.html)
\ Recording meetings without a local recording token\ \ Zoom Developer Forum](/content/blog/recording-meetings-without-a-local-recording-token/index.html)
\ Resolving intermittent errors while downloading Zoom transcripts\ \ Zoom Developer Forum](/content/blog/resolving-intermittent-errors-while-downloading-zoom-transcripts/index.html)
\ Applying account-level settings to meetings created via the Zoom API\ \ Zoom Developer Forum](/content/blog/applying-account-level-settings-to-meetings-created-via-the-zoom-api/index.html)
\ Why can't my bot join meetings hosted by people outside of my Zoom organization?\ \ Zoom Developer Forum](/content/blog/why-cant-my-bot-join-meetings-hosted-by-people-outside-of-my-zoom-organization/index.html)
\ Zoom Cloud Recording API: Transcript Tutorial, Common Pitfalls, and Workarounds\ \ Tutorials](/content/blog/zoom-transcript-api/index.html)
\ Zoom Meeting Bots: What They Are and Solutions\ \ Deep Dive](/content/blog/zoom-bots/index.html)
\ Can I access gallery view video on the Linux SDK?\ \ Zoom Developer Forum](/content/blog/can-i-access-gallery-view-video-on-the-linux-sdk/index.html)
\ How to access the Zoom Archive Files API\ \ Zoom Developer Forum](/content/blog/how-to-access-the-zoom-archive-files-api/index.html)
\ Resolving Web SDK local recording errors\ \ Zoom Developer Forum](/content/blog/resolving-web-sdk-local-recording-errors/index.html)
\ How to resolve permissions errors with the Zoom Users API\ \ Zoom Developer Forum](/content/blog/how-to-resolve-permissions-errors-with-the-zoom-users-api/index.html)
\ How to track participant name changes in breakout rooms\ \ Zoom Developer Forum](/content/blog/how-to-track-participant-name-changes-in-breakout-rooms/index.html)
\ Why is the transcript.completed webhook not firing?\ \ Zoom Developer Forum](/content/blog/zoom-sdk-webhook-not-firing/index.html)
\ Debugging Zoom SDK failed video capture\ \ Zoom Developer Forum](/content/blog/zoom-sdk-debugging-video-capture/index.html)
\ Capturing video and audio streams through the Zoom SDK\ \ Zoom Developer Forum](/content/blog/zoom-sdk-receiving-video-streams/index.html)
\ Can you suppress the Zoom recording consent prompt through the SDK?\ \ Zoom Developer Forum](/content/blog/zoom-sdk-suppressing-consent-prompt/index.html)
\ How to stream video to a meeting through the Zoom SDK\ \ Zoom Developer Forum](/content/blog/zoom-sdk-streaming-video-to-meeting/index.html)
\ Sending chat messages through the Zoom SDK\ \ Zoom Developer Forum](/content/blog/zoom-sdk-sending-chat-messages/index.html)
\ Handling Zoom app OAuth redirect URL requirements\ \ Zoom Developer Forum](/content/blog/zoom-app-oauth-redirect-url-requirement/index.html)
\ Debugging missing Zoom transcription webhooks\ \ Zoom Developer Forum](/content/blog/zoom-sdk-missing-transcription-webhooks/index.html)
\ Handling Zoom SDK recording compliance requirements\ \ Zoom Developer Forum](/content/blog/zoom-sdk-compliance-requirements/index.html)
\ Handling Zoom app verification\ \ Zoom Developer Forum](/content/blog/zoom-app-domain-verification/index.html)
\ How to join registration-required meetings with a Zoom bot\ \ Zoom Developer Forum](/content/blog/zoom-sdk-joining-registration-required-meetings/index.html)
\ How to use a Zoom bot to join meetings without passcodes\ \ Zoom Developer Forum](/content/blog/zoom-sdk-joining-meetings-without-passcodes/index.html)
\ Debugging stuck Zoom SDK bots\ \ Zoom Developer Forum](/content/blog/zoom-sdk-docker-issues/index.html)
\ How to create a voice agent to send to Zoom meetings\ \ Zoom Developer Forum](/content/blog/zoom-sdk-ai-voice-agent/index.html)
\ How to capture Zoom audio and video with a meeting bot\ \ Zoom Developer Forum](/content/blog/create-audio-video-capture-bots/index.html)
\ How to transcribe a Zoom meeting in real time\ \ Zoom Developer Forum](/content/blog/accessing-real-time-transcription-api/index.html)
\ How to receive raw video from the Zoom SDK\ \ Zoom Developer Forum](/content/blog/accessing-host-video-stream/index.html)
\ Announcing the Recall.ai and Speechmatics Integration\ \ Announcements](/content/blog/announcing-the-recall-ai-and-speechmatics-integration/index.html)
\ Can I access raw audio data using the Zoom Web SDK?\ \ Zoom Developer Forum](/content/blog/can-i-access-raw-audio-data-using-the-zoom-web-sdk/index.html)
Tutorials
Zoom Cloud Recording API: Transcript Tutorial, Common Pitfalls, and Workarounds
Updated at:
October 24, 2025
Written By:
Vivek Sahu
Table of Contents
- Introduction
- Overview of steps
- Brief on Zoom Apps and OAuth2
- Pre-requisites
- Create a Server-to-Server OAuth App
- Start and complete a meeting
- Write code to fetch transcripts
- Limitations of the Zoom Cloud Recording API
- Workarounds
- Recommended alternatives
- Conclusion
- References
Introduction
Zoom provides a platform for video conferencing, but there are often scenarios where we need to access the transcripts of a recorded meeting. This could be useful for various purposes, such as sharing meeting notes over email, translating the meeting content into multiple languages, or analyzing and summarizing the discussion using advanced language models.
Fortunately, Zoom offers APIs that allow developers to retrieve transcripts for the recorded meetings, albeit with some limitations. However, the Zoom official documentation does not provide a detailed guide for using these APIs, or the caveats they come with.
In this article, we will explore the process of accessing these transcripts via Zoom's Cloud Recording API. We will cover the necessary setup, including creating a Zoom App and obtaining the required credentials, as well as providing a Python code example that demonstrates how to interact with the Zoom API to retrieve the meeting transcripts. We will also look into its limitations, some workarounds that can be employed, and quickly touch on a few alternatives.
Note that while we are using Python here, this can be easily translated into other languages with ease. At the heart of it, all we are doing is calling Zoom APIs. If you want to build a Zoom bot yourself, you can either start from scratch with our blog on how to build a zoom bot or check out our Zoom transcript API which works in just a few lines of code ( tutorial on how to get transcripts from Zoom).
Overview of steps
We will simply do 3 things:
- Create a Zoom App to allow access to some of their APIs
- Create and join a meeting with cloud recording enabled
- Programmatically fetch the audio transcripts using Python
Brief on Zoom Apps and OAuth2
Zoom employs the OAuth 2.0 protocol for authorizing access to its APIs. OAuth is an industry-standard authorization mechanism that allows applications to securely access resources on behalf of a user or service account without exposing sensitive credentials like passwords.
To access the Zoom APIs, you need to create a Server-to-Server OAuth app within the Zoom App Marketplace. This type of application is suitable for machine-to-machine communication, which is precisely what we need in this case.
Pre-requisites
- Zoom Paid Plan
- Python3 >= 3.3 installed in your system.
- If you are not the account admin, then your account should have:
- Permissions to view and edit Server-to-Server OAuth apps
- Permissions for scopes that you will add to the app . We will detail the scopes later in the article.
Create a Server-to-Server OAuth App
Follow these steps:
1. Let's go to the Zoom App Marketplace. Click on Develop and then click on Server-to-Server App.
2. Give a name to your app. In this example, we've called it MyTranscriptionApp. You can give it your own name. Click on Create.
3. You should now be in the App Credentials section:
Notice your Account ID, Client ID, and Client Secret in the App Credentials. These client values are specific to your app. When we make Zoom API calls later, we will use these.
4. Provide details in the Information section.
5. Next jump to Scopes. Here, we will be defining the scopes to which this app's tokens have access to. This in turn defines which APIs can be called using the token.
In this tutorial, we'll be using the following endpoints:
That means we'll need the following scopes, which Zoom mentions in the documentation for those endpoints:
cloud_recording:read:list_user_recordings:admincloud_recording:read:list_recording_files:admin
6. Next, go to the Activation section and click Activate your app. Your app won't provide the access_tokens without this step.
Before Activation:
After Activation:
Start and complete a meeting
Start a Zoom meeting. Ensure that you have enabled Cloud recording by expanding Options, checking the option for Automatically record meeting, and selecting the In the cloud radio button.
Join the meeting alone, or add more people. Talk for a couple of seconds during the meeting, and then end the meeting.
It will take a few minutes for the recording to show up as Zoom needs to process it. For this article, we'll monitor the Recordings Tab for the recording.
You can also use the
recording.transcript_completedwebhook event to be notified when the recording transcript is available.
Write code to fetch transcripts
Now that we've set up our Server-to-Server OAuth App and completed a meeting, let's write code to fetch details from the Zoom API.
In this section, we'll create a Zoom SDK Python Client that can interact with the Zoom API to fetch transcripts.
Create a Zoom SDK Client
We'll create a simple Zoom SDK Client.
1$ mkdir my-zoom-sdk-client
2$ cd my-zoom-sdk-client
3$ python3 -m venv venv
4$ source venv/bin/activate
5$ echo"requests" >> requirements.txt
6$ pip install -r requirements.txt
Create a file called main.py and copy the following code:
1"""
2MyZoomSDKClient
3"""
4import requests
5
6
7classMyZoomSDKClient:
8
9# Initialize the client with account_id, client_id, and client_secret
10def__init__(self, client_id, client_secret, account_id):
11 self.client_id = client_id
12 self.client_secret = client_secret
13 self.account_id = account_id
14 self.access_token = None
15
16# Generate a new access token only if one does not exist, or if the user explicitly asks to generate
17# (using 'force=True' means generating a new token)
18defget_access_token(self, force=False):
19if self.access_token andnot force:
20return self.access_token
21
22 access_token_uri = "https://zoom.us/oauth/token"
23 data = {
24"grant_type": "account_credentials",
25"account_id": self.account_id,
26"client_id": self.client_id,
27"client_secret": self.client_secret
28 }
29 response = self._make_request(access_token_uri, data=data, method='POST')
30return response.json()["access_token"]
31
32def_make_request(self, uri, headers=None, method='GET', data=None):
33try:
34if method == 'POST':
35 response = requests.post(uri, headers=headers, data=data)
36else:
37 response = requests.get(uri, headers=headers)
38
39if response.status_code // 100 != 2:
40raise Exception('Invalid response from Zoom API. Please try again later.')
41return response
42except Exception as e:
43raise Exception('Invalid response from Zoom API. Please try again later. Error Message: ' + str(e))
... See all 43 lines
__init__simply initializes our client with the account_id, client_id and client_secret.(Remember we saw these earlier in Step 3 in theCreate a Server-to-Server OAuth Appsection?)_make_requestis just a utility function that allows us to call any REST APIs.get_access_tokengenerates a new access token by calling the Zoom OAuth API.forceis a simple maneuver to ensure a newaccess_tokenis generated instead of reusing the earlieraccess_token.access_tokens expire after a certain time.
Let's see if all works well.
1$ python3
2>>> CLIENT_ID=''# Put your Client ID
3>>> CLIENT_SECRET=''# Put your CLIENT_SECRET
4>>> ACCOUNT_ID=''# Put your ACCOUNT_ID
5>>> from main import MyZoomSDKClient
6>>> client = MyZoomSDKClient(CLIENT_ID, CLIENT_SECRET, ACCOUNT_ID)
7>>> access_token = client.get_access_token()
8>>> print(access_token)
9>>> exit()
List all meetings
We'll modify the code to access the List Recordings API.
1GET /users/{userId}/recordings
Update main.py to call List Meetings and return parsed data. Use the following code:
1#...
2# Generate authorization header using access_token
3defget_authorization_header(self):
4return { "Authorization": f"Bearer {self.get_access_token()}" }
5
6# List id and topic of all my meetings
7deflist_my_meetings(self):
8 list_meetings_uri = "https://api.zoom.us/v2/users/me/recordings"
9 headers = self.get_authorization_header()
10
11 response = self._make_request(list_meetings_uri, headers=headers)
12return [(x['id'], x['topic']) for x in response.json()['meetings']]
13#...
... See all 13 lines
Let's see it in action:
1$ python3
2>>> CLIENT_ID=''# Put your Client ID
3>>> CLIENT_SECRET=''# Put your CLIENT_SECRET
4>>> ACCOUNT_ID=''# Put your ACCOUNT_ID
5>>> from main import MyZoomSDKClient
6>>> client = MyZoomSDKClient(CLIENT_ID, CLIENT_SECRET, ACCOUNT_ID)
7>>> meetings = client.list_my_meetings()
8>>> print(meetings)
9>>> exit()
Get Meeting Details
Let's modify the code to access the Get Recording API.
1GET "/meetings/{meetingId}/recordings"
Update main.py to add the following function:
1#...
2# Get meeting details by ID
3defget_meeting_details(self, meeting_id):
4if meeting_id in self.meetings:
5return self.meetings[meeting_id]
6
7 meeting_details_url = f"https://api.zoom.us/v2/meetings/{meeting\_id}/recordings"
8 headers = self.get_authorization_header()
9
10 self.meetings[meeting_id] = self._make_request(meeting_details_url, headers=headers).json()
11return self.meetings[meeting_id]
12#...
... See all 12 lines
Also, add this new property to the client:
1classMyZoomSDKClient:
2
3# Initialize the client with account_id, client_id, and client_secret
4def__init__(self, client_id, client_secret, account_id):
5# ...
6 self.meetings = {}
Let's run this code to get our meeting details:
1$ python3
2>>> CLIENT_ID=''# Put your Client ID
3>>> CLIENT_SECRET=''# Put your CLIENT_SECRET
4>>> ACCOUNT_ID=''# Put your ACCOUNT_ID
5>>> from main import MyZoomSDKClient
6>>> client = MyZoomSDKClient(CLIENT_ID, CLIENT_SECRET, ACCOUNT_ID)
7>>> meetings = client.list_my_meetings()
8>>> my_meeting = client.get_meeting_details(meetings[0][0])
9>>> print(my_meeting)
10>>> exit()
Get Transcriptions
Finally, let's add the following code to fetch the transcripts. Transcripts are available as part of the Get Recording API. The API response contains a recording_files property which contains all the download_urls for video recordings, audio recordings, transcripts, and more. We can check the recording_type to find the type of recording. We are interested in the audio_transcript as recording_type.
Modify main.py to add the following function:
1#...
2# Get audio transcript for a given meeting
3defget_audio_transcript(self, meeting_id):
4 meeting_details = self.get_meeting_details(meeting_id)
5
6 aud_ts_uri = [i['download_url'] for i in meeting_details['recording_files'] if i['recording_type']=='audio_transcript'][0]
7 headers = self.get_authorization_header()
8
9 response = self._make_request(aud_ts_uri, headers=headers)
10# response.content contains audio transcript in bytes, so we need to decode it to understand the content.
11 decoded_content = response.content.decode("utf-8")
12 final_formatted_content = decoded_content.strip().split('\r\n\r') # format content
13
14# Print the audio transcript
15for line in final_formatted_content: print(line)
16#...
... See all 16 lines
Let's run the following to fetch the transcripts:
1$ python3
2>>> CLIENT_ID=''# Put your Client ID
3>>> CLIENT_SECRET=''# Put your CLIENT_SECRET
4>>> ACCOUNT_ID=''# Put your ACCOUNT_ID
5>>> from main import MyZoomSDKClient
6>>> client = MyZoomSDKClient(CLIENT_ID, CLIENT_SECRET, ACCOUNT_ID)
7>>> meetings = client.list_my_meetings()
8>>> client.get_audio_transcript(meetings[0][0])
This is an example output. Your output should be in a similar format:
1...
2WEBVTT
3
41
500:00:16.239 --> 00:00:27.079
6John: Hi, this is a testfor audio transcripts.
7
82
900:00:28.079 --> 00:00:30.239
10Wewake: I am going to say.
11
123
1300:00:30.869 --> 00:00:32.329
14Wewake: a few words.
15
164
1700:00:32.629 --> 00:00:41.649
18Wewake: I expect this to be recorded and available to me later.
19
205
2100:00:44.779 --> 00:00:46.509
22Wewake: That is it.
23
246
2500:00:52.219 --> 00:00:54.909
26Wewake: So simple.
27
287
2900:00:56.319 --> 00:01:00.269
30Wewake: We are done.
31
328
3300:01:00.749 --> 00:01:01.629
34Wewake: Bye.
... See all 34 lines
Bonus: Closed Caption
We can also retrieve the closed captions from the recording_files. For this, we would need to enable closed caption during the meeting. Here is the code to fetch it:
1#...
2# Get closed captions
3defget_closed_captions(self, meeting_id):
4 meeting_details = self.get_meeting_details(meeting_id)
5
6 cc_uri = [i['download_url'] for i in meeting_details['recording_files'] if i['recording_type']=='closed_caption'][0]
7 headers = self.get_authorization_header()
8
9 response = self._make_request(cc_uri, headers=headers)
10
11# response.content contains closed caption in bytes, so we need to decode it to understand the content.
12 decoded_content = response.content.decode("utf-8")
13 final_formatted_content = decoded_content.strip().split('\r\n\r') # format content
14
15# Print the closed captions
16for line in final_formatted_content: print(line)
17#...
... See all 17 lines
Run it:
1$ python3
2>>> CLIENT_ID=''# Put your Client ID
3>>> CLIENT_SECRET=''# Put your CLIENT_SECRET
4>>> ACCOUNT_ID=''# Put your ACCOUNT_ID
5>>> from main import MyZoomSDKClient
6>>> client = MyZoomSDKClient(CLIENT_ID, CLIENT_SECRET, ACCOUNT_ID)
7>>> meetings = client.list_my_meetings()
8>>> client.get_closed_captions(meetings[0][0])
Complete Code for the Zoom Client
1"""
2MyZoomSDKClient
3
4Simple Zoom SDK to get access_token, recordings, transcripts, and closed captions.
5for a Zoom meeting (with cloud recording). Requires client_id, client_secret and account_id
6"""
7import requests
8
9
10classMyZoomSDKClient:
11
12# Initialize the client with account_id, client_id, and client_secret
13def__init__(self, client_id, client_secret, account_id):
14 self.client_id = client_id
15 self.client_secret = client_secret
16 self.account_id = account_id
17 self.access_token = None
18 self.meetings = {}
19
20# Generate a new access token only if one does not exist, or if the user explicitly asks to generate
21# (using 'force=True' means generating a new token)
22defget_access_token(self, force=False):
23if self.access_token andnot force:
24return self.access_token
25
26 access_token_uri = "https://zoom.us/oauth/token"
27 data = {
28"grant_type": "account_credentials",
29"account_id": self.account_id,
30"client_id": self.client_id,
31"client_secret": self.client_secret
32 }
33 response = self._make_request(access_token_uri, data=data, method='POST')
34return response.json()["access_token"]
35
36# Generate authorization header using access_token
37defget_authorization_header(self):
38return { "Authorization": f"Bearer {self.get_access_token()}" }
39
40# List id and topic of all my meetings
41deflist_my_meetings(self):
42 list_meetings_uri = "https://api.zoom.us/v2/users/me/recordings"
43 headers = self.get_authorization_header()
44
45 response = self._make_request(list_meetings_uri, headers=headers)
46return [(x['id'], x['topic']) for x in response.json()['meetings']]
47
48# Get meeting details by ID
49defget_meeting_details(self, meeting_id):
50if meeting_id in self.meetings:
51return self.meetings[meeting_id]
52
53 meeting_details_url = f"https://api.zoom.us/v2/meetings/{meeting\_id}/recordings"
54 headers = self.get_authorization_header()
55
56 self.meetings[meeting_id] = self._make_request(meeting_details_url, headers=headers).json()
57return self.meetings[meeting_id]
58
59# Get audio transcript for a given meeting
60defget_audio_transcript(self, meeting_id):
61 meeting_details = self.get_meeting_details(meeting_id)
62
63 aud_ts_uri = [i['download_url'] for i in meeting_details['recording_files'] if i['recording_type']=='audio_transcript'][0]
64 headers = self.get_authorization_header()
65
66 response = self._make_request(aud_ts_uri, headers=headers)
67# response.content contains audio transcript in bytes, so we need to decode it to understand the content.
68 decoded_content = response.content.decode("utf-8")
69 final_formatted_content = decoded_content.strip().split('\r\n\r') # format content
70
71# Print the audio transcript
72for line in final_formatted_content: print(line)
73
74
75# Get closed captions
76defget_closed_captions(self, meeting_id):
77 meeting_details = self.get_meeting_details(meeting_id)
78
79 cc_uri = [i['download_url'] for i in meeting_details['recording_files'] if i['recording_type']=='closed_caption'][0]
80 headers = self.get_authorization_header()
81
82 response = self._make_request(cc_uri, headers=headers)
83
84# response.content contains closed caption in bytes, so we need to decode it to understand the content.
85 decoded_content = response.content.decode("utf-8")
86 final_formatted_content = decoded_content.strip().split('\r\n\r') # format content
87
88# Print the closed captions
89for line in final_formatted_content: print(line)
90
91def_make_request(self, uri, headers=None, method='GET', data=None):
92try:
93if method == 'POST':
94 response = requests.post(uri, headers=headers, data=data)
95else:
96 response = requests.get(uri, headers=headers)
97
98if response.status_code // 100 != 2:
99raise Exception('Invalid response from Zoom API. Please try again later.')
100return response
101except Exception as e:
102raise Exception('Invalid response from Zoom API. Please try again later. Error Message: ' + str(e))
... See all 102 lines
Limitations of the Zoom Cloud Recording API
You might have noticed how we made some specific choices when we created the Zoom App to get transcription. This is because the native Zoom APIs have several limitations:
1. You need to be on a Paid Plan
The Zoom account hosting the meeting must be on the Pro, Business, or Enterprise tier. The free Basic plan will not work.
2. You need to enable Zoom Cloud Recording
Transcripts are only produced if the user records their meeting using Zoom Cloud Recording (not Zoom local recording). Zoom also has live captions that appear without recording the meeting, but it does not produce a transcript file after the call unless the meeting is being recorded.
3. Only the Meeting Host can access the transcript
The recorded meeting is only stored in the host's account, so other users cannot access the meeting and transcript details.
4. Meeting Host must enable recording settings for the transcript to be generated
The audio transcript feature in Zoom is disabled by default. You must enable this setting in Zoom for transcription to be produced.
5. Not accessible without elevated plan
Users must be on a paid plan to access recording/transcribing with Zoom natively.
6. Transcripts can take a long time to become available
After the meeting has ended, it typically takes about 2 times the duration of the recorded meeting for all the recordings to be available. For example, the transcript of a 30 minute long meeting will be available 1 hour after the meeting is done. Depending on the load on Zoom's servers, processing time can take up to 24 hours.
7. Transcripts are not available in real-time
Zoom Cloud transcripts are only available after the meeting is done, so you won’t be able to get the transcription in real-time.
Workarounds
To workaround the above limitations, there are a few options:
Workaround 1: Use the Zoom RTMP Live-Streaming API
Zoom allows Live Streaming the meeting to custom apps, using the Real-Time Messaging Protocol (RTMP) protocol. This allows you to use a custom app to fetch the audio of the meeting. This audio can then be piped to any 3rd-party transcription service to get real-time transcripts.
Advantages:
- You get real-time transcripts.
- You can get transcripts in any language.
Disadvantages:
- The setup is more complex. You need to set up a live-streaming server.
- You also need to integrate with a 3rd-party service for transcription, which can add to the cost and complexity.
- This also requires a Zoom paid plan.
- This also requires you to be the host.
Workaround 2: Build a Zoom Meeting Bot
Zoom allows meeting bots to access the video and audio contents of the meetings.
Advantages:
- You can get real-time transcripts.
- You don't need a paid Zoom plan.
- You don't need to be the host to access transcriptions.
Disadvantages:
- Developing a meeting bot is quite complex since Zoom does not provide an API to call to build one.
- There is a scale problem. Meeting bots require a separate instance of a Zoom client for each meeting. As the amount of meetings grows, this can become extremely difficult to manage. Also, it may blow up the infrastructure costs. It typically takes 6-12 months to build a stable meeting bot in its most basic form.
- You need to build separate integrations for each platform that you want to support. Your Zoom integration will look different from your Google Meet integration which will differ from your Microsoft Teams integration. They each come with their own set of edge cases and required maintanence.
Recommended alternatives
Recall.ai's Zoom Meeting Bot API, allows you to access transcripts, recordings, meeting metadata, and more across all major platforms. This means that you do not need to build or maintain integrations with each platform nor do your customers have to have elevated plans on each platform. Recall.ai handles all of the scaling, adapts to changes that the meeting platforms make, and deals with every edge case. The user just needs to add a few lines of code to launch a bot and then either retrieve the data after the call is over or specifying real-time data. We've got tutorials on how to get transcripts from Zoom and how to get recordings from Zoom using Recall.ai or you can get started with our Zoom Meeting Bot API today. Our API allows users to add the same functionality to Google Meet, Microsoft Teams, and more simply by changing the meeting url that is passed to the create bot endpoint.
If the bot form factor doesn't work for your use case, you might benefit from a Desktop Recording SDK. A deskop SDK allows you to gather conversation data in your app. It should be noted that with a desktop SDK you will need to figure out your own consent flow. With Recall.ai's Desktop Recording SDK you get real-time and post-call data just as a meeting bot would provide.
Conclusion
We looked at how to programmatically access Zoom transcripts using the Zoom API, several limitations of the Zoom API, and workarounds you can use to overcome those limitations. If you need a Zoom transcript API and Zoom recording API rolled into one, Recall.ai is the answer.
References
- Recall.ai
- OAuth 2.0 protocol
- Server-to-Server OAuth app
- Zoom App Marketplace
- Get Recording API
- List Recordings API
- Zoom Live Streaming API
- Zoom Live Streaming SDK
- Zoom meeting bots
Written By:
Vivek Sahu
Table of Contents
The API to get transcripts, recordings, and metadata from meetings.
Need help? Email us at support@recall.ai
Get transcripts, recordings and metadata from meetings
Product
Meeting Bot API\ \ \ example Desktop Recording SDK\ \ \ example Mobile Recording SDK\ \ \ example Calendar Integration\ \ \ example Storage and Playback\ \ \ example
Company
Careers\ \ \ We're hiring! Blog\ \ \ example Case Studies\ \ \ example
Security
Security Portal\ \ \ example SOC 2\ \ \ example ISO 27001\ \ \ example HIPAA\ \ \ example GDPR\ \ \ example CCPA\ \ \ example
Legal
Privacy\ \ \ We're hiring! Terms of Use\ \ \ We're hiring!
Resources
API Docs\ \ \ example Pricing\ \ \ example Notetaker API\ \ \ example Meeting Recording API\ \ \ example Transcription API\ \ \ example Meeting Transcription API\ \ \ example Compliance Recording API\ \ \ example Speaker Diarization API\ \ \ example Slack Huddles API\ \ \ example
Compare
Recall.ai vs Attendee\ \ \ example Recall.ai vs Meeting BaaS\ \ \ example Recall.ai vs Nylas Notetaker\ \ \ example Recall.ai vs Skribby\ \ \ example
More
Meeting Bots
Google Meet Bot API\ \ \ example Microsoft Teams Bot API\ \ \ example Zoom Meeting Bot API\ \ \ example
Recording
Google Meet Recording API\ \ \ example Microsoft Teams Recording API\ \ \ example Zoom Meeting Recording API\ \ \ example
Transcription
Google Meet Transcription API\ \ \ example Microsoft Teams Transcription API\ \ \ example Zoom Meeting Transcription API\ \ \ example