Skip to main content
ConfigView pulls Zoom account data through a Server-to-Server OAuth app that you create in the Zoom App Marketplace. That app type authenticates as the account itself rather than as a signed-in user, so ConfigView never uses anyone’s Zoom login. The app does still have an owner — the Zoom user who creates it — and the owner’s role matters (see below). You will end up with 3 secrets in ConfigView (ZOOM_ACCOUNT_ID, ZOOM_CLIENT_ID, ZOOM_CLIENT_SECRET) when setup is complete.
Scope of this integration today. ConfigView ingests the Zoom user directory and its access — who has an account (including deactivated ones), what licence and role, which admin permissions, which groups, and which Marketplace apps they have asked to install — plus how Zoom is used: who actually hosts meetings each month, every scheduled meeting, the account’s security and meeting settings, AI Companion usage, Zoom Workplace visitor invitations, and webinars: who holds a webinar licence, every webinar and its panelists, and how many people from each company domain registered and attended. Webinar registrants and attendees are counted by email domain only — ConfigView never stores their names or addresses. Meeting content, meeting participant lists, recordings and phone are not collected. If you need those, mention it to your ConfigView contact.

Step 1: Open the Zoom page in ConfigView

Before you start in Zoom, open ConfigView in a second browser tab and leave it open: https://{companyname}.configview.com/admin/integrations/Zoom Zoom shows the credentials on one screen of the app builder. With ConfigView open alongside it you can paste each value straight into its Credentials row as you copy it, rather than keeping a client secret in a notes file.

Step 2: Create the Server-to-Server OAuth app

  1. Sign in to the Zoom App Marketplace as an account Owner or Admin with permission to create apps. Use a shared service account (for example an integrations@ or sysadmin@ user) rather than a person’s own login — see Who should own the app below
  2. Go to the app build page: https://marketplace.zoom.us/user/build
  3. Click the blue + button (Build App). A menu pops up with three options — General app, Server to Server OAuth app and Webhook
  4. Choose Server to Server OAuth app, and enter Name: ConfigView
  5. The App Credentials screen shows three values. Switch to the ConfigView tab and paste each one into its row under Credentials, clicking the save icon on each:
  1. Back in Zoom, fill in the required Information fields (company name, developer contact) — Zoom will not let you activate the app without them
  2. On the Scopes screen, click Add Scopes and add these read scopes:
All of these are read-only. The picker also offers account:read:account_setting:admin and visitor_management:read:invitation_details:admin; ConfigView does not need them, because the settings and invitation lists already return everything those add. The scope picker also offers :master versions of the user and group scopes. Those are only for Zoom master accounts that manage sub-accounts; ConfigView does not need them.
  1. Click Continue, then Activate your app
The activation step is the one people miss. An app that is created but not activated returns a token error rather than a permission error, so it reads like a bad secret. The ConfigView health check distinguishes the two for you.

Who should own the app

The Zoom user who creates the app becomes its owner. ConfigView never signs in as that user, but Zoom ties two things to them:
  • The app’s scopes follow the owner’s role. Every scope ConfigView uses is admin-level. If the owner is later moved to a non-admin role, Zoom automatically strips the admin-level scopes from the app and collection stops.
  • Only the owner (or an admin) can manage the app — change scopes, rotate the client secret, or deactivate it. A deactivated app’s tokens stop working immediately.
So create it from a service account that will not leave or be demoted, not from a named person’s login. If the owner ever has to be demoted, transfer the app’s ownership to another admin first (Marketplace → Created Apps → the app’s action menu → Transfer App Owner). If the owner is removed from the Zoom account instead, Zoom hands the app to the account Owner automatically.
A transfer rotates the credentials. The new owner has to complete a credential rotation to accept the app, which issues a new Client Secret. Paste the new value into ZOOM_CLIENT_SECRET in ConfigView straight away, or collection fails with a token error from the next run.
The email on the app’s Information page is a contact Zoom requires before activation; ConfigView does not use it.

Step 3: Connect and verify

  1. Back on https://{companyname}.configview.com/admin/integrations/Zoom, confirm all three credentials show as saved
  2. Click Connect. ConfigView creates its tables and schedules every collector at your default run time. Stop any you do not want under Collectors:
  1. Click Verify now. The health check requests a token, then calls one endpoint for each scope above.
