← library
Self-serve, review-gated
Video conferencing / communications platform·agent-generated · deepseek-v4.1-flash·checked 2026-10-28
difficulty
3/5

Works in your own Zoom account in about an hour - General app, redirect URL, allow list, code exchange - but installing for anyone outside your account means Marketplace review with an OWASP-facing security audit and scope-by-scope least-privilege justification.

First working connection
~1–3 hours
Production / approved
Same day for private/beta apps; ~2–6 weeks for public/unlisted review (inferred)
Composio managed OAuth
Available: ship today
Composio lists a managed OAuth app for this toolkit — you can ship on it while your own app is set up or reviewed.
who does itagent 3you 5provider 0
evidencetested 4sourced 29inferred 4
◆ agent run11 pages read26/26 quotes verified verbatim65s$0.021deepseek-v4.1-flash

01Pick your path

Private app (your Zoom account only)
when Your own org is the only customer, or you are prototyping against real accounts.
→ Installs only for users inside your Zoom account; no Marketplace review; usable the same day.
Beta app
when Design partners outside your account need access before you are ready to submit.
→ Shared with restrictions via a requested authorization URL; no review.
Unlisted public app
when Customers install it themselves but you do not want a public listing.
→ Full review (metadata, usability, compliance, security) but not discoverable in the Marketplace.
Published Marketplace app
when You want discovery, or the customer requires a Marketplace listing for procurement.
→ Full review plus ongoing monitoring and remediation obligations after publication.

02Time & effort

Hands-on work
8.9 h – ~3 workdays
Waiting on others
2 weeks – 6 weeks
You're actually working
3% of elapsed time
Phases
5
start↑ first working connection, then production pathproduction
  1. DEVCreate General app + credentials10–20 minutesinferred[S10][S5]Marketplace generates separate development and production client ID/secret.
  2. DEVRedirect URL, allow list, scopes15–30 minutessourced[S10][S7]OAuth redirect URL and OAuth allow lists are both required; scope_description is what reviewers read.
  3. DEVImplement authorize + token + refresh30–120 minutesinferred[S2]Standard RFC 6749 code flow; PKCE supported for public clients.
  4. PRODReview submission pack1–3 dayssourced[S9][S1]Technical Design section in the build flow, plus Terms of Use, Privacy Policy, docs and support URL.
  5. PRODMarketplace review cycleswait 2–6 weekssourced[S1][S9]Zoom states review time varies with app quality and scope clarity but gives no SLA.
agent can do it you waiting on providerbar widths ∝ √time, so short tasks stay visible

03Steps

0/8 done

