import { Callout, Steps, Tabs } from "nextra/components";
import UniversalTabs from "@/components/UniversalTabs";
import { snippets } from "@/lib/generated/snippets";
import { Snippet } from "@/components/code";

# Slack Webhooks

Slack has several different ways to send data to your app — slash commands, interactive components (buttons, modals, etc.), and event subscriptions. They each have different payload formats and authentication mechanisms, which makes the setup a bit more involved than other webhook integrations. This guide walks through each one.

<Callout type="info">
  Slack's different interaction modes use different content types. Event
  subscriptions send JSON, but slash commands and interactive components send
  form-encoded data. Hatchet handles both, but it's good to be aware of the
  difference when writing your CEL expressions and task logic.
</Callout>

## Slack App Setup

Before configuring anything in Hatchet, you'll need a Slack app. If you don't already have one:

1. Go to [api.slack.com/apps](https://api.slack.com/apps) and click **Create New App**. See [Slack's getting started guide](https://api.slack.com/quickstart) if this is your first time.
2. Choose **From scratch**, give it a name, and select your workspace.
3. Once created, go to **Basic Information** and note the **Signing Secret** — you'll need this for Hatchet. See [Slack's signing secret docs](https://api.slack.com/authentication/verifying-requests-from-slack) for more on how request verification works.

## Event Subscriptions

Event subscriptions are what Slack uses to notify your app about things happening in the workspace — messages being posted, channels being created, users joining, and so on.

<Steps>

### Create the webhook in Hatchet

| Field                    | Value                               |
| ------------------------ | ----------------------------------- |
| **Name**                 | `slack-events`                      |
| **Source**               | Slack                               |
| **Event Key Expression** | `'slack:event:' + input.event.type` |
| **Secret**               | Your Slack app's signing secret     |

Copy the generated URL.

### Enable Event Subscriptions in Slack

In your Slack app settings, go to [**Event Subscriptions**](https://api.slack.com/events), toggle it on, and paste the Hatchet webhook URL into the **Request URL** field.

<Callout type="info">
  Slack will send a challenge request to verify the URL. Hatchet handles this
  automatically — you should see a green checkmark confirming the URL is
  verified.
</Callout>

Then, under **Subscribe to bot events**, add the events you want to listen for (e.g., `message.channels`, `app_mention`, `member_joined_channel`).

### Write a task

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]}>
  <Tabs.Tab title="Python">
    <Snippet
      src={snippets.python.webhooks.worker.slack_event_subscription_task}
    />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <Snippet
      src={snippets.typescript.webhooks.workflow.slack_event_subscription_task}
    />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <Snippet src={snippets.go.webhooks.main.slack_event_subscription_task} />
  </Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet
      src={snippets.ruby.webhooks.worker.slack_event_subscription_task}
    />
  </Tabs.Tab>
</UniversalTabs>

</Steps>

## Slash Commands

Slash commands work differently from event subscriptions. When a user types something like `/deploy production`, Slack sends a form-encoded POST to your configured URL. The payload includes the command, the text after it, the user, the channel, and a `response_url` you can use to send a response back.

<Steps>

### Create the webhook in Hatchet

| Field                    | Value                              |
| ------------------------ | ---------------------------------- |
| **Name**                 | `slack-commands`                   |
| **Source**               | Slack                              |
| **Event Key Expression** | `'slack:command:' + input.command` |
| **Secret**               | Your Slack app's signing secret    |

Copy the generated URL.

<Callout type="info">
  Even though slash commands send form-encoded payloads, Hatchet parses them
  into a JSON object so you can use the same `input.field` syntax in your CEL
  expressions.
</Callout>

### Add the slash command in Slack

In your Slack app settings, go to [**Slash Commands**](https://api.slack.com/interactivity/slash-commands) and create a new command. Set the **Request URL** to the Hatchet webhook URL you just copied.

### Write a task

The `input.command` field includes the leading slash (e.g., `/deploy`), so your event key will look like `slack:command:/deploy`.

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]}>
  <Tabs.Tab title="Python">
    <Snippet src={snippets.python.webhooks.worker.slack_slash_command_task} />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <Snippet
      src={snippets.typescript.webhooks.workflow.slack_slash_command_task}
    />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <Snippet src={snippets.go.webhooks.main.slack_slash_command_task} />
  </Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.webhooks.worker.slack_slash_command_task} />
  </Tabs.Tab>
</UniversalTabs>

</Steps>

## Interactive Components

Interactive components — buttons, menus, modals — send payloads to an **Interactivity Request URL** when a user interacts with them. These are also form-encoded, with the actual payload nested inside a `payload` field as a JSON string.

<Steps>

### Create the webhook in Hatchet

| Field                    | Value                               |
| ------------------------ | ----------------------------------- |
| **Name**                 | `slack-interactions`                |
| **Source**               | Slack                               |
| **Event Key Expression** | `'slack:interaction:' + input.type` |
| **Secret**               | Your Slack app's signing secret     |

### Enable Interactivity in Slack

In your Slack app settings, go to [**Interactivity & Shortcuts**](https://api.slack.com/interactivity/handling), toggle it on, and paste the Hatchet webhook URL into the **Request URL** field.

### Write a task

<UniversalTabs items={["Python", "Typescript", "Go", "Ruby"]}>
  <Tabs.Tab title="Python">
    <Snippet src={snippets.python.webhooks.worker.slack_interaction_task} />
  </Tabs.Tab>
  <Tabs.Tab title="Typescript">
    <Snippet
      src={snippets.typescript.webhooks.workflow.slack_interaction_task}
    />
  </Tabs.Tab>
  <Tabs.Tab title="Go">
    <Snippet src={snippets.go.webhooks.main.slack_interaction_task} />
  </Tabs.Tab>
  <Tabs.Tab title="Ruby">
    <Snippet src={snippets.ruby.webhooks.worker.slack_interaction_task} />
  </Tabs.Tab>
</UniversalTabs>

</Steps>
