# Slack channel

A Slack app that replies to **DMs** and **@mentions** in channels. Inbound events
arrive via the Slack **Events API** webhook; replies go out via `chat.postMessage`.

## 1. Create a Slack app

At <https://api.slack.com/apps> → **Create New App** → _From scratch_.

- **OAuth & Permissions** → **Bot Token Scopes**, add:
  - `app_mentions:read` — receive `@mentions`
  - `im:history` — receive DMs
  - `chat:write` — post replies
  - (optional) `users:read` if you want nicer sender names
- **Install to Workspace** → copy the **Bot User OAuth Token** (`xoxb-…`).
- **Basic Information** → copy the **Signing Secret**.

## 2. Configure the channel in Callbackfy

Channels → **New channel** → Kind = **slack**.

| Field              | What it is                                                     |
| ------------------ | -------------------------------------------------------------- |
| **Default agent**  | Agent that answers.                                            |
| **Identity**       | A label for this Slack app/workspace, e.g. `acme-slack`.       |
| **Bot token**      | The `xoxb-…` token. Posts replies. Supports `{{ variables }}`. |
| **Signing secret** | Verifies inbound requests. Supports `{{ variables }}`.         |

Store both as **secure variables** and reference them as `{{ slack_bot_token }}` /
`{{ slack_signing_secret }}`. Save, then copy the URL from the **Endpoint** panel.

## 3. Point Slack at the webhook

```
POST /slack/<workspaceId>/<channelId>/events
```

In the Slack app:

1. **Event Subscriptions** → toggle on → **Request URL** = the Endpoint URL. Slack sends a signed `url_verification` challenge; Callbackfy echoes it and the URL turns green.
2. **Subscribe to bot events:** `app_mention` and `message.im`.
3. **App Home** → **Show Tabs** → enable the **Messages Tab** and check **"Allow users to send Slash commands and messages from the messages tab"**. Without this, Slack turns off DMs to the app ("Sending messages to this app has been turned off").
4. **Save** and (if prompted) **reinstall** the app.
5. **Invite the bot** to any channel where you want it to answer `@mentions` (`/invite @yourbot`). DMs work once the Messages Tab is enabled.

> **Bot verified but never replies to DMs?** It's almost always the Messages Tab being off (step 3) — Slack blocks the DM before it ever reaches Callbackfy.

## Behavior

- **DMs** (`message.im`) — every message is answered; replies are posted to the DM.
- **Channels** — only messages that `@mention` the bot are answered; the reply is posted **in-thread**, and the leading `@mention` is stripped before the agent sees it.
- Commands, sticky routing, the concierge, and guards work as on every channel (see the [common docs](./README.md)). The sender allowlist guard matches Slack **user IDs**.

## How it's secured

Every request is verified with an HMAC signature over the raw body using the signing
secret (with a 5-minute replay window) — a wrong/missing signature is rejected with
`401`. Slack requires a response within 3 seconds, so Callbackfy acks immediately and runs
the agent in the background. Retried deliveries are de-duplicated by event id.

A Slack app has one Request URL, so a second channel sharing the same bot token would
never receive events — dead configuration that looks like a working channel. Saving a
channel resolves its token via `auth.test` and records the bot id, so the duplicate is
refused with a `409`.
