[Recall.ai has raised a $38M series B!](/content/blog/recall-ai-series-b-the-api-for-meeting-recording/index.html)

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)

[Go To Blog](/content/blog/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](/content/blog/zoom-transcript-api#introduction/index.html)
- [Overview of steps](/content/blog/zoom-transcript-api#overview-of-steps/index.html)
- [Brief on Zoom Apps and OAuth2](/content/blog/zoom-transcript-api#brief-on-zoom-apps-and-oauth2/index.html)
- [Pre-requisites](/content/blog/zoom-transcript-api#pre-requisites/index.html)
- [Create a Server-to-Server OAuth App](/content/blog/zoom-transcript-api#create-a-server-to-server-oauth-app/index.html)
- [Start and complete a meeting](/content/blog/zoom-transcript-api#start-and-complete-a-meeting/index.html)
- [Write code to fetch transcripts](/content/blog/zoom-transcript-api#write-code-to-fetch-transcripts/index.html)
  - [Create a Zoom SDK Client](/content/blog/zoom-transcript-api#create-a-zoom-sdk-client/index.html)
  - [List all meetings](/content/blog/zoom-transcript-api#list-all-meetings/index.html)
  - [Get Meeting Details](/content/blog/zoom-transcript-api#get-meeting-details/index.html)
  - [Get Transcriptions](/content/blog/zoom-transcript-api#get-transcriptions/index.html)
  - [Bonus: Closed Caption](/content/blog/zoom-transcript-api#bonus-closed-caption/index.html)
  - [Complete Code for the Zoom Client](/content/blog/zoom-transcript-api#complete-code-for-the-zoom-client/index.html)
- [Limitations of the Zoom Cloud Recording API](/content/blog/zoom-transcript-api#limitations-of-the-zoom-cloud-recording-api/index.html)
- [Workarounds](/content/blog/zoom-transcript-api#workarounds/index.html)
  - [Workaround 1: Use the Zoom RTMP Live-Streaming API](/content/blog/zoom-transcript-api#workaround-1-use-the-zoom-rtmp-live-streaming-api/index.html)
  - [Workaround 2: Build a Zoom Meeting Bot](/content/blog/zoom-transcript-api#workaround-2-build-a-zoom-meeting-bot/index.html)
- [Recommended alternatives](/content/blog/zoom-transcript-api#recommended-alternatives/index.html)
- [Conclusion](/content/blog/zoom-transcript-api#conclusion/index.html)
- [References](/content/blog/zoom-transcript-api#references/index.html)

## Introduction

[Zoom](https://zoom.us/) 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](/content/blog/how-to-build-a-zoom-bot/index.html) or check out our [Zoom transcript API](/content/product/meeting-bot-api/zoom/index.html) which works in just a few lines of code ( [tutorial on how to get transcripts from Zoom](/content/blog/how-to-get-transcripts-from-zoom/index.html)).

## Overview of steps

We will simply do 3 things:

- [Create a Zoom App to allow access to some of their APIs](/content/blog/zoom-transcript-api#create-a-Server-to-Server-oauth-app/index.html)
- [Create and join a meeting with cloud recording enabled](/content/blog/zoom-transcript-api#start-and-complete-a-meeting/index.html)
- [Programmatically fetch the audio transcripts using Python](/content/blog/zoom-transcript-api#write-code-to-fetch-transcripts/index.html)

## Brief on Zoom Apps and OAuth2

Zoom employs the [OAuth 2.0 protocol](https://auth0.com/intro-to-iam/what-is-oauth-2) 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](https://developers.zoom.us/docs/internal-apps/create/) 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](https://zoom.us/pricing)
- [Python3](https://www.python.org/downloads/) >= 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](https://developers.zoom.us/docs/internal-apps/#enable-the-server-to-server-oauth-role)
- [Permissions for scopes that you will add to the app](https://developers.zoom.us/docs/internal-apps/#assign-permissions-to-access-scopes) . 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](https://marketplace.zoom.us/). 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:

- [List Meetings](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingsList)
- [Get Meetings and its recordings](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingGet).

That means we'll need the following scopes, which Zoom mentions in the documentation for those endpoints:

- `cloud_recording:read:list_user_recordings:admin`
- `cloud_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](https://us06web.zoom.us/meeting#/upcoming). 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](https://us06web.zoom.us/recording) for the recording.

> You can also use the [`recording.transcript_completed`](https://developers.zoom.us/docs/api/meetings/events/#tag/recording/POSTrecording.transcript_completed) webhook 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 the `Create a Server-to-Server OAuth App` section?)
- `_make_request` is just a utility function that allows us to call any REST APIs.
- `get_access_token` generates a new access token by calling the Zoom OAuth API. `force` is a simple maneuver to ensure a new `access_token` is generated instead of reusing the earlier `access_token`. `access_token`s 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**](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingsList) 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**](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingGet) 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**](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingGet) 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](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetingLiveStreamUpdate) 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

1. Recall.ai's [Zoom Meeting Bot API](/content/product/meeting-bot-api/zoom/index.html), 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](/content/blog/how-to-get-transcripts-from-zoom/index.html) and [how to get recordings from Zoom](/content/blog/how-to-get-recordings-from-zoom/index.html) using Recall.ai or you can get started with our [Zoom Meeting Bot API](/content/product/meeting-bot-api/zoom/index.html) 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.

2. If the bot form factor doesn't work for your use case, you might benefit from a [Desktop Recording SDK](/content/product/desktop-recording-sdk/index.html). 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](/content/product/meeting-bot-api/zoom/index.html) and [Zoom recording API](/content/product/meeting-bot-api/zoom/index.html) rolled into one, Recall.ai is the answer.

## References

- [Recall.ai](/content/?utm_source=recall.ai&utm_medium=blog_references&utm_campaign=zoom_transcript_api_tutorial&utm_content=Recall.ai)
- [OAuth 2.0 protocol](https://auth0.com/intro-to-iam/what-is-oauth-2)
- [Server-to-Server OAuth app](https://developers.zoom.us/docs/internal-apps/create/)
- [Zoom App Marketplace](https://marketplace.zoom.us/)
- [Get Recording API](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingGet)
- [List Recordings API](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingsList)
- [Zoom Live Streaming API](https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetingLiveStreamUpdate)
- [Zoom Live Streaming SDK](https://developers.zoom.us/blog/how-to-live-stream-with-video-sdk/)
- [Zoom meeting bots](https://developers.zoom.us/docs/zoom-apps/guides/meeting-bots-sdk-media-streams/)

Written By:

Vivek Sahu

Table of Contents

## The API to get transcripts, recordings, and metadata from meetings.

[Start for free](/content/signup/index.html) [Get a demo](/content/book-a-demo/index.html)

Need help? Email us at [support@recall.ai](mailto:support@recall.ai)

Get transcripts, recordings and metadata from meetings

[Start for free](/content/signup/index.html)

**Product**

[Meeting Bot API\\
\\
\\
example](/content/product/meeting-bot-api/index.html) [Desktop Recording SDK\\
\\
\\
example](/content/product/desktop-recording-sdk/index.html) [Mobile Recording SDK\\
\\
\\
example](/content/product/mobile-recording-sdk/index.html) [Calendar Integration\\
\\
\\
example](/content/product/calendar-integration-api/index.html) [Storage and Playback\\
\\
\\
example](https://docs.recall.ai/docs/storage-and-playback)

**Company**

[Careers\\
\\
\\
We're hiring!](/content/careers/index.html) [Blog\\
\\
\\
example](/content/blog/index.html) [Case Studies\\
\\
\\
example](/content/customersold/index.html)

**Security**

[Security Portal\\
\\
\\
example](https://security.recall.ai/) [SOC 2\\
\\
\\
example](https://security.recall.ai/resources?s=6yae1gt76airvvh39f2vbh&name=soc-2-type-2-report) [ISO 27001\\
\\
\\
example](https://security.recall.ai/resources?s=e9egniy1sgrydeihajcmv&name=isms-certificate) [HIPAA\\
\\
\\
example](https://security.recall.ai/) [GDPR\\
\\
\\
example](https://security.recall.ai/) [CCPA\\
\\
\\
example](https://security.recall.ai/)

**Legal**

[Privacy\\
\\
\\
We're hiring!](/content/privacy/index.html) [Terms of Use\\
\\
\\
We're hiring!](/content/terms-of-use/index.html)

**Resources**

[API Docs\\
\\
\\
example](https://docs.recall.ai/) [Pricing\\
\\
\\
example](/content/pricing/index.html) [Notetaker API\\
\\
\\
example](/content/product/notetaker-api/index.html) [Meeting Recording API\\
\\
\\
example](/content/product/meeting-recording-api/index.html) [Transcription API\\
\\
\\
example](/content/product/transcription-api/index.html) [Meeting Transcription API\\
\\
\\
example](/content/product/meeting-transcription-api/index.html) [Compliance Recording API\\
\\
\\
example](/content/product/compliance-recording-api/index.html) [Speaker Diarization API\\
\\
\\
example](/content/product/speaker-diarization-api/index.html) [Slack Huddles API\\
\\
\\
example](/content/product/slack-huddles-api/index.html)

**Compare**

[Recall.ai vs Attendee\\
\\
\\
example](/content/recall-ai-vs-attendee/index.html) [Recall.ai vs Meeting BaaS\\
\\
\\
example](/content/recall-ai-vs-meetingbaas/index.html) [Recall.ai vs Nylas Notetaker\\
\\
\\
example](/content/recall-ai-vs-nylas-notetaker/index.html) [Recall.ai vs Skribby\\
\\
\\
example](/content/recall-ai-vs-skribby/index.html)

More

**Meeting Bots**

[Google Meet Bot API\\
\\
\\
example](/content/product/meeting-bot-api/google-meet/index.html) [Microsoft Teams Bot API\\
\\
\\
example](/content/product/meeting-bot-api/microsoft-teams/index.html) [Zoom Meeting Bot API\\
\\
\\
example](/content/product/meeting-bot-api/zoom/index.html)

**Recording**

[Google Meet Recording API\\
\\
\\
example](/content/product/google-meet-recording-api/index.html) [Microsoft Teams Recording API\\
\\
\\
example](/content/product/microsoft-teams-recording-api/index.html) [Zoom Meeting Recording API\\
\\
\\
example](/content/product/zoom-recording-api/index.html)

**Transcription**

[Google Meet Transcription API\\
\\
\\
example](/content/product/google-meet-transcription-api/index.html) [Microsoft Teams Transcription API\\
\\
\\
example](/content/product/microsoft-teams-transcription-api/index.html) [Zoom Meeting Transcription API\\
\\
\\
example](/content/product/zoom-transcription-api/index.html)
