Skip to main content

Developing apps for Enterprise Grid

Welcome to the new home of Slack developer docs!

We're still building and not all features are available quite yet. Enjoy this peek into the future!

Not ready for the future? Return to the past at api.slack.com.

Enterprise Grid allows large organizations to collaborate across many workspaces. While many apps, integrations, and bots will work as expected on Enterprise Grid, there are enough new behaviors, conditions, and nuances to warrant reviewing your app for compatibility.

Read on if you are:

  • developing Slack apps for your own or other Enterprise Grid workspaces
  • readying Enterprise Grid support for tools, libraries, or frameworks

Requesting a sandbox

Building properly for Enterprise Grid or shared channels requires experiencing the unique constraints and opportunities yourself. If you don't already have access to an Enterprise Grid of workspaces, please complete the form below to request a sandbox. We'll get back to you as soon as possible.

Identifying Enterprise Grid workspaces

Workspaces don't always start out part of an Enterprise Grid. Thanks to mergers, acquisitions, and the inherent nature of life, any workspace may become part of an Enterprise Grid.

A single user may have an identity in Workspace A, and another in Workspace B. With Enterprise Grid, you can reconcile those identities and make that user a cross-referenced entity identifiable across multiple workspaces.

Enterprise IDs

If your app is in a workspace that's part of an Enterprise Grid organization, you will observe a constant and unique enterprise_id attribute through API methods and events. Below are notable methods:

If you store data, you'll want to warehouse the enterprise_id value. Just as you'd never store information about a user or their data without tying it to a workspace first, it's best to associate Enterprise Grid workspace data with its enterprise_id.

If your app is installed on multiple workspaces within an Enterprise Grid organization, you may want to utilize that position effectively by grouping data by enterprise_id values and using those new values as your primary source of truth.

Supporting the transition to Enterprise Grid

Some platform features require additional support in Enterprise Grid workspaces.

Slack apps require you to:

  • Support global user IDs.
  • Support users from other workspaces within the same Enterprise Grid using your application features.

The Events API requires you to:

The Web API requires you to:

Slash commands require you to:

  • Toggle on Escape channels, users, and links sent to your app for all Slash commands within the Slash Commands app management page. This will allow you to identify channels and users by ID. See the Slash commands guide for more info.
  • Support user ID fields containing global user IDs
  • Be aware that Slash commands can only be invoked by users belonging to the workspace it is installed in.
Legacy integrations

Legacy bot users are more likely than other integration points to require additional work for exemplary performance on Enterprise Grid workspaces.

Legacy custom integrations have few programmatic signals to interpret and off-the-shelf code may not know how to handle certain situations like shared channels.

Legacy message buttons require you to support user ID fields containing global user IDs and to support action invocations by users from other workspaces.

Legacy RTM API usage will require additional effort to prevent duplicative messages and other undesired behaviors. See Using the RTM API on Enterprise Grid for more detail.

Enable organization-wide installation

To install your app on an Enterprise Grid organization, it must become org-ready:

  1. Navigate to OAuth & Permissions, scroll down to Scopes, and add any bot scope to your app, such as team:read. A bot scope is required for the next step to be available.
  2. In the Org Level Apps section in the sidebar, select Opt-In, then select Yes, Opt-in at the confirmation prompt. This will be reflected in the app manifest as follows:
    "settings": {
"org_deploy_enabled": true,
...
}
  1. From the Manage Distribution section in the app settings sidebar, you will now see that Private Distribution is enabled Private distribution lets your app gain access to all of the workspaces in an organization.
  2. Select Collaborators under the Settings section. Add an Org Admin user as a collaborator.

Requesting to install the app to an organization means that an Org Admin will receive a direct message from Slackbot to review the request. Approving a request to install to the org means the admin installs the app to the org, then further decides which workspaces to add it to.

For more information about how to add apps to workspaces from your Enterprise Grid organization, refer to Manage apps on Enterprise Grid.

Implement an OAuth flow

If you plan on making your app available for other organizations to install, or to list it in the Slack Marketplace, it is recommended that you follow the OAuth flow. This option is only available to apps that do not have custom steps.

When an Org Admin installs your app across the entire organization, it will not yet be installed to any workspaces in the organization. Therefore, once you have completed the OAuth flow, you'll likely want to redirect an installing Admin back to a modal that will allow them to add the app to individual workspaces. For example:

https://app.slack.com/manage/ORG_ID/integrations/profile/APP_ID/workspaces/add

You need to determine whether the installation happened on an organization, as opposed to an individual workspace. In order to do that, look for the is_enterprise_install boolean field in the oauth.v2.access API method response:

{
"ok": true,
"access_token": "xoxb-XXXX",
"token_type": "bot",
"scope": "identify,users:read",
"bot_user_id": "W123ABC456",
"app_id": "A123ABC456",
"team": null,
"enterprise": {
"id": "E123ABC456",
"name": "Jesse Slacksalot"
},
"is_enterprise_install": true,
"authed_user": {
"id": "WXXXX",
"access_token": "xoxp-XXXX"
...
}
}

