Route an alert to the right channel
One failure firing ten times in five minutes should not page ten people ten times: repeats inside the window you set fold into the first alert, and each alert goes to Slack, Discord or your own receiving address. Pay per use, no subscription.
Run it online
Run this on our servers with your account. Free tools run in your browser; this one bills your KIT balance per the price above.
The same underlying failure firing ten times in five minutes shouldn't page ten people ten times.
Why alerts need one decision point
Most systems can detect a problem; fewer decide, consistently, who should hear about it and through which channel. When every monitor and every program sends its own messages, people start ignoring alerts, because the important ones arrive buried among dozens of low-value ones. This tool puts that decision in one place. Each alert carries a source, a severity and a key you choose, often the alert type plus the affected resource. Rules you define once then send it onwards: warnings to a Slack channel, critical problems to a channel that reaches the on-call phone, informational events to email.
When it helps and what to watch
It shines with a health check that flaps between pass and fail every minute: instead of paging the on-call person again and again, the repeats collapse into one active incident. It also lets security alerts always reach the security channel, whatever their severity. The most common mistake is a key that is too specific, for example one that includes the time, so identical problems never match and nothing is folded. The opposite mistake is a key so broad that two different failures merge into one alert. Choose a window long enough to cover a typical flapping cycle.
How routing and dedupe work together
If an alert with the same dedupe key arrives again inside the configured window, it's folded into the existing alert instead of firing a second notification; once the window passes or the alert is acknowledged, the next occurrence starts fresh. Routing rules then decide the destination — Slack for warnings, a phone-reaching channel for critical severity, email for informational events — based on criteria you define once.
What you can do with it
Deduplicating flapping monitoring checks
A health check that flaps between pass and fail fires alerts every minute; dedupe collapses them into one active incident instead of paging on-call repeatedly.
Severity-based on-call routing
Critical database alerts route to the on-call phone channel while low-severity warnings route to a Slack channel nobody needs to be paged for.
Escalation by alert type
Security-related alerts always route to the security channel regardless of severity, while infrastructure alerts follow the standard severity-based rules.
FAQ
Is notify.alert free?
There's no free tier — free tiers get abused and slow everyone down. No subscription, no tokens, no invented credits, and a failed task is never charged.
What happens if no routing rule matches an alert?
The response reports explicitly that no rule matched, rather than silently discarding the alert, so you can catch gaps in your routing configuration before they matter.
Can I set different dedupe windows per alert type?
Yes, dedupe windows are configurable per rule, so a flapping health check and a rare critical failure can use different windows suited to each.
Can one alert notify multiple channels at once?
Yes, a routing rule can fan out to more than one channel — for example Slack and a phone-reaching channel together for critical severity.
How does alert deduplication work?
If the same alert arrives again inside the time window you set, it is folded into the alert already open instead of sending a second notification. Once the window passes or the alert is acknowledged, the next occurrence starts fresh.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/notify/alert \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"message":"CPU al 95%","slack_url":"https://hooks.slack.com/services/…"}'const res = await fetch("https://api.kit.forhosting.com/notify/alert", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"message": "CPU al 95%",
"slack_url": "https://hooks.slack.com/services/…"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/notify/alert",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"message": "CPU al 95%",
"slack_url": "https://hooks.slack.com/services/…"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/notify/alert", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"message":"CPU al 95%","slack_url":"https://hooks.slack.com/services/…"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"message":"CPU al 95%","slack_url":"https://hooks.slack.com/services/…"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/notify/alert", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"message": "CPU al 95%",
"slack_url": "https://hooks.slack.com/services/…"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "notify.alert",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
This endpoint takes one alert, applies your routing rules and dedupe window, and sends it to exactly the channel that should see it, once.
Built for the gap between 'something broke' and 'the right person knows'
Most systems can detect a problem; fewer can decide, consistently, who should hear about it and through what channel without a human writing that logic into every single integration separately. notify.alert centralizes that decision — severity thresholds, on-call schedules, channel preference by alert type — so your monitoring, application code and third-party integrations all send alerts through one door instead of each hardcoding its own Slack webhook.
How routing and dedupe work together
POST /notify/alert takes an event with a source, severity and a dedupe key you choose — often a combination of the alert type and the affected resource.
Alert fatigue is an old, well-documented problem
The pattern of teams silencing or ignoring alerts because too many low-value ones arrived alongside the important ones predates modern cloud monitoring by decades — it's the same failure mode that shows up in industrial control rooms and hospital equipment, which is part of why deduplication and severity-based routing became standard practice in incident management rather than a nice-to-have. We built this endpoint around that lesson instead of treating every alert as equally urgent by default.
Where it sits relative to the other notification endpoints
Think of this as the decision layer that sits in front of notify.slack, notify.discord, notify.webhook and notify.digest: your monitoring or application code sends everything here, and the routing configuration decides which of those channels actually fires for a given alert, or whether it should instead wait for the next digest. That keeps the routing logic in one place instead of duplicated across every service that can raise an alert.
What comes back to confirm it worked
If no rule matches an alert, that's reported explicitly rather than the alert quietly going nowhere, so gaps in your routing configuration surface immediately instead of during an actual incident. You receive the routing decision made — which channel was used and why, plus whether the alert was new or deduplicated against an existing one — through a signed webhook or a signed link valid for 24 hours.
Integration use cases
Centralizing alerts from many services
A dozen microservices each raise alerts through the same endpoint, and one routing configuration decides destinations instead of twelve separate integrations.
Technical questions
How does deduplication work in the alert routing API?
You supply a dedupe key with each alert; repeated alerts sharing that key inside the configured window are folded into the existing alert instead of triggering a new notification.
Which channels can notify.alert route to?
It routes to any of the other notification endpoints on your account — Slack, Discord, webhook or digest — based on the rules you configure for severity, source or alert type.
What does alert routing cost?
It's $0.002 per POST /notify/alert request; the routing decision itself doesn't add extra charges beyond the underlying channel's own per-notification cost when it actually fires.
Is alert data kept after it's routed?
No, alert payloads and routing history are deleted after the stated retention window and are never used for training.