Slack
SlackService → SlackAdapter → Slack Web API
Method routing
Cursor pagination
What & Why
The Slack integration reads and writes Slack as the authenticated person, not as a bot. OAuth requests a user token (xoxp-…) alongside the optional bot token, so Octopus sees every conversation the user can see — public channels, private channels, DMs and group DMs — with no per-channel bot invite, and posts as them rather than as an app.
Every call flows through SlackAdapter, which picks the right token, handles cursor-based pagination, and surfaces Slack error codes as structured exceptions.
Three properties drive most deployments:
Complete visibility. A bot token only sees channels it was explicitly invited to and can never see DMs. The user token covers the person's whole Slack surface the moment they connect, which is what makes assistant-style use cases work at all.
Acting as the user. send_message posts under the person's own name by default. Pass send_as="bot" when you want the message to come from the app instead — for CI notifications, for example.
Search. search_messages maps to search.messages, which Slack exposes only to user tokens. It is the fastest way to answer "what was said about X" across every conversation at once.
The conversation ID prefix decides the token: D… (DM) and G… (private channel or group DM) require the user token, C… (public channel) prefers it and falls back to the bot. When an action needs the user token and none is stored, the API returns slack_reconnect_required rather than silently downgrading — falling back would read the wrong thing or post as the wrong identity.
Which Token Is Used
send_as="user". Slack only lets a message's original author edit or delete it, so update_message and delete_message take the same argument and it must match whoever sent it.Methods Reference
| Method | Category | Description | Key Params |
|---|---|---|---|
list_chats | Conversations | Channels and DMs unified, most recent first | limit, include_direct_messages, include_channels, unread_only |
list_channels | Channels | List channels the token can see | limit, exclude_archived, types, cursor, team_id |
get_channel | Channels | Fetch metadata for one channel | channel_id, include_num_members |
list_channel_members | Channels | Member user IDs for a channel | channel_id, limit |
list_messages | Messages | History for any conversation — channel, private, DM | channel_id, limit, oldest, latest, cursor, inclusive |
get_message | Messages | Fetch one message by timestamp | channel_id, message_ts |
list_thread_replies | Messages | Replies in a thread | channel_id, thread_ts, limit, oldest, latest, cursor, inclusive |
search_messages | Search | Full-text search across channels and DMs | query, max_results, page, sort, sort_dir |
send_message | Messages | Post to a channel or DM | channel_id, text, thread_ts, blocks, attachments, send_as |
update_message | Messages | Edit a message you sent | channel_id, message_ts, text, blocks, send_as |
delete_message | Messages | Delete a message you sent | channel_id, message_ts, send_as |
list_users | Users | List workspace members | limit |
get_user | Users | Fetch a user profile by ID | user_id |
get_connection_info | Connection | Authenticated user ID and team ID | – |
Required Slack App Scopes
Add these in your Slack app under OAuth & Permissions. The user scopes are what deliver DM access, full history and search.
User Token Scopes
| Scope | Unlocks |
|---|---|
chat:write | Send, edit and delete messages as the user |
channels:history / channels:read | Public channel messages and metadata |
groups:history / groups:read | Private channels the user belongs to |
im:history / im:read / im:write | Direct messages |
mpim:history / mpim:read / mpim:write | Group direct messages |
users:read / users:read.email | Resolve senders to names and emails |
search:read | search_messages |
files:read / files:write | Read and upload attachments |
reactions:read | Reactions on messages |
Bot Token Scopes
Only needed if the app should also act as itself (send_as="bot") or operate
without a signed-in user.
chat:write, channels:history, channels:read, groups:history,
groups:read, im:history, im:read, mpim:history, mpim:read,
users:read, users:read.email, channels:join
Workspaces connected before user tokens were requested have a bot token only.
DM, private-channel and search calls will return slack_reconnect_required
until the user re-runs the OAuth flow.
HTTP Example
Send a direct message as the authenticated user.
{
"channel_id": "D01ABCDEF",
"text": "Deploy complete",
"send_as": "user",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":white_check_mark: *Deploy complete*\nAll services healthy."
}
}
]
}
{
"id": "1747634400.000100",
"provider": "slack",
"channel_id": "D01ABCDEF",
"text": "Deploy complete",
"sender": { "id": "U9876543210", "name": "Alice" },
"is_own_message": true,
"sent_at": "2026-05-19T09:20:00Z"
}
send_as posts as the user. Pass "bot" to post as the app — not valid for DMs. The returned id is the message timestamp; pass it as thread_ts to reply in a thread.CLI Examples
# List every conversation, channels and DMs together
constellation slack list-chats --limit 20
# Read a DM thread (D… id — the user token is selected automatically)
constellation slack list-messages --channel-id D01ABCDEF --limit 50
# Read a public channel
constellation slack list-messages --channel-id C0123456 --limit 50
# Everything sent on one day (oldest/latest also take Slack ts or epoch seconds)
constellation slack list-messages --channel-id C0123456 --oldest 2026-01-01 --latest 2026-01-02
# Everything before a specific message — a message id is itself a valid bound
constellation slack list-messages --channel-id D01ABCDEF --latest 1747634400.000100
# ...and everything after it, including the message itself
constellation slack list-messages --channel-id D01ABCDEF --oldest 1747634400.000100 --inclusive
# Walk a long thread page by page (pass next_cursor back as --cursor)
constellation slack list-thread-replies --channel-id C0123456 --thread-ts 1747634400.000100 --limit 100
# Search everything the user can see
constellation slack search-messages --query "deployment failed"
# Search with Slack modifiers
constellation slack search-messages --query "from:@alice in:#engineering after:2026-01-01"
# Send a DM as yourself
constellation slack send-message --channel-id D01ABCDEF --text "Morning!"
# Post to a channel as the app instead of as yourself
constellation slack send-message --channel-id C0123456 --text "Build passed" --send-as bot
# Reply in a thread
constellation slack send-message --channel-id C0123456 --text "Reply" --thread-ts 1747634400.000100
# Edit a message you sent
constellation slack update-message --channel-id C0123456 --message-ts 1747634400.000100 --text "Deploy complete ✓"
# Delete a message you sent
constellation slack delete-message --channel-id C0123456 --message-ts 1747634400.000100
# Thread replies
constellation slack list-thread-replies --channel-id C0123456 --thread-ts 1747634400.000100
# Channels and members
constellation slack list-channels --limit 50
constellation slack list-channel-members --channel-id C0123456
# Who am I connected as
constellation slack get-connection-info