Skip to main content

Zoom Collection

Zoom Collection Integration with Onna

Overview

This guide explains how to set up and interact with a Zoom collection through the Onna Platform API. You'll learn how to create a workspace and collection, authorize access to Zoom via OAuth2, list the users and channels available in the Zoom account, configure sync filters to control exactly which users are synchronized, start the sync, and clean up your environment afterward.

Create a workspace

A workspace is the main container for your project in Onna. Create one with a POST request.

curl --location --request POST 'https://api.onna.com/v1/workspaces' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"name": "My New Workspace",
"description": "This is a workspace for organizing Zoom data in Onna."
}'

Where:

  • name is the name of the workspace.
  • description is a brief description of the workspace's purpose.

A successful response (201) will return:

{
"onna_id": "<WORKSPACE_ID>"
}

Create a Zoom Wallet

Zoom credentials are stored in a wallet that the collection references. Create an empty wallet first; the OAuth pairing step later populates it with the access token.

curl --location --request POST 'https://api.onna.com/v1/wallet' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"name": "Zoom",
"credential_type_name": "Datasource",
"config_type": "zoom"
}'

Where:

  • name is a label for the wallet.
  • credential_type_name is the credential type. For Zoom, use Datasource.
  • config_type identifies the service the wallet holds credentials for. For Zoom, use zoom.

A successful response (201) will return:

{
"onna_id": "<WALLET_ID>"
}

Create a Zoom Collection

Next, create a Zoom collection within the workspace you created. The collection is the container for the users and content you will sync from Zoom.

curl --location --request POST 'https://api.onna.com/v1/collections' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"name": "My Zoom Collection",
"onna_parent_id": "<WORKSPACE_ID>",
"type": "zoom",
"config_type": "zoom",
"wallet_credentials": "<WALLET_ID>"
}'

Where:

  • name is the name of the collection.
  • onna_parent_id is the ID of the workspace that this collection will belong to.
  • type is the type of collection being created. For Zoom, the type is zoom.
  • config_type is the configuration type. For Zoom, this is also zoom.
  • wallet_credentials is the ID of the wallet you created for the Zoom service.

A successful response (201) will return:

{
"onna_id": "<COLLECTION_ID>",
"type": "zoom"
}
Actionable Tips: While creating collections, consider adding metadata that might be required later for reporting or analysis.

You might also want to implement a naming convention (like Collection-{WorkspaceName}-Zoom) for better organization.

Initiate OAuth2 Flow to Get an Authorization Code

To authorize access to Zoom, initiate the OAuth2 flow using the source-type authorization URL. The response is a 302 redirect to the Zoom authorization URL. Open that URL in your browser to log in and grant the application access to Zoom.

Unlike Miro or Box, Zoom OAuth does not go through Connector Hub. The same GET /collections/authorization_url/zoom endpoint is used, but Zoom is routed internally to canonical @datasourceAuthCode/zoom.

curl --location --request GET 'https://api.onna.com/v1/collections/authorization_url/zoom?redirect_to=http%3A%2F%2Flocalhost%3A9000%2Fcallback' \
--header 'Authorization: Bearer <token>'

Where:

  • redirect_to is the URL Zoom redirects to after authorization. It must be on your account's allowlist of valid collection redirect URLs.

Once you've authorized, you'll be redirected to the provided redirect_to URL with an authorization code.