If a check fails:
  • Token request fails — Check all three secrets, and check the app is activated in the Marketplace. A created-but-not-activated app fails here, not at the scope checks.
  • Every Scope: check fails at once on a setup that used to work — The app owner has probably been demoted or removed, and Zoom stripped the admin scopes. Transfer ownership to an admin and re-add the scopes.
  • A Scope: check returns 401/403 — That scope is missing. Add it in the app’s Scopes tab, then re-activate the app; scope changes do not take effect until you do.
  • A Scope: dashboard:… check fails but the scope is there — AI usage needs a Business plan or higher. On lower plans those two collectors cannot run; stop them under Collectors.
  • Health check passes but a table is empty — Re-run that script and check the run log. User App Requests is often legitimately empty: it only has rows if people have asked to install Marketplace apps. Visitor Invitations stays empty without a visitor management licence, and the six webinar collectors stay empty without a Zoom Webinars licence.

Data Tables

Once the scripts run, these tables are created in your database. Each includes a run_at column for historical tracking. Most are snapshots (each run adds a full copy, read the newest with run_at = (SELECT MAX(run_at) …)); zoom_host_activity, zoom_ai_usage and zoom_ai_usage_trend are ledgers instead — one row per period, updated in place — so read them by period_month or usage_date, not run_at. zoom_webinar_instances and zoom_webinar_attendee_domains are ledgers too, one row per webinar session (and domain); read them by start_time.

Things worth knowing

type is the licence, and it is a number. Zoom encodes the licence type as an integer rather than a name (Basic / Licensed / On-prem). If you are reporting on paid seats, that column is the one to filter on — check a couple of known users to confirm the mapping for your account before relying on it. Users covers every status, so counts differ from Zoom’s default list. Zoom’s user list returns only active users unless asked otherwise. ConfigView asks for active, inactive and pending in turn, so deactivated accounts are in zoom_users too — filter on status = 'active' for current seats. Zoom Rooms are counted in zoom_users_summary but are not users, so the summary total runs a few higher than the row count. Permissions are per user, not per role. zoom_user_permissions lists what each person can actually do in the admin console (for example Meeting:Edit, AccountProfile:Read), which is the quickest way to find everyone with more than member access. Pair it with role_name in zoom_user_details. last_login_time is not a liveness signal on its own. It records the last sign-in Zoom saw, which for a user on a permanently signed-in desktop client can be a long time ago while they are using Zoom daily. Pair it with last_client_version before concluding a seat is idle. Hosting is the better seat-usage signal. zoom_host_activity counts meetings a person hosted on your Zoom account. In one account, a user whose last_login_time was 14 months old had hosted 15 meetings in the previous six months, so reclaim seats on hosting (and attending) rather than sign-in alone. Someone who only joins other people’s meetings hosts nothing, so a licensed user with no hosting rows is a candidate, not a verdict. Meetings people run on a personal Zoom account never appear here at all. A meeting’s host is its host_id, not whose list it came from. Zoom lists a meeting under its host and under anyone with scheduling privilege for that host. ConfigView keeps one row per meeting with the real host, and puts the assistants in also_listed_for. Meetings with no start_time are recurring meetings with no fixed time (type = 3). Settings values are text. zoom_account_settings.value holds the setting as Zoom returned it — true/false, a number, a string, or JSON for lists — with value_type saying which. Nested settings are flattened to a dot path in setting, for example section = 'in_meeting', setting = 'waiting_room'. The webinar licence is not on the user record. Neither zoom_users nor zoom_user_details shows it; it is a per-user feature flag, which is what zoom_webinar_licenses reads. Only licensed users have a webinar list at all. Webinar people are counted, not named — except presenters. Registrants and attendees are usually your customers’ or the public’s staff, so ConfigView keeps one count per email domain ((no email) when Zoom has none). Panelists are the presenters and are kept by name and email, so you can see which of your people present on which webinars. A webinar can have several sessions on the same day. Starting a webinar to test it, or restarting it, makes a separate session in Zoom. Those short sessions are kept in zoom_webinar_instances; filter on duration to drop them. join_count counts joins, so someone who drops and rejoins counts twice; zoom_webinar_attendee_domains.attendees counts distinct people.