You'll also want to consider redirecting your installer after OAuth for your organization-ready app, since the app won't actually be added to any workspaces yet. Consider redirecting to a modal that adds the app to workspaces, so that you can remind the installing Org Admin that they still need to do so:

https://app.slack.com/manage/ENTERPRISE_ID/integrations/profile/APP_ID/workspaces/add

Handle unknown users gracefully

If your app is used as part of a shared channel, it will encounter users it is not aware of, and the users.list API method won't return users from other workspaces in its payload.

To find users from another workspace on an Enterprise Grid, use the users.info method and query by their "foreign" user ID. Many apps need only a user's ID, and won't need additional information to operate.

Not only will you encounter user IDs belonging to other workspaces, but you'll also encounter the artifacts of their existence and workspace cross-pollination. Messages will be authored by these users, and if they fall within your app's functionality, you should respond as you normally would. Messages may also mention users on other workspaces. If your messages contain interactive elements, you may receive invoked actions from these users, and should handle them just as you would a "native" workspace user.

If you provide a slash command, you'll want to handle mentions of members from other workspaces. We strongly recommend turning on entity resolution so that you can resolve mentioned users.

Handle user object changes

In order to work across an organization, your app needs to be prepared for users and channels that span multiple workspaces. You'll likely want to map users in Slack to users in your system.

If your app already stored some local IDs from a workspace that subsequently merged into an Enterprise organization, the translation layer will continue to work as it did before.

For more insight into working with users in Enterprise organizations, check out the guide to single-workspace Enterprise apps.

User objects on Enterprise Grid workspaces now have an enterprise_user attribute, containing fields with additional context about the user in the larger Enterprise Grid organization:

enterprise_user fieldsDescription
idThe user's ID, which might start with U or W.
enterprise_idThe unique ID for this particular Enterprise Grid organization.
enterprise_nameThe name of this umbrella organization.
is_adminA boolean value indicating whether this user administers this Enterprise Grid.
is_ownerA boolean value indicating whether this user is the owner of this enterprise organization.
teamsAn array of team (workspace) IDs within the containing enterprise organization that this user belongs to.

User IDs

Within an Enterprise Grid, all users have a single, global ID beginning with either the letter U or W. The specific prefix does not indicate anything in particular.

Slack will automatically convert users' pre-Enterprise migration ID references to their singular Enterprise ID. This allows your app to remain backwards compatible for users identified on a workspace before the days of Enterprise Grid.

Users created after a workspace became part of an Enterprise will have no pre-Enterprise-migration ID.

Shared channel considerations

Your odds of encountering a Slack Connect channel are high when developing an app for Enterprise Grid. These channels are shared between one or more workspaces or organizations.

When you develop your app, decide which features should work with Slack Connect channels.

Once you've done that, remember to determine the type of conversation you're working with before you perform an action. Call the conversations.info method if you need to determine what kind of channel, DM, or MPDM you're dealing with.

Internal integration considerations

As with all Slack apps, installation and ownership of apps is on a workspace basis. Apps that are locked to a single workspace cannot be installed across an Enterprise Grid.

Slack Marketplace considerations

If your app is part of the Slack Marketplace, you'll want to let us know that you've prepared it for Enterprise Grid workspaces. We'll do some additional testing and give you feedback on anything that could be improved.

Using APIs with organization-ready apps

For the most part, APIs at Slack work the same with all apps. However, there are some exceptions.

Use the team_id parameter

Since your app's token now can represent installations in many workspaces, some API methods will require a team_id parameter to indicate which workspace to act on.

You may have certain installations of your app that are on a single workspace, while other installations are deployed across organizations. A safe option is to always pass a team_id parameter to these methods. If your token is a single-workspace installation, the team_id parameter will be accepted, but ignored.

Here's the full list of methods that require a team_id parameter when used by an organization-ready app:

You can call API endpoints that do not use a team_id parameter, but the behavior may be inconsistent. For example, you can call the conversations.read API method to retrieve information from channels that are shared across multiple workspaces within the organization using an org token, even if the app is not deployed to any workspaces within the org. However, if a channel only exists on a single workspace, the app will fail to retrieve any information and will return a team_access_not_granted error instead.

Use the context_team_id field

You may also come across the context_team_id field in your org-wide travels.

We use this field behind the scenes to resolve which channels come from which workspaces within the organization, and what roles and preferences are applied to those channels. For all channel types, this field represents the perspective through which the viewing user is accessing the channel. Let's look at an example.

Let's say there is an Enterprise Grid instance called Middle Earth. Within that instance, there are two workspaces: Rohan and Gondor. You are a user in the Gondor workspace.

  • For both workspace's non-shared channels—or for all channels that may be shared, but are hosted by your team (in this case, Gondor)—the team ID comes from the team_id field.
  • Now, someone in the Rohan workspace shares the #oath-of-eorl channel with Gondor. In this case, since the shared channel is hosted by the "away" workspace, the team ID comes from the context_team_id field.

