Asset 20 8 2
Does AI recommend your business? Run the free check →

Join 15,000 business owners, marketers and entrepreneurs. The Sunday newsletter you'll be annoyed only arrives once a week.

Article

Slack Webhooks: Set Up an Incoming Webhook and Fix Its Errors

Slack webhooks, or incoming webhooks, give you a unique URL that posts messages from another app into a Slack channel when you send it a JSON payload. You get one by creating a Slack app, switching on Incoming Webhooks and authorising it for the channel you want it to post to.

Here's the catch. Each webhook URL is specific to a single user and a single channel, and you can't override the channel, username or icon from your payload. Those always come from the Slack app's configuration, set by whoever installed it. So if you want alerts in three channels, you're setting up three webhooks.

Setting up an incoming webhook in four steps

  1. Create a Slack app: pick a name and choose the workspace it belongs to, then click Create. An app you already have works too. Slack suggests a sandbox channel, because you'll post plenty of test messages.
  2. In the app's settings, select Incoming Webhooks and toggle Activate Incoming Webhooks to on.
  3. Click Add New Webhook to Workspace, pick the channel the app will post to, then select Authorize. For a private channel, you have to be in it first.
  4. Copy your new URL from the Webhook URLs for Your Workspace section and send it a POST request with your message.

That Add New Webhook to Workspace button runs a shortcut version of the Slack app installation flow, so you don't need to write any code to get a URL. The address starts with hooks.slack.com/services/ and ends in three IDs. If you're building a GovSlack app for public sector customers, your API calls go to the slack-gov.com domain instead of slack.com.

Sending your first message

Make an HTTP POST request to the webhook URL with the header Content-type: application/json and a body like {"text": "Hello, World"}. Check the channel and you'll see the message, posted by your app. Slack's example uses cURL, but any HTTP request library works, and the requests are structured in exactly the same way.

Webhooks follow the same rules as Slack's other messaging APIs, so you can send one line of text or use text formatting, Block Kit layout blocks and interactive components. The only difference is that your JSON carries other fields alongside text. Slack's own advanced example turns a hotel review alert into a formatted message with a section, an image with alt text and an average rating field.

Keep the webhook URL secret

Slack is blunt about this: your webhook URL contains a secret. Don't share it online, and that includes public version control repositories. Slack actively searches out leaked secrets and revokes them, so a URL pushed to a public repo can stop working. Keep it out of shared code and screenshots, and treat it like a password.

What an incoming webhook can't do

LimitWhat Slack's docs say
Pick the channel per messageNo. It's fixed to the channel chosen when the app was installed
Change the username or iconNo. Both inherit from the Slack app's configuration
Delete a message it postedNo. For a chat flow that needs deletion, call chat.postMessage
AttachmentsA maximum of 100 per message
Return the message tsNo, so threaded replies need an extra lookup

Replying in a thread with a webhook

You can make a webhook message appear as a reply in a thread by sending the parent message's ts value as the thread_ts field. The awkward part is that the webhook doesn't return ts when you post, so you have to fetch it another way. Slack lists three: enable the Events API and subscribe to a callback when your webhook posts, search for the message by timestamp with assistant.search.context, or find it in a set of messages with conversations.history.

Slack webhook errors and what they mean

Most of the time you'll get an HTTP 200 response with a plain text ok. When a post fails, incoming webhooks return more expressive errors than Slack's Web API, with status codes such as 400 Bad Request, 403 Forbidden and 404 Not Found, plus an error string.

ErrorMeaning
action_prohibitedAn admin has restricted this way of posting. Don't retry for now
channel_is_archivedThe channel's archived and won't accept new messages
invalid_payloadMalformed JSON or badly escaped text. Fix it before retrying
invalid_tokenThe token's expired, invalid or missing
no_active_hooksThe webhook is disabled
no_serviceThe webhook is disabled, removed or invalid
no_service_idThe service ID, the B part of the URL, is invalid or missing
no_team / team_disabledThe workspace is missing, invalid or no longer active
no_textYour payload has no text field
posting_to_general_channel_deniedPosting to #general is restricted and the webhook's creator isn't allowed to post there
too_many_attachmentsThe message has more than 100 attachments
channel_not_found / user_not_foundThe channel or user doesn't exist or is invalid

The ones to watch are invalid_payload, channel_not_found and user_not_found: Slack says not to retry those without changing the request first.

Generating webhook URLs for an app you distribute

The settings page route is fine for your own workspace. If other people will install your app, it needs to create URLs on the fly during the standard OAuth install flow. Add the incoming-webhook permission to your scope list, and users see an extra permission on the Authorize screen where they pick the channel. After the OAuth code exchange, the JSON response includes an incoming_webhook object with four fields: channel, channel_id, configuration_url and url, which is the new webhook URL.

Work with me

Want AI doing the heavy lifting in your marketing?

I build the systems that handle the boring 80 percent, so you get your week back. Done properly, with the human kept in.

Webhooks can also start a workflow from outside Slack. That's set up in Slack Workflow Builder, not in your app's settings.

My verdict on Slack webhooks

I'd use an incoming webhook whenever you want another tool to drop updates into one channel, because you can have it posting in minutes without building a full app. Give each channel its own webhook, test in a sandbox channel first, and guard the URL like a password. If you need to delete messages, switch channels on the fly or build richer chat flows, move to chat.postMessage. And if a ready-made integration already does the job, check the Slack apps directory before you build anything.

Webhooks are often the first bit of automation a team builds, and the time savings snowball from there. I run AI training and workshops for teams, and help businesses with AI enablement and workflow automation, so the busywork runs itself and people get time back. Most of that work is with SaaS marketing teams and small businesses. Here's how we can work together.

Frequently asked questions

What is a Slack incoming webhook?

A unique URL that lets an app post messages into Slack. You send it a JSON payload with the message text and some options, and the message appears in the channel the webhook was set up for.

Can one Slack webhook post to several channels?

No. Each webhook URL is specific to a single user and a single channel, and you can't override the channel, username or icon in the payload.

Can I delete a message sent with a Slack webhook?

No. Incoming webhooks don't let you delete a message after it's been posted. If you need that, call chat.postMessage instead.

What does the no_text error mean in Slack?

The text attribute was missing from your JSON payload. Add a text field and send the request again.

Can I add a Slack webhook to a private channel?

Yes, but you must be in that private channel first. Then pick it when you authorise the webhook.

Published and maintained by the Lilach Bullock team, covering marketing, AI and business growth.
Your buyers are asking AI who to use. Does it say you?

See for free whether ChatGPT, Claude, Perplexity, Gemini and Google name you, and get the plan to become the answer.

Check my AI visibility →
Sundays only

Get the Sunday newsletter.

One email a week. AI experiments, marketing tactics, and the workflows Lilach is building right now in her own business.

Subscribe free

Let’s get your marketing running on AI.

Book a free 30-minute call

We figure out what you need, where AI fits in, and what working together would look like.

Book the call →

Or take the 30-second calculator

You’ll see the hours and the money quietly leaking out of your week, and the three workflows worth building first.

Take the calculator →

Or grab the free AI resource library

Prompt packs, templates, checklists, and swipe files. The exact tools I build for paying clients. Yours, free.

Get the library →
Keep reading

More from the blog.