# Slack App for Channel Routing

{% hint style="info" %}
Webhook Notification Channel is getting an upgrade: meet [Webhook Connected App](/integrations/connected-apps/generic-webhook.md)
{% endhint %}

groundcover supports sending notifications to Slack using a **Slack App with bot tokens** instead of static webhooks. This method allows dynamic routing of alerts to any channel by including the channel ID in the payload. In addition to routing, messages can be enriched with formatting, blocks, and mentions — for example including <@user\_id> in the payload to directly notify specific team members. This provides a flexible and powerful alternative to fixed incoming webhooks for alerting.

Make sure you created a [webhook for a Slack App with Bot Tokens](https://docs.groundcover.com/~/revisions/ETrLpNk6KtHjyaVUTLoE/integrations/workflow-integrations/slack-app-with-bot-tokens).

Use the following workflow as an example. You can later enrich your workflow with additional functionality.

Here are a few tips for using the example workflow:

1. In the consts section, the `channels` attribute defines the mapping between Slack channels and their IDs. Use a clear, readable label to identify each channel (for example, the channel’s actual name in Slack), and map it to the corresponding channel ID.
2. To locate a channel ID, open the channel in Slack, click the channel name at the top, and scroll to the About section. The channel ID is shown at the bottom of this section.

<figure><img src="/files/zvQyTxJ1MohXBV0tfSRd" alt="" width="375"><figcaption></figcaption></figure>

1. The channel name should be included in the monitor’s **Metadata Labels**, or you can fall back to a default. See the channel\_id attribute in the workflow example.\\

   <figure><img src="/files/kPnV4lZsSaMtRhJZT2UB" alt=""><figcaption></figcaption></figure>
2. Finally, replace the integration name in `{{ providers.slack-routing-webhook }}` with the actual name of the Webhook integration you created.

```yaml
workflow:
  id: slack-channel-routing-workflow
  description: workflow for all channels with dynamic routing
  triggers:
  - type: alert
    filters:
    - key: annotations.slack-channel-routing-workflow
      value: enabled
  name: slack-channel-routing-workflow
  consts:
    channels: '{"devops":"C0111111111", "alerts":"C0222222222", "incidents":"C0333333333"}'
    channel_id: keep.dictget( '{{ consts.channels }}', '{{ alert.labels.channel_id }}', 'C09G9AFHLTB')
    env: keep.dictget({{ alert.labels }}, 'env', 'no-env')
    upper_env: "keep.uppercase({{consts.env}})"
    severity: keep.dictget({{ alert.annotations }}, '_gc_severity', 'unknown-severity')
    summary: keep.dictget({{ alert.labels }}, 'summary', 'no-summary')
    slack_message: "<https://app.groundcover.com/monitors/create-silence?keep.replace(keep.join(keep.dict_pop({{ alert.labels }}, \"_gc_monitor_id\", \"_gc_monitor_name\", \"_gc_severity\", \"backend_id\", \"grafana_folder\", \"_gc_issue_header\"), \"&\", \"matcher_\"), \" \", \"+\")|Silence> :no_bell: | \n<https://app.groundcover.com/monitors/issues?backendId={{ alert.labels.backend_id }}&selectedObjectId={{ alert.fingerprint }}|Investigate> :mag: | \n<https://app.groundcover.com/monitors?backendId={{ alert.labels.backend_id }}&selectedObjectId={{ alert.labels._gc_monitor_id }}|See Monitor> :chart_with_upwards_trend:\n\n*Labels:*  \n- keep.join(keep.dict_pop({{alert.labels}}, \"_gc_monitor_id\", \"_gc_monitor_name\", \"_gc_severity\", \"backend_id\", \"grafana_folder\", \"_gc_issue_header\"), \"\\n- \")\n"
    title_link: "https://app.groundcover.com/monitors/issues?backendId={{ alert.labels.backend_id }}&selectedObjectId={{ alert.fingerprint }}"
    red_color: "#FF0000"
    green_color: "#008000"
    footer_url: "groundcover.com"
    footer_icon: "https://app.groundcover.com/favicon.ico"
  actions:
  - if: "{{ alert.status }} == 'firing'"
    name: webhook-alert
    provider:
      type: webhook
      config: "{{ providers.slack-routing-webhook }}"
      with:
        body:
          channel: "{{ consts.channel_id }}"
          attachments:
          - color: "{{ consts.red_color }}"
            footer: "{{ consts.footer_url }}"
            footer_icon: "{{ consts.footer_icon }}"
            text: "{{ consts.slack_message }}"
            title: "\U0001F6A8 Firing: {{ alert.alertname }} [{{ consts.upper_env}}]"
            title_link: "{{ consts.title_link }}"
            type: plain_text
  - if: "{{ alert.status }} != 'firing'"
    name: webhook-alert-resolved
    provider:
      type: webhook
      config: "{{ providers.slack-routing-webhook }}"
      with:
        body:
          channel: "{{ consts.channel_id }}"
          text: "\u2705 [RESOLVED][{{ consts.upper_env}}] {{ consts.severity }} {{ alert.alertname }}"
          attachments:
          - color: "{{ consts.green_color }}"
            text: "*Summary:* {{ consts.summary }}"
            fields:
            - title: "Environment"
              value: "{{ consts.upper_env}}"
              short: true
            footer: "{{ consts.footer_url }}"
            footer_icon: "{{ consts.footer_icon }}"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.groundcover.com/use-groundcover/workflows/full-webhook-examples/slack-app-for-channel-routing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