Get a working connection

  1. Confirm you can see the Developer linkyousourced ❝[S10]

    Sign in to the Marketplace as owner/admin or with the 'Zoom for developers' role. The Developer link only renders when Zoom detects the permission - if it is missing, an admin must grant it first.

    “The Marketplace only displays the Developer link when it detects that the user has the proper developer permissions.” — [S10] verified verbatim
    ↗ marketplace.zoom.us/
    ◆ prepared by agent · Zoom App Marketplace
    https://marketplace.zoom.us/
  2. Create a General appyousourced ❝[S10][S5][S3]

    Lower-left Developer > Develop > Build an app > General app > Create. This is the user-managed OAuth app type that acts on behalf of an authorized user. Server-to-Server is the wrong choice for per-user agents.

    “On the app creation screen, select General app and click Create.” — [S10] verified verbatim
  3. Set redirect URL, allow list and strict modeyousourced ❝[S10][S7]

    On Basic Info: set the OAuth redirect URL, add your base URL to the OAuth allow lists (required), enable Strict Mode so only exact matches are accepted, and keep development and production credentials separate. Custom URL schemes only work for Meeting SDK apps.

    “OAuth allow lists (required): Add any unique URLs that Zoom should allow as valid redirects for your OAuth flows.” — [S10] verified verbatim
    ◆ prepared by agent · build-flow OAuth manifest (edit before pasting)
    {
      "oauth_information": {
        "usage": "USER_OPERATION",
        "development_redirect_uri": "https://yourapp.example.com/oauth/zoom/callback",
        "production_redirect_uri": "https://yourapp.example.com/oauth/zoom/callback",
        "oauth_allow_list": ["https://yourapp.example.com"],
        "strict_mode": true,
        "scopes": [
          { "scope": "user:read:user", "optional": false },
          { "scope": "user:read:email", "optional": false }
        ],
        "scope_description": "Identify the signed-in user (name + email) to display in the agent UI. No write or admin access.",
        "enable_public_pkce_client": true
      }
    }
  4. Choose narrowest scopes and write the justificationagentsourced ❝[S9][S7]

    Pick the fewest scopes that ship v1. Write a scope_description for each; the review team verifies least privilege and may require unused scopes be removed. Do not take meeting/recording/admin scopes you cannot point to a screen for.

    “The Marketplace Security Review Team verifies that the app only requests the minimum necessary OAuth scopes required for its functionality. Developers may be asked to remove unused or inappropriate scopes.” — [S9] verified verbatim
    ◆ prepared by agent · scope justification draft for review
    Scope justification - user:read:user + user:read:email (v1)
    
    What the agent does: reads the signed-in user's name and email to label its session and route requests to the right person.
    
    Why these scopes: both are read-only and limited to the authorizing user's own profile. We request no meeting, recording, chat or phone scopes, and no ':admin' scopes.
    
    What we deliberately do NOT take: meeting create/update (not in v1), recordings (out of scope), admin-managed account access (we are a user-managed app).
    
    Data handling: tokens stored encrypted at rest; refresh tokens revoked on uninstall via Zoom's deauthorization callback; no data shared with third parties or used for advertising.
  5. Implement authorization code flowagentsourced ❝[S2][probe]

    Send the user to https://zoom.us/oauth/authorize with response_type=code, client_id and redirect_uri; POST the returned code to https://zoom.us/oauth/token with a Basic auth header (base64 client_id:client_secret). Use PKCE for public clients with no secret. Verify the state parameter.

    “https://zoom.us/oauth/authorize?response_type=code&client_id=ZOOM_CLIENT_ID&redirect_uri=REDIRECT_URI” — [S2] verified verbatim
    ↗ developers.zoom.us/docs/integrations/oauth/
    ◆ prepared by agent · authorize + token exchange
    const authUrl = new URL('https://zoom.us/oauth/authorize');
    authUrl.search = new URLSearchParams({
      response_type: 'code',
      client_id: process.env.ZOOM_CLIENT_ID,
      redirect_uri: process.env.ZOOM_REDIRECT_URI,
      state,
    }).toString();
    
    // in your callback handler
    const basic = Buffer.from(`${process.env.ZOOM_CLIENT_ID}:${process.env.ZOOM_CLIENT_SECRET}`).toString('base64');
    const res = await fetch('https://zoom.us/oauth/token', {
      method: 'POST',
      headers: { Authorization: `Basic ${basic}` },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        code,
        redirect_uri: process.env.ZOOM_REDIRECT_URI,
      }),
    });
    const { access_token, refresh_token, expires_in } = await res.json(); // expires_in: 3600
  6. Handle refresh, expiry and deauthorizationagentsourced ❝[S2]

    Tokens live 3600 seconds. Refresh before expiry, store refresh tokens encrypted, and implement Zoom's deauthorization endpoint so uninstalls invalidate data. Treat a scope/webhook change as a forced re-consent event for existing users.

    “Access tokens expire after one hour. After your access token expires, you can follow the refresh flow to get a new one.” — [S2] verified verbatim
  7. Install and test in your own accountyousourced ❝[S2][S1][S9]

    Use the Local Test page's 'Add App Now' to install into your own account and run a real consent + token exchange in a browser (curl cannot validate your client ID). Then choose: private app (no review), beta (no review, restricted sharing), or submit for public/unlisted review.

    “You can get a user authorization code by adding your app to your Zoom account. To do this, navigate to the Local Test page, and choose Add App Now.” — [S2] verified verbatim

Make it production-ready

  1. Submit for Marketplace reviewyousourced ❝[S1][S9]

    Complete the Technical Design section, attach Terms of Use / Privacy Policy / docs / support URL, and expect two phases: metadata + usability + compliance, then a security audit with OWASP Top 10 testing and scope evaluation. Rejections come back as a remediation report and re-submission.

    “In the first phase of the submission process, the Marketplace Operations team reviews metadata, usability, and compliance.” — [S1] verified verbatim
    ↗ developers.zoom.us/docs/distribute/

04Requirements, scopes & nuances

You'll need

  • ▸A Zoom account where you are owner, account admin, or hold the 'Zoom for developers' role (admin enables it under User Management > Roles > Role Settings > Advanced features). sourced ❝[S10]
  • ▸A public HTTPS redirect endpoint, entered as the OAuth redirect URL and added to the OAuth allow list (both are required fields). sourced ❝[S10][S7]
  • ▸For any public/unlisted listing: Terms of Use, Privacy Policy, self-serve documentation and a Support URL, plus ongoing individual user support. sourced ❝[S1]
  • ▸A completed Technical Design section in the build flow describing stack, architecture and how each OAuth scope's data is used. sourced ❝[S9]
  • ▸Willingness to undergo a security test against OWASP Top 10, including least-privilege verification, web app scanning and vulnerable-library checks. sourced ❝[S9][S1]

