> ## Documentation Index
> Fetch the complete documentation index at: https://docs.guild.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Slack

> Give agents authenticated access to the Slack Web API.

The Slack integration provides agents with access to the Slack Web API through Guild's OAuth integration. Slack is dynamically resolved from its OpenAPI specification at runtime, so agents do not import a Slack-specific package.

## Authentication

* **Type:** OAuth 2.0
* **Token management:** Slack tokens don't expire — no refresh needed

### Setup

<Steps />

### OAuth scopes

| Category        | Scopes                                                                  |
| --------------- | ----------------------------------------------------------------------- |
| Channels        | `channels:history`, `channels:join`, `channels:manage`, `channels:read` |
| Groups          | `groups:history`, `groups:read`, `groups:write`                         |
| Direct messages | `im:history`, `im:read`                                                 |
| Group DMs       | `mpim:history`, `mpim:read`                                             |
| Messages        | `chat:write`, `app_mentions:read`                                       |
| Files           | `files:read`, `files:write`                                             |
| Reactions       | `reactions:read`, `reactions:write`                                     |
| Users           | `users:read`, `users:read.email`, `users.profile:read`                  |
| User groups     | `usergroups:read`, `usergroups:write`                                   |
| Team            | `team:read`                                                             |

## Usage

Slack is dynamically resolved, so you do not import a Slack-specific package. Register the operations your agent needs with `guildServiceTool()` from the Guild Agents SDK, passing `slack` as the service name. Name each tool with the `slack_` prefix to match the underlying operation — for example, the `chat_post_message` operation becomes the `slack_chat_post_message` tool.

```typescript theme={null}
import { guildServiceTool, llmAgent } from "@guildai/agents-sdk"
import { z } from "zod"

const slack_chat_post_message = guildServiceTool("slack", {
  description: "Post a message to a Slack channel.",
  inputSchema: z.object({
    channel: z.string(),
    text: z.string(),
  }),
})

export default llmAgent({
  description: "An agent that manages Slack messages",
  tools: { slack_chat_post_message },
})
```

### Selecting specific tools

Agents perform better with fewer tools. Register only the operations your agent needs — add each one as its own `guildServiceTool("slack", ...)` entry:

```typescript theme={null}
import { guildServiceTool, llmAgent } from "@guildai/agents-sdk"
import { z } from "zod"

const slack_chat_post_message = guildServiceTool("slack", {
  description: "Post a message to a Slack channel.",
  inputSchema: z.object({ channel: z.string(), text: z.string() }),
})

const slack_conversations_list = guildServiceTool("slack", {
  description: "List channels in the workspace.",
  inputSchema: z.object({ limit: z.number().optional() }),
})

const slack_conversations_history = guildServiceTool("slack", {
  description: "Fetch a channel's message history.",
  inputSchema: z.object({ channel: z.string(), limit: z.number().optional() }),
})

export default llmAgent({
  description: "An agent that posts Slack updates",
  tools: {
    slack_chat_post_message,
    slack_conversations_list,
    slack_conversations_history,
  },
})
```

## API endpoints

<AccordionGroup>
  <Accordion title="Messages">
    | Operation                       | Method | Path                           |
    | ------------------------------- | ------ | ------------------------------ |
    | `chat_post_message`             | POST   | `/chat.postMessage`            |
    | `chat_update`                   | POST   | `/chat.update`                 |
    | `chat_delete`                   | POST   | `/chat.delete`                 |
    | `chat_post_ephemeral`           | POST   | `/chat.postEphemeral`          |
    | `chat_schedule_message`         | POST   | `/chat.scheduleMessage`        |
    | `chat_scheduled_messages_list`  | GET    | `/chat.scheduledMessages.list` |
    | `chat_delete_scheduled_message` | POST   | `/chat.deleteScheduledMessage` |
    | `chat_get_permalink`            | GET    | `/chat.getPermalink`           |
  </Accordion>

  <Accordion title="Conversations">
    | Operation                   | Method | Path                        |
    | --------------------------- | ------ | --------------------------- |
    | `conversations_list`        | GET    | `/conversations.list`       |
    | `conversations_info`        | GET    | `/conversations.info`       |
    | `conversations_history`     | GET    | `/conversations.history`    |
    | `conversations_replies`     | GET    | `/conversations.replies`    |
    | `conversations_members`     | GET    | `/conversations.members`    |
    | `conversations_join`        | POST   | `/conversations.join`       |
    | `conversations_leave`       | POST   | `/conversations.leave`      |
    | `conversations_invite`      | POST   | `/conversations.invite`     |
    | `conversations_archive`     | POST   | `/conversations.archive`    |
    | `conversations_unarchive`   | POST   | `/conversations.unarchive`  |
    | `conversations_set_topic`   | POST   | `/conversations.setTopic`   |
    | `conversations_set_purpose` | POST   | `/conversations.setPurpose` |
  </Accordion>

  <Accordion title="Reactions">
    | Operation          | Method | Path                |
    | ------------------ | ------ | ------------------- |
    | `reactions_add`    | POST   | `/reactions.add`    |
    | `reactions_get`    | GET    | `/reactions.get`    |
    | `reactions_list`   | GET    | `/reactions.list`   |
    | `reactions_remove` | POST   | `/reactions.remove` |
  </Accordion>

  <Accordion title="Files">
    | Operation      | Method | Path            |
    | -------------- | ------ | --------------- |
    | `files_info`   | GET    | `/files.info`   |
    | `files_delete` | POST   | `/files.delete` |
  </Accordion>

  <Accordion title="Pins">
    | Operation     | Method | Path           |
    | ------------- | ------ | -------------- |
    | `pins_add`    | POST   | `/pins.add`    |
    | `pins_list`   | GET    | `/pins.list`   |
    | `pins_remove` | POST   | `/pins.remove` |
  </Accordion>

  <Accordion title="Reminders">
    | Operation            | Method | Path                  |
    | -------------------- | ------ | --------------------- |
    | `reminders_add`      | POST   | `/reminders.add`      |
    | `reminders_complete` | POST   | `/reminders.complete` |
    | `reminders_delete`   | POST   | `/reminders.delete`   |
    | `reminders_list`     | GET    | `/reminders.list`     |
  </Accordion>

  <Accordion title="Users">
    | Operation               | Method | Path                   |
    | ----------------------- | ------ | ---------------------- |
    | `users_info`            | GET    | `/users.info`          |
    | `users_list`            | GET    | `/users.list`          |
    | `users_lookup_by_email` | GET    | `/users.lookupByEmail` |
    | `users_profile_get`     | GET    | `/users.profile.get`   |
  </Accordion>

  <Accordion title="User groups">
    | Operation                 | Method | Path                       |
    | ------------------------- | ------ | -------------------------- |
    | `usergroups_create`       | POST   | `/usergroups.create`       |
    | `usergroups_list`         | GET    | `/usergroups.list`         |
    | `usergroups_update`       | POST   | `/usergroups.update`       |
    | `usergroups_users_list`   | GET    | `/usergroups.users.list`   |
    | `usergroups_users_update` | POST   | `/usergroups.users.update` |
  </Accordion>

  <Accordion title="Team">
    | Operation    | Method | Path          |
    | ------------ | ------ | ------------- |
    | `team_info`  | GET    | `/team.info`  |
    | `emoji_list` | GET    | `/emoji.list` |
    | `bots_info`  | GET    | `/bots.info`  |
  </Accordion>
</AccordionGroup>

## Webhook events

Slack uses an app-scoped webhook model — a single webhook receives all events and Guild routes them to matching triggers.

| Event                   | Description                                    |
| ----------------------- | ---------------------------------------------- |
| `app_mention`           | The Guild bot is mentioned in a channel        |
| `message`               | A message is posted in a channel the bot is in |
| `reaction_added`        | A reaction is added to a message               |
| `reaction_removed`      | A reaction is removed from a message           |
| `member_joined_channel` | A user joins a channel                         |
| `channel_created`       | A new channel is created                       |

Events can be filtered to specific channels by setting `channel_ids` in the service configuration. Messages sent by the Guild bot itself are automatically excluded to prevent feedback loops.

## Limitations

* The bot must be invited to channels to receive `message` events (except `app_mention`, which works without an invite)
* If the app is uninstalled from the workspace, credentials must be reconnected in Guild

# **How** **the** **Slack** **Integration** **Works**

  **Auth:** **OAuth** **2.0,** **Bot** **Token** **Only**

 Guild uses Slack's **OAuth** **v2** flow. When a user connects Slack, they go through the standard redirect dance and Guild gets back a **bot** **access** **token** — a single token scoped to the installed workspace.

Key things about this token:

  - **Never** **expires.** Slack bot tokens are long-lived with no expiry. Guild stores it once and uses it forever — no refresh logic needed.

  - **No** **user** **token.** Guild only gets a bot token, not a per-user token. All API calls are made as the bot, not as the user who installed it.

  - **One** **workspace** **per** **connection.** A single Slack install = one team\_id + one bot token. If you want multiple Slack workspaces in one Guild workspace, that's not

  supported.

  - **Bot** **user** **ID** **is** **captured** **at** **install** **time** and stored alongside the token — this is used to filter out the bot's own messages to prevent infinite loops.

  **Slack's** **Architecture** **and** **What** **It** **Means** **Here**

  Slack's API is split into two worlds:

  **1.** **Events** **(inbound)** **—** **via** **webhooks**

  Slack pushes events to a single registered URL (/webhooks/slack). Guild validates the payload with HMAC-SHA256 (using X-Slack-Signature + X-Slack-Request-Timestamp), deduplicates by event\_id, and routes to matching triggers.

 Supported events: message, app\_mention, reaction\_added/removed, member\_joined\_channel, channel\_created.

 **Limitations** **of** **the** **event** **model:**

  - The bot must be **invited** **to** **a** **channel** to receive message events there. app\_mention is the exception — that works everywhere.

  - If channel\_ids is empty in the trigger config, **all** **channels** are processed (no default filtering). Easy to accidentally flood an agent with events.

  - Events are app-scoped — there's no per-user event subscription.

  **2.** **API** **calls** **(outbound)** **—** **via** **Web** **API** **proxy**

 Agents make Slack API calls (post messages, list channels, etc.) through Guild's HTTP proxy, which injects the bot token. The runtime exposes \~45 operations as agent tools (slack\_chat\_post\_message, slack\_conversations\_list, etc.).

Because everything uses the bot token, all messages come from the bot — you can't post as a specific user.

**Other** **Noteworthy** **Limitations**

  - **App** **uninstall** **=** **silent** **breakage.** If someone uninstalls the Slack app from their workspace, the token goes invalid. There's no revocation webhook handling — the user just has to reconnect.

  - **Payload** **scrubbing.** Before webhooks reach agents, Guild strips URLs, thumbnails, avatars, and permalinks to reduce token usage. Agents won't see file previews or image URLs from Slack.

  - **Signing** **secret** **is** **required.** SLACK\_WEBHOOK\_SIGNING\_SECRET must be configured or the webhook handler will error — no graceful degradation.
