Connect Retool to Zoom using a REST API Resource with Zoom's Server-to-Server OAuth credentials. Authenticate once by exchanging your Account ID, Client ID, and Client Secret for an access token, then query Zoom's API to schedule meetings, list recordings, view participants, and generate attendance reports — all without user-level OAuth prompts.
| Fact | Value |
|---|---|
| Tool | Zoom |
| Category | Communication |
| Method | REST API Resource |
| Difficulty | Intermediate |
| Time required | 25 minutes |
| Last updated | April 2026 |
Why Connect Retool to Zoom?
Zoom generates a significant amount of operational data — meeting schedules, recording archives, participant attendance, webinar registrant lists, and usage analytics — but this data is scattered across Zoom's own reporting UI, which is limited in customization and difficult to cross-reference with your internal CRM, HR system, or project management database. Connecting Retool to Zoom's API brings that data into a single internal tool where you can slice, filter, join, and act on it alongside your other operational data.
For operations and HR teams, a Retool Zoom dashboard enables practical workflows: see which team members attended which meetings, identify recordings that haven't been viewed by required participants, track recurring meeting attendance rates over time, and export participant lists for compliance or training records. For customer-facing teams, you can build panels that show all Zoom meetings scheduled with a specific account, pull recording links to share with clients, or monitor webinar attendance against your CRM's contact list.
Zoom's Server-to-Server OAuth app type — the current recommended authentication approach after Zoom deprecated JWT apps in September 2023 — is purpose-built for exactly this kind of backend integration. It requires no per-user login flow, generates non-expiring credentials, and scopes API access at the account level. Combined with Retool's server-side request proxying, this means your Zoom credentials stay completely off the client, and every member of your team can use the Retool Zoom dashboard without needing their own Zoom OAuth session.
Integration method
Zoom connects to Retool via a REST API Resource using Server-to-Server OAuth authentication — Zoom's recommended method for backend integrations that don't require individual user authorization prompts. You create a Server-to-Server OAuth app in Zoom Marketplace, obtain Account ID, Client ID, and Client Secret credentials, then use a Retool JavaScript query to exchange them for a short-lived access token. Subsequent Zoom API queries pass that token in the Authorization header, with Retool proxying all requests server-side so credentials never reach the browser.
Prerequisites
- A Zoom account with admin or developer access (to create apps in Zoom Marketplace)
- A Retool account (Cloud or self-hosted) with permission to add Resources
- A Zoom Server-to-Server OAuth app created in Zoom App Marketplace with the necessary API scopes enabled
- Account ID, Client ID, and Client Secret from your Zoom Server-to-Server OAuth app
- Basic familiarity with Retool's query editor, JavaScript queries, and component panel
Step-by-step guide
Create a Zoom Server-to-Server OAuth app in Marketplace
Navigate to Zoom App Marketplace at marketplace.zoom.us and sign in with your Zoom admin account. Click the Develop button in the top-right navigation, then select Build App from the dropdown menu. In the app type selector, find and choose Server-to-Server OAuth — this app type is specifically designed for server-side integrations that don't require individual user authorization. Name your app something descriptive like 'Retool Integration' and click Create. The app configuration page opens and immediately displays three critical credentials under the App Credentials section: Account ID, Client ID, and Client Secret. Copy all three values and store them securely — you will need them in the next step. The Client Secret is shown only once and cannot be retrieved later, though it can be regenerated. Next, configure the API scopes your Retool integration needs. Click the Scopes tab in the left navigation of the app configuration page. Use the search box to find and add the following scopes based on your use case: - meeting:read:admin — read meeting details and participant data for all users in your account - recording:read:admin — access cloud recording data for all users - webinar:read:admin — read webinar details, registrants, and attendees - report:read:admin — access usage reports and participant reports Add only the scopes you actually need — unnecessary scopes increase your security surface area. After adding scopes, click Save. Then navigate to the Activation tab and click Activate your app. The app status changes to Active, meaning you can now exchange your credentials for API access tokens. Note: Zoom's Server-to-Server OAuth access tokens expire after one hour. Your Retool JavaScript query will need to fetch a fresh token before each session's queries — you will handle this in step two.
Pro tip: After activating the app, test credential validity immediately using Zoom's API reference playground at marketplace.zoom.us/docs/api-reference — this confirms your app is active and the scopes are correctly configured before you build the Retool resource.
Expected result: A Zoom Server-to-Server OAuth app is active in Zoom Marketplace with Account ID, Client ID, Client Secret, and the required API scopes configured. The app status shows Active.
Store Zoom credentials as Retool Configuration Variables
Before creating the Retool resource, store your three Zoom credentials securely in Retool's Configuration Variables system. Navigate to your Retool instance's Settings page — click the gear icon in the bottom-left corner of the Retool home page, then select Configuration Variables from the settings navigation. Click Add Variable three times to create the following variables, marking each one as Secret: - Name: ZOOM_ACCOUNT_ID — Value: paste your Zoom Account ID - Name: ZOOM_CLIENT_ID — Value: paste your Zoom Client ID - Name: ZOOM_CLIENT_SECRET — Value: paste your Zoom Client Secret Variables marked as Secret are stored encrypted and are only accessible in resource configurations and Retool Workflows — they are never exposed to the browser frontend, meaning your Zoom credentials remain completely server-side. Click Save for each variable. Once saved, you can reference these variables in resource configurations and JavaScript queries using the syntax {{ environment.variables.ZOOM_ACCOUNT_ID }}, {{ environment.variables.ZOOM_CLIENT_ID }}, and {{ environment.variables.ZOOM_CLIENT_SECRET }}. This approach means you can rotate your Zoom credentials by updating just the configuration variable, without touching any individual queries or resource settings — especially important because Zoom Client Secrets can be regenerated, and when they are, you only need to update one place in Retool.
Pro tip: If your Retool instance uses multiple environments (e.g., staging and production), set different values per environment for each configuration variable — this lets your staging Retool apps use a test Zoom account while production uses your live account, without any query changes.
Expected result: Three Configuration Variables appear in Settings — ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, and ZOOM_CLIENT_SECRET — all marked as Secret and saved. They are ready to reference in resource and query configurations.
Add a Zoom REST API Resource and create a token exchange query
Navigate to the Resources tab in Retool (top navigation bar) and click Add Resource. Select REST API from the resource type list. Configure the resource: - Name: enter 'Zoom API' - Base URL: enter https://api.zoom.us/v2 - Authentication: select None at the resource level (you will handle auth dynamically per-query using the token exchange pattern) Click Save Changes. The resource is created but without static auth — this is intentional because Zoom's Server-to-Server OAuth tokens expire after one hour, so you need to fetch a fresh token dynamically. Open your Retool app and in the Code panel, click + New to create a JavaScript query. Name it 'getZoomToken'. Set the query type to JavaScript. Write the following token exchange code in the query editor — this calls Zoom's OAuth endpoint to get a fresh access token using your stored credentials: Paste the code shown below. This query makes a POST request to Zoom's token endpoint using Basic Auth (Client ID:Client Secret encoded as Base64) and the grant type account_credentials with your Account ID. The response contains an access_token valid for one hour. Enable 'Run this query automatically when inputs change' and set the trigger to 'On page load' so a fresh token is always available when the app opens. The fetched token is now accessible as getZoomToken.data.access_token from any other query in the app. Create a second query for your first actual Zoom API call: - Resource: Zoom API - Method: GET - Path: /users/me/meetings - Headers: add Authorization with value Bearer {{ getZoomToken.data.access_token }} This pattern — token exchange query runs first, subsequent queries reference its output in headers — is the standard approach for any OAuth 2.0 integration where tokens expire and must be refreshed.
1// JavaScript query: getZoomToken2// Exchanges Zoom Server-to-Server OAuth credentials for an access token3// Run this on page load; reference the token as getZoomToken.data.access_token45const accountId = retoolContext.configVars.ZOOM_ACCOUNT_ID;6const clientId = retoolContext.configVars.ZOOM_CLIENT_ID;7const clientSecret = retoolContext.configVars.ZOOM_CLIENT_SECRET;89// Encode credentials as Base64 for Basic Auth10const credentials = btoa(`${clientId}:${clientSecret}`);1112const response = await fetch(13 `https://zoom.us/oauth/token?grant_type=account_credentials&account_id=${accountId}`,14 {15 method: 'POST',16 headers: {17 'Authorization': `Basic ${credentials}`,18 'Content-Type': 'application/x-www-form-urlencoded'19 }20 }21);2223if (!response.ok) {24 const error = await response.text();25 throw new Error(`Zoom token exchange failed: ${error}`);26}2728const tokenData = await response.json();29return tokenData; // access_token, token_type, expires_inPro tip: Set the getZoomToken query's cache duration to 3,300 seconds (55 minutes) in the Advanced tab — Zoom tokens are valid for 3,600 seconds (1 hour), and caching for 55 minutes avoids unnecessary token refreshes while ensuring the token is always fresh before it expires.
Expected result: The getZoomToken JavaScript query runs successfully on page load and returns a JSON object containing an access_token string. Other queries can now reference {{ getZoomToken.data.access_token }} in their Authorization header to authenticate against Zoom's API.
Build queries to list meetings and fetch participant data
With token exchange working, create the core Zoom data queries for your dashboard. All queries follow the same pattern: REST API Resource set to 'Zoom API', Authorization header set to Bearer {{ getZoomToken.data.access_token }}, and specific paths for each Zoom endpoint. Create a 'listMeetings' query: - Resource: Zoom API - Method: GET - Path: /users/{{ userSelect.value || 'me' }}/meetings - URL Parameters: type=scheduled, page_size=100, next_page_token={{ '' }} - Headers: Authorization: Bearer {{ getZoomToken.data.access_token }} This returns upcoming scheduled meetings for the selected user or the authenticated account. Add a URL Parameter 'type' set to 'previous_meetings' to list past meetings instead. Create a 'getMeetingParticipants' query for a specific meeting: - Resource: Zoom API - Method: GET - Path: /report/meetings/{{ table1.selectedRow.id }}/participants - URL Parameters: page_size=300 - Headers: Authorization: Bearer {{ getZoomToken.data.access_token }} - Trigger: Manual (fires when a user selects a meeting row) Note: Participant reports require the report:read:admin scope and are only available for meetings that have already ended — this endpoint returns post-meeting data, not live participant status. Create a 'listRecordings' query: - Resource: Zoom API - Method: GET - Path: /users/{{ userSelect.value || 'me' }}/recordings - URL Parameters: from={{ dateRange.start }}, to={{ dateRange.end }}, page_size=100 - Headers: Authorization: Bearer {{ getZoomToken.data.access_token }} Drag Table components onto the canvas for meetings and recordings, setting each one's Data Source to {{ listMeetings.data.meetings }} and {{ listRecordings.data.meetings }} respectively — Zoom's API wraps results in a 'meetings' key in the response object. Wire the getMeetingParticipants query to the meetings Table's onRowClick event handler so selecting a meeting automatically loads its participant list into a second Table below.
1// JavaScript transformer for meeting list — formats Zoom API response for Table component2const meetings = data.meetings || [];3return meetings.map(meeting => ({4 id: meeting.id,5 topic: meeting.topic,6 type: meeting.type === 2 ? 'Scheduled' : meeting.type === 3 ? 'Recurring' : 'Instant',7 start_time: new Date(meeting.start_time).toLocaleString(),8 duration_min: meeting.duration,9 host_id: meeting.host_id,10 join_url: meeting.join_url,11 participants: meeting.participants_count || 'N/A'12}));Pro tip: Zoom's /users/me/meetings endpoint returns only the token owner's meetings. To list meetings for any user in the account, use /users/{userId}/meetings with the meeting:read:admin scope — replace userId with the user's Zoom email address or user ID.
Expected result: Three queries are configured and running — listMeetings returns the meeting schedule in a Table, getMeetingParticipants loads participant details when a meeting row is selected, and listRecordings shows cloud recording entries with date filters.
Add attendance analytics with Charts and a Retool Workflow for alerts
Elevate the dashboard from a data viewer to an analytics tool by adding Charts and calculated metrics. In the Component panel, drag a Chart component above or beside the meetings Table. Set the Chart's Data Source to a JavaScript transformer that calculates attendance metrics from your participant data: Create a standalone JavaScript transformer (click + New in the Code panel, select Transformer) named 'attendanceTrend'. This transformer reads from the listMeetings query data and calculates a weekly attendance summary. Reference the transformer in the Chart component's Data Source as {{ attendanceTrend.value }}. For the Chart component settings: - Chart Type: Bar Chart - X-axis: week (the week field from the transformer output) - Y-axis series: avg_participants - Title: 'Average Meeting Attendance by Week' Add a Statistics component row above the tables to show key metrics: total meetings this month, average attendance rate, and total recording hours. Wire each Stat component's value to a JavaScript transformer that calculates the metric from the query data. For proactive alerting, build a Retool Workflow that runs weekly and identifies meetings with very low attendance. Navigate to Workflows in the Retool home page sidebar, create a new Workflow, and add a Schedule trigger for Monday mornings. Add a Resource Query block targeting your Zoom API resource, pulling past week's meetings. Add a JavaScript Code block that filters for meetings where participants_count is below a threshold (e.g., less than 3). Add a Slack Resource Query block (if Slack is connected) that posts a summary of low-attendance meetings to a #meeting-ops channel. Click Publish Release to activate the Workflow. For complex cross-tool reporting combining Zoom with CRM and HR data across multiple workflows, RapidDev's team can help architect and build the full Retool solution.
1// Standalone transformer: attendanceTrend2// Calculates weekly average attendance from past meetings data3const meetings = listMeetings.data?.meetings || [];45// Group meetings by week6const weekMap = {};7meetings.forEach(meeting => {8 const date = new Date(meeting.start_time);9 const weekStart = new Date(date);10 weekStart.setDate(date.getDate() - date.getDay()); // Sunday of that week11 const weekKey = weekStart.toISOString().split('T')[0];1213 if (!weekMap[weekKey]) {14 weekMap[weekKey] = { total_participants: 0, meeting_count: 0 };15 }16 weekMap[weekKey].total_participants += (meeting.participants_count || 0);17 weekMap[weekKey].meeting_count += 1;18});1920return Object.entries(weekMap)21 .sort(([a], [b]) => a.localeCompare(b))22 .map(([week, stats]) => ({23 week,24 avg_participants: stats.meeting_count > 025 ? Math.round(stats.total_participants / stats.meeting_count)26 : 0,27 meeting_count: stats.meeting_count28 }));Pro tip: Zoom's participant report endpoint (/report/meetings/{meetingId}/participants) provides individual join/leave timestamps with duration in minutes — use this for detailed attendance compliance reports where you need to verify that specific people attended for at least a minimum duration.
Expected result: The dashboard shows a bar chart of weekly meeting attendance trends, statistics components with total meetings and average attendance, and an active Retool Workflow that monitors low-attendance meetings and posts weekly alerts. The complete Zoom meeting management dashboard is operational.
Common use cases
Build a meeting attendance tracker for team managers
Create a Retool dashboard that lets managers select a date range and see all Zoom meetings held by their team, the list of participants who attended each meeting, and attendance rates as a percentage of expected attendees. Cross-reference Zoom participant data with your HR database to match Zoom users to employee records and flag meetings with unusually low attendance for follow-up.
Build a Retool attendance panel with a date range picker that queries Zoom's past meetings API for the team's host email, shows each meeting's title, scheduled time, participant count vs. expected count, and includes a drill-down table of individual attendees with join/leave times pulled from the participant report endpoint.
Copy this prompt to try it in Retool
Zoom recording library with CRM linking
Build a Retool recording management panel that lists all Zoom cloud recordings, their duration, size, and a shareable link. Add a column where team members can paste a CRM deal or contact ID to associate each recording with the relevant account. Store the linking data in Retool Database and display a unified view of recordings per CRM account.
Create a Retool recording panel that fetches all cloud recordings from the Zoom API for the past 30 days, displays them in a Table with title, host, duration, recording date, and a direct share link, plus an editable 'CRM Account' text column that saves associations to Retool Database for sales team reference.
Copy this prompt to try it in Retool
Webinar registrant and attendance dashboard
Build a Retool webinar operations panel for marketing teams: list all scheduled and past webinars, show registrant counts vs. actual attendees, calculate show-up rate percentages, and export attendee lists. Use Retool Charts to visualize attendance trends across webinars over time. Add a button to trigger a follow-up Slack notification to the marketing channel with a post-webinar summary.
Build a webinar analytics dashboard in Retool that lists all Zoom webinars from the past 90 days using the webinar list API, shows registrant count and actual attendee count for each, calculates show-up rate as a percentage, includes a Chart component showing attendance trend by week, and has a 'Export Attendees' button that opens the attendee CSV download link.
Copy this prompt to try it in Retool
Troubleshooting
The getZoomToken query fails with 'invalid_client' or 401 Unauthorized error
Cause: Either the Client ID or Client Secret is incorrect, the Server-to-Server OAuth app is not yet activated in Zoom Marketplace, or the credentials were copied with extra whitespace.
Solution: In Zoom Marketplace, navigate to your Server-to-Server OAuth app and verify the app status shows 'Active' — if it shows 'Created' or 'Inactive', click the Activation tab and activate the app. Verify the Account ID, Client ID, and Client Secret in your Retool Configuration Variables match exactly what Zoom displays (re-copy each one fresh from Marketplace). Check that the Base64 encoding in the JavaScript query uses the format clientId:clientSecret with a colon separator and no extra characters.
Zoom API queries return 401 Unauthorized after working for a while
Cause: The Zoom access token has expired — Server-to-Server OAuth tokens are valid for only 3,600 seconds (one hour). If the Retool app has been open for more than an hour without a page reload, the cached token is no longer valid.
Solution: Enable caching on the getZoomToken query with a 3,300-second cache duration (Advanced tab → Cache → Enable with 3300 seconds). This ensures Retool fetches a fresh token just before the previous one expires. Alternatively, add an error event handler on failing Zoom queries that triggers getZoomToken to re-run, then retries the failed query on success — this creates automatic token refresh on expiry.
The /report/meetings/{id}/participants endpoint returns 404 or empty data
Cause: Participant reports are only available for completed meetings — the meeting must have ended before the report endpoint has data. Additionally, the report:read:admin scope must be enabled in your Zoom Server-to-Server OAuth app.
Solution: Verify the meeting has ended (it should appear in past meetings, not upcoming). In Zoom Marketplace, open your app's Scopes tab and confirm report:read:admin is listed and enabled. Participant report data can take up to 30 minutes after a meeting ends to become available in Zoom's API — if querying a recently ended meeting, wait and try again. For meeting-in-progress participant data, use the /meetings/{meetingId}/participants endpoint instead (requires meeting:read:admin scope).
listMeetings query returns data but the Table component shows no rows
Cause: Zoom wraps list responses in a nested key — meetings, webinars, or recordings depending on the endpoint — but the Table's Data Source is pointing to the query root object rather than the nested array.
Solution: In the Table component's Inspector panel, update the Data Source from {{ listMeetings.data }} to {{ listMeetings.data.meetings }}. Similarly for webinars use .webinars and for recordings use .meetings (Zoom's recordings endpoint also uses a 'meetings' key for the recording array). Inspect the raw query response in the Code panel's Response tab to confirm the exact key name for each endpoint.
Best practices
- Use Zoom's Server-to-Server OAuth app type for all Retool integrations — the older JWT app type was deprecated in September 2023 and should not be used for new integrations.
- Store Zoom credentials (Account ID, Client ID, Client Secret) in Retool Configuration Variables marked as Secret rather than hardcoding them in queries or resource headers — this enables rotation without editing individual queries.
- Cache the Zoom access token in the getZoomToken query for 3,300 seconds (55 minutes) to avoid making unnecessary token exchange requests on every app interaction while ensuring the token never expires during active use.
- Request only the API scopes your Retool dashboard actually uses — if you only need to list meetings, you do not need recording:read:admin or report:read:admin scopes. Minimal scopes reduce security risk if credentials are ever compromised.
- Use Zoom's admin-level endpoints (/users/{userId}/meetings with meeting:read:admin scope) rather than user-level endpoints when building dashboards that aggregate data across your entire organization rather than for a single user.
- Add error handling to your Zoom queries with failure event handlers that show an in-app notification when API calls fail — Zoom API rate limits (100 requests per second) can cause intermittent 429 errors during high-frequency dashboard use.
- For recording-intensive dashboards, store Zoom recording metadata in Retool Database and sync it periodically via a Retool Workflow rather than fetching recordings fresh on every page load — recording data is relatively static and benefits from caching.
Alternatives
Choose Google Meet if your organization is on Google Workspace — Meet data is accessed via the Google Calendar API's conferenceData, using the same OAuth credentials as other Google services your team already uses.
Choose Microsoft Teams if your organization is on Microsoft 365 — Teams meetings and recordings are accessible via Microsoft Graph API, which integrates with your existing Azure AD authentication setup.
Choose Webex if your organization uses Cisco infrastructure or has compliance requirements that make Webex's enterprise security certifications the preferred platform for video conferencing.
Frequently asked questions
Does Zoom have a native connector in Retool, or do I need a REST API Resource?
Zoom does not have a dedicated native connector in Retool's Resources catalog as of early 2026. You connect to Zoom by creating a generic REST API Resource with Zoom's base URL (https://api.zoom.us/v2) and handling authentication via a JavaScript token exchange query. This approach gives you full access to Zoom's API — the only difference from a native connector is manually configuring the auth token header in each query.
Why does Zoom use Server-to-Server OAuth instead of regular OAuth 2.0 for this integration?
Server-to-Server OAuth is Zoom's recommended authentication method for backend integrations where you don't need individual user authorization — you authenticate at the account level using your Zoom admin credentials rather than requiring each Retool user to log into Zoom separately. This is the replacement for Zoom's deprecated JWT app type (deprecated September 2023). Standard OAuth 2.0 would require each user to authorize the app individually, which is appropriate for user-specific access but unnecessary overhead for a shared internal dashboard.
How do I access Zoom meeting data for all users in my organization, not just the admin account?
Add the meeting:read:admin scope to your Zoom Server-to-Server OAuth app, then use the /users/{userId}/meetings endpoint with specific user email addresses or Zoom user IDs. You can first call the /users endpoint with user:read:admin scope to get a list of all users in your organization, then iterate through them in Retool to build an aggregated view of all meetings across your account.
Can I schedule new Zoom meetings directly from a Retool app?
Yes. Add the meeting:write:admin scope to your Zoom Server-to-Server OAuth app, then create a Retool query with Method POST, Path /users/{userId}/meetings, and a JSON body containing the meeting settings (topic, start_time, duration, timezone, type). Trigger this query from a Form component Submit button. The response returns the created meeting's join_url, which you can display to the user or store in your database.
Are there rate limits on Zoom's API that could affect Retool dashboard performance?
Yes. Zoom's API rate limits vary by endpoint — most endpoints allow around 100 requests per second at the account level, with lower limits on report endpoints. For Retool dashboards used by many simultaneous users, implement query caching (Advanced tab → Cache duration) to reduce redundant API calls. The Zoom Meetings and Recordings list endpoints are the most commonly hit — a 60-second cache on these queries significantly reduces API load for shared dashboards without meaningfully impacting data freshness.
How do I get Zoom participant data for compliance or attendance verification purposes?
Use the /report/meetings/{meetingId}/participants endpoint, which requires the report:read:admin scope. This returns each participant's name, email (if signed in with a Zoom account), join time, leave time, and duration in seconds. The data becomes available 30–60 minutes after a meeting ends and is retained for 6 months in Zoom's system. Export this data from Retool by wiring a button to a JavaScript query that formats the results as CSV and triggers a download using the browser's download API.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation