Posting Rich Block Kit Messages with Slack Incoming Webhooks: A Practical Guide
Learn how to set up a Slack incoming webhook, send Block Kit payloads with curl, understand rate limits, size caps, and avoid common pitfalls.
06 Sept 2025, 02:09 UTC

What You Can Do with an Incoming Webhook
A Slack incoming webhook is a permanent HTTPS endpoint that lets any external system post a message to a single channel in a workspace. The message is sent as the identity of the webhook’s owning app, and the channel is fixed at the time the URL is created. This makes webhooks ideal for simple, one‑way notifications such as CI/CD status updates, monitoring alerts, or scheduled reminders.
Getting the Webhook URL
- Create a new Slack app at
https://api.slack.com/apps.- Choose a name (e.g., Deploy Notifier) and select the workspace where it will live.
- Navigate to Incoming Webhooks under Features and toggle the feature on.
- Click Add New Webhook to Workspace.
- Grant the app permission to post to the target channel (e.g.,
#deployments). The channel is now bound to the URL.
- Copy the generated URL that looks like
https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXX. Store it securely; it is a bearer token that can post as the app.
Sending a Rich Message with curl
The payload must be JSON with a text field (fallback for clients that cannot render blocks) and an optional blocks array that defines the Block Kit layout. Below is a minimal example that sends a short status update to the channel.
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"text": "Deploy complete for `web`",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deploy complete* for `web`"
}
}
]
}' \
https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXX
Replace the placeholder URL with your actual webhook. The text field is shown in notifications and when the app’s message appears in a client that cannot render Block Kit. The blocks array can contain up to 50 blocks, each with its own formatting options (e.g., section, image, actions).
Understanding Limits
| Limit | Typical Value | Notes |
|---|---|---|
| Messages per second | ~1 | Short bursts up to 5–10 messages are allowed; exceeding triggers a 429 response. |
| Maximum payload size | ~10 kB | Includes all blocks; each block’s text is capped at ~3 000 characters. |
| Blocks per message | 50 | Any more results in a validation error. |
| Attachments | 0 | Attachments are deprecated; use blocks instead. |
These numbers are approximate and can change with Slack releases; always consult the current Slack API docs for the latest limits.
Common Integration Mistakes
- Missing
textfallback – Clients that cannot render blocks will show an empty or broken message, reducing accessibility. - Hard‑coding the webhook URL in client code or public repos – The URL is a secret; expose it and any attacker can post as your app.
- Assuming a single webhook can target multiple channels – The channel is fixed; to post elsewhere you need a new webhook or a bot token.
- Ignoring rate‑limit headers – 429 responses include a
Retry-Afterheader; implement back‑off logic or throttle your sender. - Exceeding payload size – Large payloads are rejected; validate your JSON before sending.
When to Use a Webhook vs a Bot Token
Choose a webhook if:
- You only need to post to one channel.
- The message is static or generated by an external system that cannot be authenticated.
- You want a minimal setup with no user interaction.
Choose chat.postMessage with a bot token if:
- You need to select channels at runtime.
- Messages require context (e.g., replying to a thread or including a user’s mention).
- You want to read events or integrate with other Slack APIs.
Verifying Your Setup
- Send the example
curlpayload to a test channel. - Check that the message appears with the correct formatting.
- Review the message’s
thread_tsif you added a thread; it should be present. - Observe the
429response when sending more than one message per second; confirm that theRetry-Afterheader is honored. - Use Slack’s chat.postMessage response to confirm the
okfield is true.
Security Best Practices
- Store the webhook URL in a secrets manager or environment variable; never commit it to source control.
- Rotate the URL if you suspect it has leaked.
- Use a separate app per environment (dev, staging, prod) to isolate access.
- Implement an IP whitelist if your integration allows it (Slack supports IP whitelisting for apps).
Conclusion
Slack incoming webhooks provide a lightweight, secure way to push rich Block Kit messages to a single channel. By following the setup steps, using a proper text fallback, respecting rate limits, and safeguarding the webhook URL, you can integrate external systems with Slack notifications reliably and efficiently.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.