Skip to main content

Microsoft Teams Enterprise Collection

Microsoft Teams Enterprise Collection Integration with Onna

Overview

This guide explains how to set up and interact with a Microsoft Teams (emsteams) collection through the Onna Platform API. You'll learn how to create a workspace and collection, authorize access to Microsoft 365 via OAuth2, list tenant users, teams, and channels, configure sync filters to control exactly which teams, channels, and user chats are synchronized, start the sync, and clean up your environment afterward.

Teams sync filters support two independent content types that can be combined:

  • Channels - messages from standard and private channels within Microsoft Teams teams.
  • Chats - one-on-one and group chat messages for specific custodian users.

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 Microsoft Teams 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 Teams Collection

Next, create a Teams collection within the workspace you created. The collection is the container for the teams, channels, and chats you will sync from Microsoft 365.

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

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 Microsoft Teams, the type is emsteams.

A successful response (201) will return:

{
"onna_id": "<COLLECTION_ID>",
"type": "emsteams"
}
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}-Teams) for better organization.

Initiate OAuth2 Flow to Get an Authorization Code

To authorize access to the Microsoft 365 tenant, initiate the OAuth2 flow. It will return an authorization URL. Open this URL in your browser to log in and grant the application access.

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

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.

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>' \
--header 'Content-Type: application/x-www-form-urlencoded'

Where:

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

Retrieve the List of Tenant Users

To retrieve the users available in the authorized Microsoft 365 tenant, send a GET request to the collection's /users endpoint. This is useful for identifying user IDs when configuring custodian-level chat sync filters.

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

Example user response:

{
"entries": [
{
"id": "f8a9c3b1-1234-4abc-9def-0987654321ab",
"display_name": "Lisa Simpson",
"email": "lisa@onnaqa.com"
},
{
"id": "d4c7b8e2-5678-4fff-aaaa-1122334455cc",
"display_name": "Bart Simpson",
"email": "bart@onnaqa.com"
}
],
"limit": 1000,
"next_marker": "<next_marker>"
}

Where:

  • id is the unique Microsoft 365 object ID of the user. Use this as the filter key when configuring per-user sync filters.
  • display_name is the user's display name.
  • email is the user's primary email address (userPrincipalName).

Configure Sync Filters

Sync filters control which content is pulled into the collection. Teams sync filters use the following top-level keys inside the sync_filters object:

  • types - selects which content types to sync (channels, chats, or both).
  • teams - selects which teams to include or exclude (only applies when syncing channels without a users key present).
  • A per-team key (<team_id>) - selects which channels to include or exclude within a specific team.
  • users - selects which custodian users to include. When present, activates custodian mode for both channel and chat syncing, and the top-level teams key is ignored.
  • A per-user key (<user_id>) - controls which teams are included for that user when syncing channels in custodian mode.

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

Sync all channels across all teams

Use all_selected: true under both teams and the types entry for channels to capture every channel in the tenant.

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",
"sync_filters": {
"types": {
"all_selected": false,
"selected": [{ "id": "channels" }]
},
"teams": {
"all_selected": true,
"selected": [],
"excluded": []
}
}
}'

Sync specific teams only

Set all_selected to false under teams and list the teams to include in selected.

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",
"sync_filters": {
"types": {
"all_selected": false,
"selected": [{ "id": "channels" }]
},
"teams": {
"all_selected": false,
"selected": [
{ "id": "<team_id_1>" },
{ "id": "<team_id_2>" }
],
"excluded": []
}
}
}'

Sync specific channels within a team

Combine a teams entry with a per-team key to select individual channels. The per-team key uses the team ID and contains a standard all_selected / selected / excluded filter.

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",
"sync_filters": {
"types": {
"all_selected": false,
"selected": [{ "id": "channels" }]
},
"teams": {
"all_selected": false,
"selected": [
{ "id": "<team_id_1>" }
],
"excluded": []
},
"<team_id_1>": {
"all_selected": false,
"selected": [
{ "id": "<channel_id_1>" },
{ "id": "<channel_id_2>" }
],
"excluded": []
}
}
}'