Gotchas

  • !A token from a Free-plan account unlocks the same scopes as Business+, but your app shares account-level rate limits with every other app installed on that account - a big customer on Free throttles fast. inferred
  • !Private and beta apps skip review entirely; public and unlisted apps do not. 'Unlisted' is not a loophole - it still goes through the full review. sourced ❝[S9][S1]
  • !Access tokens expire after 3600 seconds. You must store and use the refresh_token, and you must handle Zoom's deauthorization callback so uninstalls are cleaned up. sourced ❝[S2]
  • !Redirect handling is fussy: OAuth redirect URL is required, the OAuth allow list is required, and Strict Mode makes every redirect match exactly. Custom URL schemes are only allowed for Meeting SDK apps. sourced ❝[S10][S7]
  • !Any scope or webhook change forces existing users through the consent screen again - decide your v1 scope set before launch, not after. sourced ❝[S2]
  • !Server-to-Server OAuth (grant_type=account_credentials) is not user OAuth: it returns a token for your own account and has no refresh flow. Do not pick it if an agent must act per-user. sourced ❝[S2]
Scope / permissionTierNoteEvidence
user:read:userbasicRead the authorized user's profile. Appears in Zoom's own token response examples - a safe baseline.sourced ❝[S2]
user:read:emailbasicUsed in the official manifest schema example; good enough to identify a user in your agent's UI.sourced ❝[S7]
openid email profilebasicThe only scopes advertised in Zoom's OIDC discovery document (probe). OIDC-style sign-in only; grants no Zoom API resources.tested[probe]
user:read:tokensensitiveReturned in Zoom's device-flow example. Reading a user's token is higher risk - expect the security review to ask why email/profile is not enough.sourced ❝[S2]
meeting read/write scopes (e.g. 'View and manage all user meetings')sensitiveNeeded for schedule/update/cancel automation; treat as sensitive and justify per-endpoint. Nothing in the fetched sources enumerates the exact scope strings.inferred[S3][S4]
admin-level scopes (':admin' suffix, admin-managed apps)gatedAccount-wide access - only for admin-managed apps where an account admin installs. Requires admin role setup and is the most heavily scrutinised in review.sourced ❝[S2][S3][S10]

05If you get blocked

✕No 'Developer' link in the Zoom App Marketplace.sourced ❝[S10]

→ Ask the account admin: User Management > Roles > Role Settings > Advanced features > View+Edit on 'Zoom for developers'. The Developer link appears only once the permission exists.

✕App review rejected for over-broad or unexplained OAuth scopes.sourced ❝[S9][S7]

→ Delete unused scopes before submission and fill scope_description for each; the security team explicitly may require removal of unused or inappropriate scopes.

✕You need other companies' Zoom users before review is done.sourced ❝[S1][S9]

→ Ship as a private app (users within your Zoom account) or a beta app first - both skip review - then submit for public listing when the product is stable.

✕429s in production even though OAuth works.sourced ❝[S11][S8]

→ Handle 429 with backoff and prefer webhooks over polling; heavy endpoints differ by plan (Free heavy APIs: 1/sec, 1000/day).

06Evidence: what was tested, sourced, and still uncertain

$ probes: live GETs with a dummy client_id, no credentials
✓ Discovery document (/.well-known/openid-configuration) → 200
https://api.zoom.us/.well-known/openid-configuration
issuer=https://zoom.us; authorization_endpoint=https://zoom.us/oauth/authorize; token_endpoint=https://zoom.us/oauth/token; scopes_supported=openid email profile
∴ Zoom publishes OIDC discovery, but scopes_supported lists only openid email profile - the OIDC layer, not the Zoom API scopes. You cannot enumerate user:read:user / meeting scopes from this document; they are selected in the app build flow.
✓ Discovery document (/.well-known/openid-configuration) → 200
https://zoom.us/.well-known/openid-configuration
issuer=https://zoom.us; authorization_endpoint=https://zoom.us/oauth/authorize; token_endpoint=https://zoom.us/oauth/token; scopes_supported=openid email profile
∴ Same discovery document served from zoom.us, with issuer=https://zoom.us and authorization_endpoint=https://zoom.us/oauth/authorize - confirms the endpoints the docs describe and that the issuer is the bare domain, not the api subdomain.
✓ Authorize endpoint with a fake client_id → 302
https://zoom.us/oauth/authorize?client_id=probe_invalid_client&response_type=code&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback
redirect → https://zoom.us/oauth/signin?_rnd=1793208264046&client_id=probe_invalid_client&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&response_type=code&_x_zm_rtaid=
∴ The authorize endpoint is live and answers with a 302 into the sign-in page even for a bogus client_id. You cannot validate your client ID / redirect URL with curl - invalid credentials only surface after the user is signed in, so test in a browser with a real app.

Still uncertain

  • ? Zoom publishes no review SLA; the 2–6 week range is my estimate from the documented two-phase process, not a sourced number.
  • ? The fetched sources do not enumerate the Zoom API scope catalogue or per-scope risk tiers; the meeting/recording/admin tier assignments are inferred from the API surface and the ':admin' suffix in a token example.
  • ? The OIDC discovery document advertises only openid email profile, so it cannot be used to verify which API scopes are requestable - only the app build flow shows that.
  • ? Whether Zoom issues an id_token with usable profile claims for OIDC-only clients is not covered by the sources fetched.
  • ? No source states whether a production app can stay private indefinitely without review; private apps are documented as internal-account only.
  • ? Generated automatically; no app was registered and no review was submitted.