Slack (incoming webhook)
Post messages to a Slack channel through an incoming webhook.
- 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#
- In Slack, open api.slack.com/apps and create an app From scratch for your workspace. Turn on Incoming Webhooks.
- Choose Add New Webhook to Workspace and pick the channel messages go to.
- Copy the webhook URL. It looks like
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX. - 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 thanhooks.slack.comis 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/<T…>/<B…>/<token> |
- The app's own
Authorization, cookies andx-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,%2fare 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#
{ "id": "http", "actions": ["request"], "scope": "conn_k3v9…" }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 |