Use a temporary redirect URI during development (like http://localhost:9000/callback) for easier testing. Be sure to change this to a production-ready URL before going live.

For preservation (legal hold) flows, pass scopes_type=preservation so Zoom requests the preservation scopes during authorization:

curl --location --request GET 'https://api.onna.com/v1/collections/authorization_url/zoom?redirect_to=http%3A%2F%2Flocalhost%3A9000%2Fcallback&scopes_type=preservation' \
--header 'Authorization: Bearer <token>'

You can also pass an optional state query parameter to carry context through the OAuth flow.

Pair the Authorization Code with the Collection (Token Exchange)

After successful authorization, exchange the authorization code for an access token bound to the collection.

curl --location --request POST 'https://api.onna.com/v1/collections/<COLLECTION_ID>/pair_credentials?auth_code=<AUTH_CODE>' \
--header 'Authorization: Bearer <token>'

Where:

  • auth_code is the authorization code you received during the authorization process.

A successful response returns 204 No Content.

Retrieve the List of Users

To retrieve the users available in the authorized Zoom account, send a GET request to the collection's /users endpoint.

curl --location --request GET 'https://api.onna.com/v1/collections/<COLLECTION_ID>/users?limit=100' \
--header 'Authorization: Bearer <token>'

The endpoint accepts two optional query parameters:

  • limit is the number of users to return per page. For Zoom the default and maximum is 300; a value greater than 300 is clamped to 300.
  • offset is the pagination cursor. To fetch the next page, pass the value from the previous response's next_page_token field. Omit it for the first page.

Example user response:

{
"results": [
{
"id": "zoom-user-1",
"data": {
"id": "zoom-user-1",
"first_name": "Lisa",
"last_name": "Simpson",
"email": "lisa@onnaqa.com"
}
},
{
"id": "zoom-user-2",
"data": {
"id": "zoom-user-2",
"first_name": "Bart",
"last_name": "Simpson",
"email": "bart@onnaqa.com"
}
}
],
"next_page_token": null
}

Where:

  • id is the unique identifier of the user. Use this value in the selected or excluded arrays when configuring sync filters.
  • data contains the user profile fields returned by Zoom (such as first_name, last_name, and email).
  • next_page_token is the cursor for the next page of results, or null when there are no more pages. To page through all users, pass this value as the offset query parameter on the next request and repeat until it is null.

Retrieve the List of Channels

To retrieve the channels for a Zoom user, send a GET request to the collection's /channels endpoint.

curl --location --request GET 'https://api.onna.com/v1/collections/<COLLECTION_ID>/channels?user=<USER_ID>&limit=100' \
--header 'Authorization: Bearer <token>'

The endpoint accepts these query parameters:

  • user is the Zoom user ID whose channels you want to list. This parameter is required.
  • limit is the number of channels to return per page. For Zoom the default and maximum is 300; a value greater than 300 is clamped to 300.
  • offset is the pagination cursor. To fetch the next page, pass the value from the previous response's next_page_token field. Omit it for the first page.

Example channel response:

{
"results": [
{
"id": "channel-1",
"name": "General",
"is_private": false
},
{
"id": "channel-2",
"name": "Project Updates",
"is_private": true
}
],
"next_page_token": null
}

Where:

  • id is the unique identifier of the channel.
  • name is the channel display name.
  • is_private indicates whether the channel is private.
  • next_page_token is the cursor for the next page of results, or null when there are no more pages.

Configure Sync Filters

Sync filters control what is synchronized. For Zoom, the sync_filters object uses three keys that match the Onna UI (Select content screen):

  • account_owners: which Zoom account owners (users) to sync. Use the id values from the /users endpoint.
  • content_selections: meeting content types to sync (the Meetings section in the UI).
  • chats: one-to-one chats and channels (the Chat section in the UI). Omit this key entirely if neither one-to-one chats nor channels are selected.

Update the collection with the selected configuration by sending a PATCH request.

Content types

The Onna UI Zoom collection: Select content screen maps to sync_filters as follows.

Meetings (content_selections)

UI labelAPI keyDescription
ChatschatIn-meeting chat messages
AudioaudioMeeting audio recordings
VideovideoMeeting video recordings
TranscriptstranscriptMeeting transcripts
AI Meeting NotesAI-meeting-notesZoom AI Companion meeting notes

Each type is set in content_selections.selected as a single-key object, for example { "chat": true } or { "transcript": false }.

AI Meeting Notes requires Zoom AI Companion and Cloud Recording enabled on the Zoom account. Cloud recording must also be active to collect in-meeting data; such data is only collected for licensed users.

Chat (chats)

UI labelAPI keyDescription
Chatsone-to-oneOne-to-one Zoom chat messages
ChannelschannelsZoom team chat channels. Use all_selected, selected, and excluded to pick specific channels (IDs from /channels).

Example structure for both chat options enabled with all channels:

"chats": {
"all_selected": true,
"selected": [
{ "one-to-one": true },
{
"channels": {
"all_selected": true,
"selected": [],
"excluded": []
}
}
]
}

Sync specific users with all content types

curl --location --request PATCH 'https://api.onna.com/v1/collections/<COLLECTION_ID>' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"sync_status": "pending",
"type_sync": "one",
"sync_filters": {
"account_owners": {
"all_selected": false,
"selected": [
{ "id": "zoom-user-1" }
],
"excluded": []
},
"content_selections": {
"all_selected": true,
"selected": [
{ "chat": true },
{ "audio": true },
{ "video": true },
{ "transcript": true },
{ "AI-meeting-notes": true }
]
},
"chats": {
"all_selected": true,
"selected": [
{ "one-to-one": true },
{
"channels": {
"all_selected": true,
"selected": [],
"excluded": []
}
}
]
}
}
}'