Sync chats for specific custodian users

Set types to include chats and list the users whose chats should be collected under users. All chats belonging to the listed users are included automatically.

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",
"sync_filters": {
"types": {
"all_selected": false,
"selected": [{ "id": "chats" }]
},
"users": {
"all_selected": false,
"selected": [
{ "id": "f8a9c3b1-1234-4abc-9def-0987654321ab" },
{ "id": "d4c7b8e2-5678-4fff-aaaa-1122334455cc" }
],
"excluded": []
}
}
}'

Sync both channels and chats

Include both channels and chats in the types filter. Use the users key to list custodian users, and a per-user key with all_selected: true to include all teams that user belongs to for channel syncing. Note that the top-level teams key is ignored when users is present; team scoping is controlled exclusively via per-user keys in this mode.

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",
"sync_filters": {
"types": {
"all_selected": false,
"selected": [
{ "id": "channels" },
{ "id": "chats" }
]
},
"users": {
"all_selected": false,
"selected": [
{ "id": "f8a9c3b1-1234-4abc-9def-0987654321ab" }
],
"excluded": []
},
"f8a9c3b1-1234-4abc-9def-0987654321ab": {
"all_selected": true
}
}
}'

Filter fields

The top-level request fields are the same as any collection update:

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

The types object inside sync_filters controls which content types are collected:

FieldTypeDescription
all_selectedBooleanIf true, all supported content types are collected.
selectedArrayContent types to collect. Supported values: { "id": "channels" } and { "id": "chats" }.
excludedArrayContent types to exclude when all_selected is true.

The teams object inside sync_filters controls team selection (only applies when no users key is present):

FieldTypeDescription
all_selectedBooleanIf true, all teams in the tenant are included. When false, only teams listed in selected are included.
selectedArrayTeams to include when all_selected is false. Each entry is { "id": "<team_id>" }.
excludedArrayTeams to exclude when all_selected is true. Each entry is { "id": "<team_id>" }.

Each per-team entry uses the team ID as its key and contains a standard filter object that controls channel selection within that team:

FieldTypeDescription
all_selectedBooleanIf true, all channels in the team are included.
selectedArrayChannels to include when all_selected is false. Each entry is { "id": "<channel_id>" }.
excludedArrayChannels to exclude when all_selected is true. Each entry is { "id": "<channel_id>" }.

The users object inside sync_filters activates custodian mode. When present, the top-level teams key is ignored and team selection is driven by per-user keys. users applies to both chat syncing and custodian channel syncing:

FieldTypeDescription
all_selectedBooleanIf true, all users in the tenant are included. When false, only users listed in selected are included.
selectedArrayUsers to include when all_selected is false. Each entry is { "id": "<user_id>" }.
excludedArrayUsers to exclude when all_selected is true. Each entry is { "id": "<user_id>" }.

Each per-user entry uses the user's Microsoft 365 object ID as its key and controls which teams are included for that user when channel syncing is active in custodian mode:

FieldTypeDescription
all_selectedBooleanIf true, all teams the user belongs to are eligible for channel syncing. If false, only teams listed in selected are included.
selectedArrayTeams to include for this user when all_selected is false. Each entry is { "id": "<team_id>" }.
excludedArrayTeams to exclude for this user when all_selected is true. Each entry is { "id": "<team_id>" }.

A successful PATCH returns 200 OK with no body, indicating the filter configuration was saved.

Update Existing Filters

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

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",
"sync_filters": {
"types": {
"all_selected": false,
"selected": [{ "id": "channels" }]
},
"teams": {
"all_selected": false,
"selected": [
{ "id": "<team_id_1>" },
{ "id": "<team_id_2>" },
{ "id": "<team_id_3>" }
],
"excluded": []
}
}
}'
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>' \
--header 'Content-Type: application/json'

A successful response (HTTP status code 200) indicates that the sync process has begun. Only the teams, channels, and user chats 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.