← Back to Blog
Tutorial slack webhooks notifications tutorial

How to Set Up Slack Incoming Webhooks: A Complete Developer Guide

Slack's incoming webhook API is one of the simplest ways to send messages to a channel programmatically. Here's how to set it up, what the payload looks like, and how to send rich, formatted notifications.

JW

Jason Warner

April 16, 2026

How to Set Up Slack Incoming Webhooks: A Complete Developer Guide

Slack's incoming webhook integration is one of the fastest ways to push notifications into a channel from an external system. A deployment finished? Send a message. A payment failed? Send a message. An alert fired? Send a message.

Here's everything you need to know to get it working, including the format for rich Block Kit messages and how to handle delivery reliably.

Step 1: Create a Slack App

Incoming webhooks are tied to a Slack app. If you don't have one yet:

  1. Go to api.slack.com/apps
  2. Click Create New AppFrom scratch
  3. Give it a name (something like "Deploy Notifier" or "Alert Bot")
  4. Select the workspace where you want to post messages

Step 2: Enable Incoming Webhooks

In your app settings:

  1. Navigate to FeaturesIncoming Webhooks
  2. Toggle Activate Incoming Webhooks on
  3. Scroll down and click Add New Webhook to Workspace
  4. Choose the channel you want to post to
  5. Click Allow

Slack will display a webhook URL. It looks like this:

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

Copy this URL — you'll use it to send messages. Treat it like a secret: anyone who has this URL can post to your channel.

Step 3: Send Your First Message

The minimum payload is just a text field:

curl -X POST https://hooks.slack.com/services/T00000000/B00000000/XXXX \
  -H 'Content-Type: application/json' \
  -d '{"text": "Hello from my app!"}'

If it works, you'll get ok back from Slack and your message will appear in the channel.

Step 4: Send Rich Messages with Block Kit

Plain text works, but Block Kit lets you build structured, formatted messages with sections, buttons, dividers, and images.

Here's a deployment notification:

{
  "text": "Deployment to production succeeded",
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "✅ Deployment Succeeded"
      }
    },
    {
      "type": "section",
      "fields": [
        {
          "type": "mrkdwn",
          "text": "*Environment:*\nProduction"
        },
        {
          "type": "mrkdwn",
          "text": "*Branch:*\nmain"
        },
        {
          "type": "mrkdwn",
          "text": "*Deployed by:*\nJason Warner"
        },
        {
          "type": "mrkdwn",
          "text": "*Duration:*\n2m 14s"
        }
      ]
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {"type": "plain_text", "text": "View Deploy Logs"},
          "url": "https://your-app.com/deploys/123",
          "style": "primary"
        }
      ]
    }
  ]
}

The text field is a fallback for notifications and accessibility — always include it alongside blocks.

Use Slack's Block Kit Builder to design your message layout visually before writing the JSON by hand.

Handling Errors

Slack returns ok for success and an error string for failures:

Response Meaning
ok Message delivered
no_text Missing text field in non-blocks message
invalid_payload Malformed JSON
action_prohibited Webhook disabled or channel archived
channel_not_found Channel was deleted
too_many_attachments More than 100 attachments

Slack rate-limits incoming webhooks to 1 request per second per webhook. If you need higher throughput, create multiple webhooks or use the Slack Web API with a bot token instead.

Rotating a Compromised Webhook URL

If your webhook URL gets exposed (committed to a public repo, leaked in logs), go to your app's Incoming Webhooks page and delete the compromised webhook. Create a new one. Old URLs stop working immediately after deletion.

A good practice: store the webhook URL in an environment variable, never hardcoded in source.

Sending Webhook Events to Slack via Bluejay Relay

A common pattern is using Bluejay Relay to route events from other services (Stripe, GitHub, Shopify) directly to Slack — without writing any application code.

For example, to get a Slack message every time a Stripe payment succeeds:

  1. Create a Bluejay Relay integration with Stripe as the source
  2. Add a destination pointing to your Slack webhook URL
  3. Configure a transformation to format the payload as a Slack Block Kit message

The transformation template might look like:

{
  "text": "New payment: {{ event.data.object.amount | divided_by: 100 }} {{ event.data.object.currency | upcase }}",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*Payment received:* {{ event.data.object.amount | divided_by: 100 }} {{ event.data.object.currency | upcase }}\n*Customer:* {{ event.data.object.customer }}"
      }
    }
  ]
}

This pattern means no new code in your application — just configure the relay and the transformation.

Summary

  • Create a Slack app and enable incoming webhooks in 5 minutes
  • Post to the webhook URL with a JSON body containing text or blocks
  • Use Block Kit for rich, structured notifications
  • Store the URL as a secret, rotate it if it's compromised
  • Rate limit is 1 req/sec per webhook URL

Want to route other services' webhooks directly to Slack? Try Bluejay Relay free — transform and forward webhooks without writing code.

#slack #webhooks #notifications #tutorial

Build more reliable webhook workflows.

Capture, transform, and retry webhooks with full observability. Free to start, no credit card.