Sync all users

Set all_selected to true under account_owners with an empty selected array to sync every user in the Zoom account.

curl --location --request PATCH 'https://api.onna.com/v1/collections/<COLLECTION_ID>' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"sync_status": "pending",
"type_sync": "one",
"sync_filters": {
"account_owners": {
"all_selected": true,
"selected": [],
"excluded": []
},
"content_selections": {
"all_selected": true,
"selected": [
{ "chat": true },
{ "audio": true },
{ "video": true },
{ "transcript": true },
{ "AI-meeting-notes": true }
]
},
"chats": {
"all_selected": true,
"selected": [
{ "one-to-one": true },
{
"channels": {
"all_selected": true,
"selected": [],
"excluded": []
}
}
]
}
}
}'
The /users and /channels endpoints help you discover IDs for account_owners and channel selection. The sync filter keys are account_owners, content_selections, and chats, not users and channels.

Filter fields

The top-level request fields are:

FieldTypeDescription
sync_statusStringSync lifecycle state. Set to "pending" to queue a sync after filters are saved.
sync_filtersObjectZoom sync filter configuration (see below).
type_syncStringSync type. Supported values: "one", "arch", "auto".

The sync_filters object contains:

KeyDescription
account_ownersUser selection (before Select content in the UI). Same all_selected / selected / excluded structure. Each selected entry is { "id": "<user_id>" } from /users.
content_selectionsMeetings toggles. selected is an array of objects, each with one key: chat, audio, video, transcript, or AI-meeting-notes.
chatsChat toggles. selected contains { "one-to-one": true/false } and a nested channels object with all_selected, selected, and excluded.

A successful PATCH returns 204 No Content, indicating the filter configuration was saved.

Update Existing Filters

To change an existing filter configuration (for example, to add or remove users), issue another PATCH to the same collection endpoint with the full updated sync_filters object. The new value replaces the previous one.

Always send the complete sync_filters object on update. Fields that are omitted are treated as removed, not merged with the previous value.

Start the Sync

Once the filters are saved, initiate the sync process.

curl --location --request POST 'https://api.onna.com/v1/collections/<COLLECTION_ID>/start' \
--header 'Authorization: Bearer <token>'

A successful response (HTTP status code 200) indicates that the sync process has begun. Only the users allowed by the configured filters are pulled into the collection.

Simulate Token Expiry and Refresh the Token

If the access token expires, you can refresh it by using the refresh token.

curl --location --request POST 'https://api.onna.com/v1/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<client_id>' \
--data-urlencode 'client_secret=<client_secret>' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=<refresh_token>'

This will return a new access_token and refresh_token.

{
"access_token": "<new_access_token>",
"token_type": "bearer",
"expires_in": 86399
}

Clean Up

Once you are done, you can clean up by deleting both the collection and the workspace.

curl --location --request DELETE 'https://api.onna.com/v1/collections/<COLLECTION_ID>' \
--header 'Authorization: Bearer <token>'
curl --location --request DELETE 'https://api.onna.com/v1/workspaces/<WORKSPACE_ID>' \
--header 'Authorization: Bearer <token>'

Note: Deleting a collection or workspace is permanent and cannot be undone.