baton-zoom is a connector for Zoom built using the Baton SDK. It communicates with the Zoom API to sync users, groups, roles, contact groups, invites, and license tiers.
Check out Baton to learn more the project in general.
- Zoom server to server app created in marketplace
- Scopes for syncing only(no provisioning):
- contact_group:read:list_groups:admin
- contact_group:read:list_members:admin
- group:read:list_groups:admin
- group:read:administrator:admin
- role:read:list_roles:admin
- user:read:user:admin
- user:read:list_users:admin
- billing:read:plan_usage:admin (optional, used to surface purchased vs. consumed Licensed seat counts)
Scopes for provisioning (grant/revoke) and the transfer_and_delete_user action
- role:write:member:admin
- role:delete:member:admin
- group:write:member:admin
- group:delete:member:admin
- group:write:administrator:admin
- group:delete:administrator:admin
- user:write:user:admin (create users)
- user:update:user:admin (assign/revoke license tier via PATCH /v2/users/{userId})
- user:delete:user:admin (delete users; also required for the transfer_and_delete_user action)
- Pro or higher plan
- Activate the App for Account ID, Client ID and Client Secret needed to use the API
The connector models Zoom's three user license tiers as a license resource type:
| Tier | Zoom type |
Consumes a seat? |
|---|---|---|
| Basic | 1 |
No |
| Licensed | 2 |
Yes |
| Unassigned | 4 |
No (no meetings license) |
Granting a license PATCHes the user's type field to the target tier. Revoking a license is a downgrade to Basic — Zoom has no "no license" state, and Basic is the floor. Revoking a Basic grant is a no-op since Basic does not occupy a seat.
When the billing:read:plan_usage:admin scope is granted, the Licensed resource is decorated with purchased_seats and consumed_seats (from GET /v2/accounts/me/plans/usage → plan_base.hosts / plan_base.usage). Without the scope, sync still succeeds — only the seat counts are omitted.
A Zoom user holds exactly one account role. GET /v2/users returns a single role_id per user, and the connector emits one role grant from it.
Granting a role replaces the role the user already holds. The connector issues POST /v2/roles/{roleId}/members and returns a GrantReplaced annotation naming the superseded grant, so C1 marks the previous role revoked without a separate revoke call. This is Zoom's constraint rather than a connector policy — Zoom's role management does not represent a user in two account roles.
Exclusivity covers account roles only. Group administrator is a separate Zoom concept and one user can administer several groups, so group admin grants are independent of the account role. Zoom Phone and Zoom Contact Center have their own role management, which this connector does not sync.
brew install conductorone/baton/baton conductorone/baton/baton-zoom
baton-zoom
baton resources
docker run --rm -v "$(pwd):/out" -e BATON_ZOOM_CLIENT_ID=clientId -e BATON_ZOOM_CLIENT_SECRET=clientSecret -e BATON_ACCOUNT_ID=accountId public.ecr.aws/conductorone/baton-zoom:latest -f "/out/sync.c1z"
docker run --rm -v $(pwd):/out ghcr.io/conductorone/baton:latest -f "/out/sync.c1z" resources
go install github.com/conductorone/baton/cmd/baton@main
go install github.com/conductorone/baton-zoom/cmd/baton-zoom@main
BATON_ZOOM_CLIENT_ID=clientId BATON_ZOOM_CLIENT_SECRET=clientSecret BATON_ACCOUNT_ID=accountId
baton resources
baton-zoom syncs the following Zoom resources:
- Users —
GET /v2/users. The C1 profile retainsgroup_ids,role_id, andtype; userGrants()emits group membership, role assignment, and license grants from those stored list fields without a per-user detail request. - Invites — pending users (
GET /v2/users?status=pending). - Groups —
GET /v2/groups. Member grants come from usergroup_ids. Admin grants come fromGET /v2/groups/{groupId}/admins. - Contact Groups —
GET /v2/contacts/groupsandGET /v2/contacts/groups/{id}/members(read-only). A member is either a user or a nested user group. A nested group's grant is expandable, so the users in that group also hold the contact group entitlement. - Roles —
GET /v2/roles. Membership grants come from each user'srole_id. A user holds one account role, so granting a role replaces the previous one. See Roles. - Licenses — static Basic / Licensed / Unassigned tiers from
User.type. Seat counts useGET /v2/accounts/me/plans/usagewhen the billing scope is present.
Grant emission for group members, roles, and licenses is skipped when that target type is excluded from --sync-resource-types. Those grants also require user in the filter because they are emitted from user Grants(). Group admin grants still come from the group builder. See docs/doc-info.md. Customer setup: docs/connector.mdx.
We started Baton because we were tired of taking screenshots and manually building spreadsheets. We welcome contributions, and ideas, no matter how small -- our goal is to make identity and permissions sprawl less painful for everyone. If you have questions, problems, or ideas: Please open a Github Issue!
See CONTRIBUTING.md for more details.
baton-zoom
Usage:
baton-zoom [flags]
baton-zoom [command]
Available Commands:
capabilities Get connector capabilities
completion Generate the autocompletion script for the specified shell
help Help about any command
Flags:
--account-id string required: Account ID used to generate token providing access to Zoom API. ($BATON_ACCOUNT_ID)
--client-id string The client ID used to authenticate with ConductorOne ($BATON_CLIENT_ID)
--client-secret string The client secret used to authenticate with ConductorOne ($BATON_CLIENT_SECRET)
-f, --file string The path to the c1z file to sync with ($BATON_FILE) (default "sync.c1z")
-h, --help help for baton-zoom
--log-format string The output format for logs: json, console ($BATON_LOG_FORMAT) (default "json")
--log-level string The log level: debug, info, warn, error ($BATON_LOG_LEVEL) (default "info")
-p, --provisioning This must be set in order for provisioning actions to be enabled ($BATON_PROVISIONING)
--skip-full-sync This must be set to skip a full sync ($BATON_SKIP_FULL_SYNC)
--sync-inactive-users Sync inactive Zoom users alongside active users ($BATON_SYNC_INACTIVE_USERS)
--ticketing This must be set to enable ticketing support ($BATON_TICKETING)
-v, --version version for baton-zoom
--zoom-client-id string required: Client ID used to generate token providing access to Zoom API. ($BATON_ZOOM_CLIENT_ID)
--zoom-client-secret string required: Client Secret used to generate token providing access to Zoom API. ($BATON_ZOOM_CLIENT_SECRET)
Use "baton-zoom [command] --help" for more information about a command.