# Slack (incoming webhook) Post messages to a Slack channel through an incoming webhook. URL: https://docs.qaldy.com/connectors/slack/ - **Status:** [[Available]] - **Shelf:** Messaging - **How you connect:** Webhook URL - **Regions:** global (not available to Kazakhstan-only workspaces) - **The service’s own API reference:** https://api.slack.com/messaging/webhooks Apps post messages to one Slack channel through a Slack **incoming webhook**. The webhook URL is the credential: its last three path segments are a secret. Qaldy seals that secret to the gate and the gate puts it into the URL path (`path_token` auth), so the app never sees it. > **Status: Available through the HTTP API preset.** The preset follows Slack's incoming-webhook > documentation (checked 2026-10-16). It has not been run against a live Slack workspace. > > Slack's OAuth sign-in (a bot token, reading channels, threads) is **not** built; this is the > webhook only. One webhook posts to one channel. ## Connect it 1. In Slack, open [api.slack.com/apps](https://api.slack.com/apps) and create an app **From scratch** for your workspace. Turn on **Incoming Webhooks**. 2. Choose **Add New Webhook to Workspace** and pick the channel messages go to. 3. Copy the **webhook URL**. It looks like `https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX`. 4. Qaldy → **Connectors** → Slack → **Connect Slack** → paste the **whole URL** → **Seal and connect**. Qaldy reads the part after `/services/` as the secret; only that part is sealed, and it is never shown again, not even to you. A URL on any host other than `hooks.slack.com` is refused. **Test connection** only checks that the sealed secret opens: a webhook has no read call, so a real test would post a message to the channel; it does not. ## What the gate allows | | | |---|---| | Host | `hooks.slack.com` (pinned, every resolved address public) | | Methods | `POST` | | Paths | the connection's own webhook; the app names only what follows it (nothing) | | Secret | spliced into the path by the gate: `/services///` | - The app's own `Authorization`, cookies and `x-qaldy-*` headers never reach Slack. - The secret comes first in the path; whatever path the app sends is appended after it, so the app cannot replace it, shorten it or climb out of it (`..`, `%2e`, `%2f` are refused before anything is built). - If Slack quotes the request URL back, the secret (the whole thing, each segment, the percent-encoded forms) is replaced with `[redacted]` in the body and headers. - The secret is not in the audit row, the City event or any log line. ## Use it from an app ```json { "id": "http", "actions": ["request"], "scope": "conn_k3v9…" } ``` ```ts const api = ctx.connectors.http('conn_k3v9…') await api.post('/', { json: { text: 'Beans are below 5 kg' } }) ``` Slack answers `200 ok` as plain text. Blocks work too: `{ blocks: [...] }`. ## When it breaks | You see | Why | Do | |---|---|---| | `404 no_service` or `403 invalid_token` | The webhook was revoked or the URL was mistyped | Create a new webhook and replace the connection's secret | | `404 channel_not_found` | The channel was deleted or archived | Add a new webhook for another channel | | Setup says "This address isn't on hooks.slack.com" | The pasted URL isn't a Slack webhook | Copy the URL from Incoming Webhooks again |