Notification Webhooks
Get a Slack or Discord message the moment a webhook or email arrives: a chat destination that sends at most one message a second, with the standard summary or your own text.
Updated Oct 2026
Get a message in Slack or Discord the moment a webhook or email arrives, without watching the dashboard.
A notification is a forwarding destination that sends a chat message, at most one a second. It carries a ready-made message, so Slack incoming webhooks and Discord webhooks show it as it is, and any other service that accepts a JSON POST can read the fields.
Setup
- Open the endpoint's Settings tab and find Forwarding.
- Click Slack or Discord and paste the channel's webhook URL.
- Under Advanced, set At most one every to 1 second for a heads-up, or leave it empty to get a message for every request.
- Click Add destination.
The next request the endpoint captures posts a message. Add conditions under What it gets to hear only about some of them (only emails, only failed signatures, only invoice.paid), or write your own Message with placeholders.
An endpoint whose notification URL was set before destinations existed, or through the API, has it as a destination named Notifications: a chat message, at most one a second, not retried.
Payload format
The standard message is a POST with a JSON body:
{
"slug": "my-endpoint",
"method": "POST",
"path": "/webhooks/stripe",
"ip": "203.0.113.42",
"receivedAt": "2026-04-03T12:34:56.789Z",
"preview": "{\"type\":\"checkout.session.completed\",\"data\":{\"object\":{\"id\":\"cs_test...",
"text": "New webhook on *my-endpoint* (`POST /webhooks/stripe`)\nReceived 2026-04-03T12:34:56.789Z (UTC)\n```\n{\"type\":\"checkout.session.completed\",...}\n```",
"content": "New webhook on *my-endpoint* (`POST /webhooks/stripe`)\nReceived 2026-04-03T12:34:56.789Z (UTC)\n```\n{\"type\":\"checkout.session.completed\",...}\n```"
}| Field | Type | Description |
|---|---|---|
slug | string | Endpoint slug that received the webhook |
method | string | HTTP method of the incoming request |
path | string | Request path after the slug |
ip | string | Client IP address of the webhook sender |
receivedAt | string | When the receiver took the request, ISO 8601 in UTC with milliseconds |
preview | string | First 200 characters of the request body (truncated with ...) |
text | string | The message for Slack: <, > and & from the request are escaped |
content | string | The same message for Discord, unescaped and under Discord's 2,000 characters |
The message names the endpoint, the method and path, and when the request arrived (Received ..., the same UTC time as receivedAt), followed by the body: up to 3,000 characters in text, and as much as fits in content, cut inside the code block so it still closes. Use receivedAt to measure how long a webhook took to reach webhooks.cc: it is taken when the receiver handles the request, after our CDN edge.
In the message, paths longer than 100 characters are shortened; the path field keeps the whole path. When the URL is a Discord webhook, the body also sets allowed_mentions to { "parse": [] }, so an @everyone in a webhook pings nobody.
For captured emails, method is EMAIL, path is the recipient address, preview is the subject followed by the start of the text, and the message reads "New email to ...".
A destination with its own Message sends { "text": ..., "content": ... } with your text instead, escaped for Slack in text.
Delivery
- Never in the way of the capture: the sender gets its response at once; the message is sent a second or two later.
- At most one a second with At most one every set to 1: when a burst arrives, the first request posts a message and the rest within the second are not sent. Without it, every request posts one, spaced to stay under Slack's and Discord's limits.
- Retries are your choice: the Notifications destination does not retry, so a channel that is down misses those messages, and a message that could not go out within a minute is dropped rather than sent late. Set Retry failed deliveries under Advanced when every message has to arrive.
- Logged: each message is in the endpoint's Deliveries log with Slack's or Discord's answer, so a wrong or revoked webhook URL shows up there.
Slack setup
- In Slack, go to Your Apps and create an app (or use an existing one)
- Enable Incoming Webhooks and click Add New Webhook to Workspace
- Choose a channel and copy the webhook URL
- Add it as a Slack or Discord destination
Slack posts the text field: the endpoint, the method and path, and the start of the body in a code block. For richer formatting, write your own Message, or route the JSON through a small serverless function that turns it into Slack Block Kit blocks.
Discord setup
- In Discord, go to Server Settings > Integrations > Webhooks
- Click New Webhook, choose a channel, and copy the webhook URL
- Add it as a Slack or Discord destination as it is
Discord posts the content field and, for these URLs, pings nobody. Use the plain URL rather than Discord's Slack-compatible form (ending in /slack): that form posts text instead, and its handling of mentions is not documented.
Microsoft Teams
Microsoft retired the Office 365 connectors in Teams in 2026. Their replacement, Teams Workflows webhooks, expects an Adaptive Card, not this JSON. Either send your own JSON shaped as the card the flow expects, or create a Power Automate flow with the trigger When a Teams webhook request is received that reads text from the body and posts it to a channel, and use the flow's URL with the Chat message format.
SDK and MCP
Add a chat destination from code, with the throttle that makes it a heads-up:
const client = new WebhooksCC({ apiKey: "whcc_..." });
await client.destinations.create("my-endpoint", {
url: "https://hooks.slack.com/services/T.../B.../xxx",
name: "Heads-up",
http: true,
email: true,
format: "chat",
throttleSeconds: 1,
retrySeconds: 0,
});notificationUrl on client.endpoints.create() and update() still works: it sets, changes or (with null) removes the Notifications destination. The MCP server has add_destination for the first and notificationUrl on create_endpoint and update_endpoint for the second.