Integrations
Slack
Connect Conductor to Slack to send messages, manage channels, list users, upload files, and react to messages. Covers bot tokens, user tokens, OAuth scopes, Socket Mode for local dev, and every common error you'll hit.
Authentication
Slack supports two token types. For Conductor, bot tokens are almost always the right choice. User tokens act on behalf of a specific person and are better suited to personal automation.
Bot Token (xoxb-)
Issued to the Slack App itself. Acts as the bot user. Scoped to what the app is allowed to do. Recommended for shared workflows, automations, and production integrations. Stays valid until revoked.
User Token (xoxp-)
Acts as a specific Slack user. Can read DMs and private channels that user has access to. Useful for personal scripts. Gets revoked when the user logs out or changes password. Less preferred for production.
Creating a Slack App
- 01Go to api.slack.com/apps and click Create New App.
- 02Choose From scratch. Give it a name and pick your workspace.
- 03Under OAuth & Permissions, scroll to Bot Token Scopes and add the scopes you need (see table below).
- 04Click Install to Workspace. Authorize on the OAuth screen.
- 05Copy the Bot User OAuth Token (starts with xoxb-). This goes in your Conductor config.
- 06Under Basic Information → App Credentials, copy your Signing Secret.
You can customize the bot's display name and icon under App Home → Your App's Presence in Slack. The display name is what appears in channels when the bot posts messages.
OAuth Scopes
Add these under OAuth & Permissions → Bot Token Scopes. Start with the minimum you need — Slack lets you add scopes later (but requires reinstalling the app after changes).
| Scope | What it allows |
|---|---|
| channels:read | List public channels and see channel info |
| channels:history | Read messages in public channels the bot has joined |
| channels:join | Allow bot to join public channels |
| chat:write | Send messages as the bot |
| chat:write.public | Send messages to channels the bot hasn't joined |
| users:read | View basic user info (name, email with users:read.email) |
| users:read.email | View email addresses of users |
| files:read | Read files shared in channels the bot can access |
| files:write | Upload, edit, and delete files |
| reactions:read | View emoji reactions and their authors |
| reactions:write | Add and remove emoji reactions |
| im:read | View direct messages that the bot is in |
| im:write | Start direct messages with people |
| im:history | Read messages in direct message conversations |
| groups:read | View basic info about private channels the bot is in |
| groups:history | Read messages in private channels the bot has joined |
| mpim:read | View basic info about group direct messages the bot is in |
| mpim:history | Read messages in group direct messages |
After adding scopes, always click Reinstall to Workspace. Scopes only take effect after reinstall.
Socket Mode (local dev)
Socket Mode lets your app receive events over a persistent WebSocket connection instead of requiring a public HTTPS URL. This is ideal for local development or environments behind a firewall. To enable it, go to Socket Mode in your app settings, toggle it on, and generate an App-Level Token with the connections:write scope. App-level tokens start with xapp-.
{
"plugins": {
"slack": {
"token": "xoxb-your-bot-token-here",
"app_token": "xapp-1-your-app-level-token",
"socket_mode": true
}
}
}Event subscriptions still need to be configured in your app settings under Event Subscriptions, even when using Socket Mode. Subscribe to events like message.channels, message.im, and app_mention.
Conductor config
{
"plugins": {
"slack": {
"token": "xoxb-your-bot-token-here",
"signing_secret": "your-signing-secret"
}
}
}Store your bot token in an environment variable and reference it via ${SLACK_BOT_TOKEN} rather than hardcoding it. Never commit tokens to source control.
Available tools
| Tool | Description |
|---|---|
| slack.message.send | Post a message to a channel or DM. Supports plain text and Block Kit blocks. |
| slack.message.list | Fetch recent messages from a channel. Supports pagination and time-range filtering. |
| slack.channel.list | List all public (and optionally private) channels in the workspace. |
| slack.channel.create | Create a new channel. Bot must have channels:manage scope. |
| slack.channel.archive | Archive an existing channel. Requires channels:manage scope. |
| slack.user.list | List all users in the workspace including bots and deactivated accounts. |
| slack.user.info | Get detailed profile info for a specific user by their user ID. |
| slack.file.upload | Upload a file and optionally share it to one or more channels. |
| slack.reaction.add | Add an emoji reaction to a specific message by channel and timestamp. |
| slack.thread.reply | Reply to a message in its thread using the parent message's timestamp. |
Usage examples
Sending messages
// Send a message to a channel
slack.message.send({
channel: "C0123456789", // channel ID, not name
text: "Hello from Conductor!"
})
// Send with blocks (Block Kit)
slack.message.send({
channel: "C0123456789",
text: "Fallback text",
blocks: [
{
type: "section",
text: { type: "mrkdwn", text: "*Hello!* This is a block message." }
}
]
})Replying to threads
// Reply in a thread
slack.thread.reply({
channel: "C0123456789",
thread_ts: "1683000000.123456", // timestamp of the parent message
text: "This is a thread reply"
})Uploading files
// Upload a file to a channel
slack.file.upload({
channels: ["C0123456789"],
content: "File contents here as a string",
filename: "report.txt",
title: "My Report"
})Adding reactions
// Add a reaction to a message
slack.reaction.add({
channel: "C0123456789",
timestamp: "1683000000.123456",
name: "thumbsup" // emoji name without colons
})Finding channel and workspace IDs
Slack's API always uses IDs, never names. Channel names can change; IDs cannot.
// Channel IDs look like: C0123456789
// To find a channel ID in Slack:
// 1. Right-click the channel name → "Copy link"
// The link ends in /C0123456789 — that's the ID
// 2. Or: channel details → scroll to bottom → "Channel ID"
//
// Workspace ID (team ID) looks like: T0123456789
// Settings & administration → Workspace settings
// The URL contains /T0123456789Rate limits
Slack uses a tiered rate limit system. Each API method belongs to a tier. When you exceed a tier's limit, the API returns HTTP 429 with a Retry-After header specifying seconds to wait.
| Tier | Rate limit | Example methods |
|---|---|---|
| Tier 1 | ~1 req/min | files.list, conversations.list, users.list |
| Tier 2 | ~20 req/min | conversations.history, conversations.replies |
| Tier 3 | ~50 req/min | chat.postMessage, reactions.add |
| Tier 4 | ~100 req/min | auth.test, users.info |
| Special | 1 msg/sec per channel | chat.postMessage (per channel limit) |
Common errors
channel_not_found
Channel ID is wrong or bot can't see the channel
Fix: Verify the channel ID. Make sure it's a channel ID (C...) not a name.
not_in_channel
Bot is not a member of the channel
Fix: Invite the bot: /invite @YourBotName in the channel, or add channels:join scope.
missing_scope
Token doesn't have the required OAuth scope
Fix: Add the scope in your Slack App settings → OAuth & Permissions, then reinstall.
token_revoked
The token has been revoked by an admin or user
Fix: Reinstall the app to the workspace to get a fresh token.
ratelimited
Too many API requests too quickly
Fix: Respect the Retry-After header. Implement exponential backoff.
invalid_auth
The token format is wrong or the token is invalid
Fix: Check the token starts with xoxb- (bot) or xoxp- (user). No extra spaces.
account_inactive
The Slack account associated with the token is deactivated
Fix: Reauthorize with an active account. For bot tokens, the app itself must be active.
Security best practices
- —Store tokens in environment variables or a secrets manager. Never hardcode them in config files committed to source control.
- —Request only the scopes your integration actually needs. Slack's principle of least privilege reduces blast radius if a token is leaked.
- —Rotate tokens periodically and immediately if you suspect compromise. Revoke old tokens under OAuth & Permissions → Revoke tokens.
- —For production, use a dedicated bot account rather than a personal user token. This way the integration doesn't break if someone leaves the team.
- —Verify the X-Slack-Signature header on incoming webhooks using your signing secret to prevent spoofed requests.