Alerts & Escalation
How StackSpend generates alerts, routes them to the right people, escalates unresolved issues, and notifies your team via email and Slack.
Where alerts come from
Every alert in StackSpend originates from one of two sources:
| Source | When it fires | Learn more |
|---|---|---|
| Anomaly detection | After every sync. StackSpend compares the latest spend against a per-provider baseline and fires when the deviation is statistically significant. | Anomaly detection |
| Budget thresholds | When monthly spend for a provider crosses 50%, 80%, or 100% of its configured budget. | Budgets |
Alert severity
Anomaly alerts are assigned a severity based on how far spend deviated from the normal range and the absolute dollar impact. Budget alerts are assigned severity based on which threshold was crossed.
| Severity | Meaning |
|---|---|
| Low | Minor deviation — worth noting, unlikely to require immediate action. |
| Medium | Moderate deviation — review soon. |
| High | Significant deviation — investigate promptly. |
| Critical | Large deviation or 100% budget breach — act immediately. |
Alert lifecycle
Each alert moves through the following states. Team members advance an alert from the Inbox.
| State | Description |
|---|---|
| New | Alert just fired. Appears in Inbox and triggers notifications. |
| Acknowledged | Someone is looking into it. Still counts as open — the escalation SLA keeps running from when the anomaly was detected. |
| Resolved | Root cause identified and addressed. Cleared from Inbox and escalation. |
| False positive | The spike was expected. Feeds back into baseline tuning. |
| Dismissed | Closed without action. |
Who alerts go to
Routing in the Inbox depends on whether the provider has an owner assigned:
- Owned alerts — appear under "For you" in the owner's Inbox.
- Unowned alerts — appear under "Needs attention" for every workspace member.
All alerts are also broadcast to notification channels regardless of ownership. See Notification channels below.
Escalation
When an owned alert stays open past its SLA, StackSpend escalates it automatically. The SLA is configurable per severity level — tighter for critical alerts, looser for low ones.
Default escalation SLAs
| Severity | Default SLA | Meaning |
|---|---|---|
| Critical | 1 day | Must be resolved within 1 business day or admins are notified. |
| High | 2 days | 2 business days before escalation. |
| Medium | 5 days | 5 business days before escalation. |
| Low | Off | Low-severity alerts never escalate by default. |
What happens when an alert escalates
- The alert appears in every admin's Inbox under a dedicated "Escalated" section, marked with a shield icon.
- The original owner still sees it in their "For you" section — they are not removed from the loop.
- Weekends do not count. Only business days (Monday–Friday) are counted toward the SLA.
- Once the alert is resolved, dismissed, or marked as a false positive, it is removed from the escalated list for all admins.
Configuring escalation SLAs
Admins can change the escalation thresholds for each severity level — or turn escalation off entirely for any severity — in Settings → Budgets & alerts → Task escalation.
Task escalation
When an owned task stays open past its SLA, it's flagged as escalated — shown to admins in the Inbox, on the Tasks page, and in the daily summary.
Days an owned task can stay open before it escalates, by severity. Set to 0 to turn escalation off for that severity.
1 day
2 days
5 days
Off
Set any severity to 0 to disable escalation for that level. Changes take effect immediately — any open alerts that have already exceeded the new SLA will escalate on the next check.
Notification channels
Both anomaly and budget alerts trigger notifications through your configured channels:
| Channel | Routing | Configure in |
|---|---|---|
| Broadcast to all configured report recipients. | Settings → Daily report | |
| Slack | Broadcast to the connected Slack channel. | Settings → Integrations → Slack |
| PagerDuty | Pages the on-call rotation on one service you choose. Resolves automatically when the anomaly closes. | Settings → Integrations → On-call & alerting |
| incident.io | Posts alerts to one alert source; your alert routes decide who is escalated. | Settings → Integrations → On-call & alerting |
| Better Stack | Creates an incident via an incoming webhook, routed by the escalation policy you pick. | Settings → Integrations → On-call & alerting |
On-call destinations
Anomaly alerts can page an on-call rotation in PagerDuty, incident.io or Better Stack. This is a deliberately narrow channel — paging is expensive attention, so it behaves differently from the broadcast channels above.
- Anomalies only. Daily summaries are never paged. PagerDuty can receive them as non-paging change events on the service timeline, which notifies nobody. incident.io and Better Stack have no non-paging event type, so they receive anomalies only.
- Two thresholds, both must be met. Each destination has a minimum severity and a minimum sustained daily impact in USD. Defaults are critical only and $250/day, so a critical anomaly costing $200/day pages nobody. Adjust both on the connection page. Only high and critical anomalies ever reach a paging destination, so the severity floor is a choice between critical-only and high-and-above.
- One incident per dimension, not per day. Anomalies are detected per dimension per day, so a sustained five-day spike is five records. Alerts are de-duplicated on organisation + provider + dimension — the affected service, or the cost category when there is no service — so that spike is one incident that stays open until someone resolves the anomaly, in StackSpend or (where the destination supports it) in the pager. Spend returning to baseline does not close it on its own: nothing auto-resolves a cost anomaly, because a quiet day is not evidence the cause was fixed.
- Sync latency. Inbound state is reconciled on a poll, roughly every five minutes — not instantly. If you resolve in the pager and the anomaly still looks open, give it a few minutes before assuming it failed.
- No loops. A resolve arriving from one pager is not echoed back to it, and StackSpend never re-opens an anomaly because a vendor still shows the incident open — your cost data stays authoritative on whether spend is still anomalous. Other destinations you have connected do still receive the resolve.
- Resolving from a pager closes every anomaly on that dimension. A multi-day spike is several anomaly records grouped into one incident, so resolving it closes all of them and each contributes to the savings ledger, attributed to no StackSpend user. If the spike is continuing, the next day's detection raises a fresh anomaly and pages again.
- Two-way, where the vendor allows it. Better Stack syncs both ways out of the box: acknowledge the incident there and the anomaly becomes acknowledged; resolve it and the anomaly closes. incident.io can do the same once you add an API key with alert read access, though only resolution syncs because its alerts have no acknowledged state. PagerDuty is outbound only — an Events API v2 integration key cannot read incidents back, so resolving in PagerDuty leaves the anomaly open here.
- Resolving closes the incident. When the last anomaly behind an incident is resolved, dismissed or marked a false positive, StackSpend sends the matching resolve. An incident stays open while other anomalies on the same dimension are still active.
- Burst protection. Each destination has a per-run cap so a large detection batch cannot page someone dozens of times or exhaust the vendor's rate limit: 50 events per detection run for PagerDuty and incident.io, 20 for Better Stack. The most expensive anomalies are sent first. Anything withheld is shown on the destination's connection page — the Health card gives the count and the run it happened on, with a link to the full anomaly list — so a capped run is never silent.
What you do, and what StackSpend does
| Destination | You do | StackSpend does | Main limitation |
|---|---|---|---|
| PagerDuty | Create or pick a service, set its escalation policy and urgency, copy an Events API v2 integration key. | Sends and resolves alerts on that service; groups multi-day spikes; optional non-paging daily summary. | Urgency is your service's setting. PagerDuty services default to high urgency, so set the service to low unless you want phone calls about spend. |
| incident.io | Create an HTTP alert source, copy its URL and token, and build an alert route that listens to it. | Sends and resolves alerts with thirteen labelled metadata fields your routes can filter on. | StackSpend cannot create the alert route and cannot see your routes — so it can confirm delivery, never that anyone was paged. |
| Better Stack | Get an Uptime API token for the right team and pick an escalation policy. | Creates and configures the incoming webhook; raises and resolves incidents; email and push only, never overrides Do Not Disturb. Note the webhook carries a recovery period — StackSpend asks for 24 hours and the connection page shows what Better Stack accepted — after which every cost incident closes itself there. The anomaly here stays open, but that period is your window to acknowledge or resolve in Better Stack. | The team is fixed by the token — moving teams means disconnecting and reconnecting. |
Common to all three: one connection per destination per organisation (you cannot route different providers or teams separately), StackSpend cannot tell you who your escalation policy will notify, and the “Send test alert” button deliberately ignores your thresholds so a test always goes through.
One connection per destination per organisation. Escalation logic below is separate from on-call paging: it decides when an unresolved alert becomes visible to admins inside StackSpend, and does not page anyone.