Blog · Engineering
Reducing Alert Fatigue with Voice ACKs and Grafana Webhooks
Grafana POSTs a raw body to /v1/alert with x-api-key. WakeUp Dev owns the voice cascade and digit-1 ACK internally—no Express, no ACK routes, unlimited seats.
· Enrique Drack
Overview
WakeUp Dev ingests alerts from Grafana, UptimeRobot, or any HTTP client with a single public call: a raw POST to https://api.wakeupdev.com/v1/alert plus your x-api-key. After that, the platform owns the rest of the path—voice cascade, digit-1 ACK, and stopping escalation. You do not stand up Express, ACK routes, or TwiML servers.
The ACK that cuts alert fatigue is a human pressing 1 on the phone. Pickup is not enough. That IVR loop runs privately between Cloudflare Workers and Twilio.
Grafana webhook integration
Point Grafana (or any monitor) at the ingest URL. Send the payload as the raw request body. WakeUp Dev reads that body as the alert text for the call—no required title / message / severity schema on your side.
curl -X POST https://api.wakeupdev.com/v1/alert \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"alerts":[{"status":"firing","labels":{"alertname":"HighCPU"},"annotations":{"summary":"prod CPU above 90%"}}]}'That is the only integration surface. If the key is valid and you have credits, WakeUp Dev starts the on-call cascade.
Voice ACK (handled for you)
You never implement /v1/ack. Digit capture is Worker-to-Twilio on a private callback (/v1/twilio/ivr-callback). The TwiML below is conceptual: Gather posts back into WakeUp Dev, not into your app. The action host is the product site; the Worker completes ACK and stops the cascade without a webhook back to you.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Alert: CPU usage is above ninety percent. Press one to acknowledge.</Say>
<Gather numDigits="1" action="https://wakeupdev.com" method="POST">
<Say>Press one to acknowledge.</Say>
</Gather>
</Response>If nobody presses 1, WakeUp Dev escalates to the next on-call target. You do not poll, retry, or host IVR.
Unlimited seats and cost
WakeUp Dev is pay-per-voice-alert, not per seat. Add responders in the dashboard; the bill does not grow with headcount. Digit-1 ACK keeps calls short.
Example: send an alert from Node.js
This is the full client. There is no ACK handler to add.
const API_KEY = process.env.WAKEUP_API_KEY;
async function sendAlert(payload) {
const response = await fetch("https://api.wakeupdev.com/v1/alert", {
method: "POST",
headers: {
"x-api-key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error(`WakeUp Dev alert failed: ${response.status} ${await response.text()}`);
}
return response.json();
}
await sendAlert({
source: "grafana",
summary: "Disk usage on /dev/sda1 is 95% on prod.",
});Grafana can POST the same way from a contact point: URL https://api.wakeupdev.com/v1/alert, header x-api-key.
Best practices
- Keep the Grafana body short; it is spoken on the call.
- Treat x-api-key like a secret; Grafana contact points support a custom header.
- Do not build ACK or TwiML endpoints in your stack—WakeUp Dev already runs that loop.
- Use the dashboard cascade for routing, not extra Slack/email pages for the same firing alert.
💬 SRE & DevOps Insights
What strategies have you used to reduce alert fatigue when one webhook should page a human by phone, without adding another per-seat tool or a homemade IVR?
Write to administrador@wakeupdev.com or continue from the FAQ.