This field is used in outgoing dispatches only (such as Block Kit actions and other similar events); that is, it's not a field you'll be supplying to an API method call. We just wanted you to be aware of it and what it's used for in case it shows up in your logs! However, you can optionally supply this same information by using the client_context_team_id field when calling any API method that requires the channel argument. A couple examples are the chat.postMessage or chat.update API methods.

Leverage additional event payload info

Event payloads now contain information on the [authorizations] they apply to.

You'll see the is_enterprise_install boolean inside the authorizations object. This boolean tells you whether the event is being sent to an organization-wide installation of your app.

{
"token": "XXYYZZ",
"is_ext_shared_channel": false,
"team_id": "T123ABC456",
"api_app_id": "A123ABC456",
"event": {...},
"type": "event_callback",
"event_id": "Ev123ABC456",
"event_time": 1234567890,
"authorizations": [
{
"enterprise_id": "E324567",
"team_id": "T423567",
"user_id": "W43567",
"is_bot": false,
"is_enterprise_install": true
}
]
}

The authorizations object is truncated at a single installation. If you're not sure which installations have the ability to see the event, call the apps.event.authorizations.list API method to get a full installation list.

Leverage additional events and methods

There are events and methods to help you keep track of which workspaces within an organization-wide deployment your app actually has access to.

Two Events API events indicate to you when your organization-ready app has gained or lost access to a new workspace within your org:

Subscribe to these events to have an up-to-date list of workspaces to monitor and act in.

In addition, you can now use the auth.teams.list API method to obtain a full list of workspaces your organization-ready app has been approved for. Call the method with your token acquired from installing your app on an Enterprise organization.

The Events API

If you're using the Events API, you don't have to worry about duplicate messages from shared channels. We'll only send one event, regardless of how many workspaces within the organization your app is installed on.

Look for the authed_teams node that arrives as part of the "wrapper" around delivered events. It contains a collection of team IDs within an organization that this delivery is on behalf of.

Here's an example payload of a shared channel's message being delivered on behalf of multiple workspaces:

{
"token": "ecto1EZslimer",
"team_id": "T111AAA111",
"api_app_id": "A123ABC456",
"event": {
"type": "message",
"user": "W123ABC456",
"text": "It's time to slacktivate!",
"team": "T111AAA111",
"source_team": "T111AAA111",
"user_team": "T111AAA111",
"user_profile": {
"avatar_hash": "g56821b98743",
"image_72": "https://...png",
"first_name": "Jesse",
"real_name": "Jesse Slacksalot",
"name": "jesse.slacksalot"
},
"ts": "1485371714.000002",
"channel": "C123ABC456",
"event_ts": "1485371714.000002"
},
"type": "event_callback",
"authed_users": [
"W3MBP5799"
],
"authed_teams": [
"T222BBB222",
"T111AAA111"
]
}

In this example, the application is installed on two workspaces on an Enterprise Grid and is party to a conversation in a shared channel. The message originates from team T111AAA111 and is delivered as a single event for both teams, including T222BBB222.

When a workspace migrates to an Enterprise Grid organization

In most cases, an Enterprise Grid is formed by combining multiple independent Slack workspaces together. During this period of time where data is migrated and made compatible with Grid's organization structures, platform interactions may be unavailable, both for users and your applications. For the Web API, you may encounter the team_added_to_org error during this time.

Migration time varies depending team-to-team and organization-to-organization. When encountering errors, practice an exponential backoff strategy to help manage these periods by attempting connections at incrementally increasing rates: 1 second to 3 seconds to 10 seconds to 30 seconds to 1 minute, and so on.

To best plan for migrations, subscribe to Enterprise Grid-related app events as part of the Events API. Using these events, your app can pause and resume activity as appropriate:

If your app has disabled the translation layer, use the migration.exchange method to receive global user IDs for any of your stored local user IDs.

Refer to migrating existing apps to Enterprise Grid for more information.

Toggle the translation layer

For existing apps, the best thing you can do is to use the migration.exchange method to update all records you have for an existing workspace with those from an Enterprise Grid.

That way, you won't need to worry about a "translation layer" or maintaining two IDs for a single user.

Slack Apps can turn on a translation layer in their app settings that will display "local" historical user IDs beginning with U for users that existed prior to an Enterprise Grid migration for a workspace the app was already installed on. It also lets you use these classic user IDs within a migrated workspace; it's meant to be used temporarily.

We strongly recommend you turn this translation layer off after using migration.exchange and going all-in with global user IDs, regardless of which letter they start with.

Disable the translation layer by navigating to application management for your app and finding the User ID Translation panel. If you need to update local user IDs you've stored in a database or in other ways, first use the migration.exchange method with the relevant user or bot tokens to receive global user IDs in bulk.

Next steps

✨ Read more about using Slack Connect API methods.