Slack Enterprise Collection
Slack Enterprise Collection Integration with Onna
Overview
This guide explains how to set up and interact with a Slack Enterprise (eslack) collection through the Onna Platform API.
You'll learn how to create a workspace, wallet, and collection, authorize access to Slack via OAuth2, list the users,
teams, and channels available in the Slack organization, configure sync filters to control exactly which custodians
and conversations are synchronized, start the sync, and clean up your environment afterward.
Slack sync filters support several content types that can be combined:
- Conversations - public channels (
public), private channels (private), direct messages (im), and group direct messages (mpim). - Custodians - per-user conversation selection, including controls for externally shared (Slack Connect) and multi-workspace shared channels.
- Root files - Slack Canvases (
canvas) and Lists (list) collected alongside conversations.
For a full reference of every sync filter field, see the Sync Filters Configuration Guide.
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 Slack data in Onna."
}'
Where:
nameis the name of the workspace.descriptionis a brief description of the workspace's purpose.
A successful response (201) will return:
{
"onna_id": "<WORKSPACE_ID>"
}
Create a Slack Wallet
Slack 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": "Slack Enterprise Collection Wallet",
"credential_type_name": "SlackEDatasource"
}'
Where:
nameis a label for the wallet.credential_type_nameis the credential type. For Slack Enterprise, useSlackEDatasource.
A successful response (201) will return:
{
"onna_id": "<WALLET_ID>"
}
Create a Slack Collection
Next, create a Slack collection within the workspace you created. The collection is the container for the users and content you will sync from Slack.
curl --location --request POST 'https://api.onna.com/v1/collections' \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"name": "My Slack Enterprise Collection",
"onna_parent_id": "<WORKSPACE_ID>",
"type": "eslack",
"credential_id": "<WALLET_ID>"
}'
Where:
nameis the name of the collection.onna_parent_idis the ID of the workspace that this collection will belong to.typeis the type of collection being created. For Slack Enterprise, the type iseslack.credential_idis the ID of the wallet you created for the Slack service.
A successful response (201) will return:
{
"onna_id": "<COLLECTION_ID>",
"type": "eslack"
}
You might also want to implement a naming convention (like Collection-{WorkspaceName}-Slack) for better organization.
Initiate OAuth2 Flow to Get an Authorization Code
To authorize access to Slack, initiate the OAuth2 flow. It will return an authorization URL. Open this URL in your browser to log in and grant the application access to Slack.
curl --location --request GET 'https://api.onna.com/v1/collections/authorization_url/eslack?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.
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. The token exchange is performed by the platform.
curl --location --request POST 'https://api.onna.com/v1/collections/<COLLECTION_ID>/pair_credentials?auth_code=<AUTH_CODE>' \
--header 'Authorization: Bearer <token>'
Where:
auth_codeis the authorization code you received during the authorization process.
A successful response returns 204 No Content.
POST /wallet/<WALLET_ID>/pair_credentials?auth_code=<AUTH_CODE>. Pairing at the collection level (shown above) is the typical approach.
Retrieve Users, Teams, and Channels
Before configuring sync filters, retrieve the entities available in the authorized Slack organization. You will use the
returned IDs when building the sync_filters object.
Users
Send a GET request to the collection's /users endpoint to list the custodians (users) available in the organization.
curl --location --request GET 'https://api.onna.com/v1/collections/<COLLECTION_ID>/users?limit=10' \
--header 'Authorization: Bearer <token>'
The endpoint accepts two optional query parameters:
limitis the number of users to return per page.offsetis the pagination cursor. To fetch the next page, pass the value from the previous response'soffsetfield. Omit it for the first page.
Example user response:
{
"users": [
{
"id": "U1234567890",
"name": "lisa.simpson",
"profile": {
"real_name": "Lisa Simpson",
"display_name": "Lisa",
"email": "lisa@onnaqa.com"
},
"teams": ["T1234567890"],
"is_bot": false,
"deleted": false
}
],
"offset": "U0987654321"
}
Where:
idis the unique Slack user ID. Use this value as a custodianidwhen configuring sync filters.nameis the user's Slack username.profilecontains the user'sreal_name,display_name, andemail.teamsis the list of team IDs the user belongs to.is_botindicates whether the user is a bot account.deletedindicates whether the user has been deactivated.offsetis the cursor for the next page of results, ornullwhen there are no more pages. To page through all users, pass this value as theoffsetquery parameter on the next request and repeat until it isnull.
Teams
Send a GET request to the collection's /teams endpoint to list the teams (workspaces within the Enterprise Grid).
curl --location --request GET 'https://api.onna.com/v1/collections/<COLLECTION_ID>/teams' \
--header 'Authorization: Bearer <token>'
Example team response (a JSON array):
[
{
"id": "T1234567890",
"name": "Engineering",
"description": ""
},
{
"id": "T0987654321",
"name": "Sales",
"description": ""
}
]
Where:
idis the Slack team ID. Use this value in theteamsfilter and as theteam_idof a conversation.nameis the team's display name.descriptionis the team's description (may be an empty string).
Channels
Send a GET request to the collection's /channels endpoint to list the conversations available for a given user and team.
This is useful for identifying channel IDs when configuring conversation-level filters.
curl --location --request GET 'https://api.onna.com/v1/collections/<COLLECTION_ID>/channels?user=<USER_ID>&
teams=<TEAM_ID>&limit=10&include_workspace_shared_all=true&include_workspace_shared_selected=false&types=public&types=private' \
--header 'Authorization: Bearer <token>'
Where:
useris the Slack user ID whose channels you want to list.teamsis the Slack team ID to scope the channels to.limitis the number of channels to return.typesselects which conversation types to return. Repeat the parameter for each type (public,private,im,mpim).include_workspace_shared_allincludes channels shared across all workspaces.include_workspace_shared_selectedincludes channels shared only with selected workspaces (slower to load).
Example channel response:
{
"results": [
{
"id": "C1234567890",
"type": "public",
"name": "general",
"team_id": "T1234567890",
"is_archived": false,
"is_shared": false,
"is_org_shared": false,
"is_ext_shared": false,
"shared_with": [],
"topic": {
"text": "Company-wide announcements and work-based matters",
"set_by": "U1234567890",
"date_set": 1513810069
},
"purpose": {
"text": "This channel is for workspace-wide communication and announcements.",
"set_by": "U1234567890",
"date_set": 1513810069
},
"is_file": false,
"is_file_channel": false
}
],
"offset": "C0987654321"
}
Where:
idis the Slack channel ID. Use this value as a conversationidwhen configuring sync filters.typeis the conversation type (public,private,im, ormpim).nameis the channel's display name.team_idis the team the channel belongs to. Pair it with the channelidin theconversations.selectedarray.is_shared,is_org_shared, andis_ext_sharedindicate how the channel is shared (across workspaces, across the org, or externally via Slack Connect).topicandpurposecontain the channel's topic and purpose text.offsetis the cursor for the next page of channels, ornullwhen there are no more pages.
Configure Sync Filters
Slack Enterprise collections always collect per custodian: you choose the users to sync, and for each user the
conversations to include. The sync_filters object must use this custodian shape, so custodians is required. A
channel-first (regular) payload, or one missing custodians, is rejected with 422 Unprocessable Entity.
Sync filters control which content is pulled into the collection, using the following top-level keys inside the sync_filters object:
custodians- required. The users to sync, and for each user the conversations to include along with external and multi-workspace sharing controls. List each user explicitly inselected— there is no "all custodians" shortcut (see the note below).types- selects which conversation types to sync (public,private,im,mpim).teams- selects which teams to include or exclude.collect_root_files- optionally collects Slack Canvases and Lists.
Update the collection with the selected configuration by sending a PATCH request.
Sync specific teams, users, and conversations
Set all_selected to false under teams and custodians, list the teams and users to include, and select individual
conversations per user. Each conversation entry pairs a channel id with its team_id.
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": {
"selected": [
{ "id": "public" },
{ "id": "private" },
{ "id": "im" },
{ "id": "mpim" }
]
},
"teams": {
"all_selected": false,
"sync_future": false,
"selected": [{ "id": "T1234567890" }]
},
"custodians": {
"all_selected": false,
"sync_future": false,
"selected": [
{
"id": "U1234567890",
"conversations": {
"all_selected": false,
"sync_future": false,
"selected": [
{ "id": "C1234567890", "team_id": "T1234567890" }
],
"check_workspace_sharing": true,
"check_external_sharing": true,
"only_ext_shared": false
}
}
]
}
}
}'
Sync all teams for selected users
Custodian collection requires listing each user you want to sync in custodians.selected; there is no "all custodians"
option, and setting custodians.all_selected to true with an empty selected array collects nothing. To collect
broadly, set teams.all_selected to true (every team) and give each custodian a conversations object with
all_selected set to true (every conversation that user is in).
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": {
"selected": [
{ "id": "public" },
{ "id": "private" },
{ "id": "im" },
{ "id": "mpim" }
]
},
"teams": {
"all_selected": true,
"sync_future": true,
"selected": [],
"excluded": []
},
"custodians": {
"all_selected": false,
"sync_future": false,
"selected": [
{
"id": "U1234567890",
"conversations": { "all_selected": true, "sync_future": true }
},
{
"id": "U0987654321",
"conversations": { "all_selected": true, "sync_future": true }
}
]
}
}
}'
all_selected behaves differently at each level. On custodians it is not honored — always list each userin selected. On a custodian's conversations it is honored: set it to true to collect every conversation that
user belongs to (as shown above), or false to collect only the conversations you list. The collection never discovers
users on its own, so append an entry to custodians.selected for every user you need.
Collect Canvases and Lists
To collect Slack Canvases and Lists alongside conversations, add a collect_root_files object. List each file type to
collect in selected, with all_selected set to true on each entry. Root files are collected for the custodians you
list in custodians.selected, so include the users whose Canvases and Lists you want.
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": {
"selected": [{ "id": "public" }]
},
"teams": {
"all_selected": true,
"sync_future": true,
"selected": [],
"excluded": []
},
"custodians": {
"all_selected": false,
"sync_future": false,
"selected": [
{
"id": "U1234567890",
"conversations": { "all_selected": true, "sync_future": true }
}
]
},
"collect_root_files": {
"all_selected": false,
"selected": [
{ "id": "canvas", "all_selected": true },
{ "id": "list", "all_selected": true }
]
}
}
}'
Filter fields
The top-level request fields are the same as any collection update:
| Field | Type | Description |
|---|---|---|
sync_status | String | Sync lifecycle state. Set to "pending" to queue a sync after filters are saved. |
sync_filters | Object | Slack sync filter configuration (see below). |
type_sync | String | Sync type. Supported values: "one", "arch", "auto". |
The types object selects which conversation types are collected:
| Field | Type | Description |
|---|---|---|
selected | Array | Conversation types to sync. Supported values: { "id": "public" }, { "id": "private" }, { "id": "im" }, { "id": "mpim" }. |
The teams object controls team selection:
| Field | Type | Description |
|---|---|---|
all_selected | Boolean | If true, all teams in the organization are included. When false, only teams listed in selected are included. |
sync_future | Boolean | Whether to include teams added in the future. |
selected | Array | Teams to include when all_selected is false. Each entry is { "id": "<team_id>" }. |
excluded | Array | Teams to exclude when all_selected is true. Each entry is { "id": "<team_id>" }. |
The custodians object controls user selection and, per user, their conversations:
| Field | Type | Description |
|---|---|---|
all_selected | Boolean | Required. Set to false for Slack Enterprise collections — users must be listed explicitly in selected. There is no "all users" expansion for custodians via the public API. |
sync_future | Boolean | Whether to include users added in the future. |
selected | Array | Required. The users to include. Each entry must contain a user id and a conversations object (see below). |
Each entry in custodians.selected contains a conversations object that scopes the channels collected for that user:
| Field | Type | Description |
|---|---|---|
all_selected | Boolean | If true, all of the user's conversations are included. When false, only conversations listed in selected are included. |
sync_future | Boolean | Whether to include conversations added in the future. |
selected | Array | Conversations to include when all_selected is false. Each entry is { "id": "<channel_id>", "team_id": "<team_id>" }. |
excluded | Array | Conversations to exclude when all_selected is true. Each entry is { "id": "<channel_id>", "team_id": "<team_id>" }. |
check_external_sharing | Boolean | If true, include externally shared (Slack Connect) conversations. Set to false to skip them. |
only_ext_shared | Boolean | If true, collect only externally shared conversations. |
check_workspace_sharing | Boolean | If true, include channels shared across multiple workspaces. Set to false to skip them. |
The optional collect_root_files object enables collection of Slack Canvases and Lists:
| Field | Type | Description |
|---|---|---|
all_selected | Boolean | Whether to collect all root file types. |
selected | Array | Specific file types to collect. Each entry is { "id": "canvas", "all_selected": true } or { "id": "list", "all_selected": true }. |
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 a custodian or include additional conversations),
issue another PATCH to the same collection endpoint with the full updated sync_filters object. The new value replaces
the previous one.
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 teams, custodians, and conversations 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.