Skip to content

Alert channels

An alert channel is one delivery destination — a Slack channel, a Teams channel, a webhook URL, a set of email recipients, a Jira project, or a PagerDuty service. Create a channel first, then subscribe it to whatever should notify it. A channel with no subscriptions is connected but will never fire.

Type How it’s set up
Slack Either connect a Slack workspace (below) and pick a channel, or paste a manually-created Slack Incoming Webhook URL.
Microsoft Teams Paste an incoming webhook URL for a Teams channel. There’s no OAuth connection for Teams — webhook only.
Webhook Any URL. Plutus POSTs the alert as JSON. If you set a secret when creating the channel, the request body is signed with HMAC-SHA256 into an X-Plutus-Signature header, so your receiver can verify the request came from Plutus.
Email One or more recipient addresses on a single channel.
Jira Creates a real issue in one Jira project. Takes its own write-scoped Jira credential — see Jira and PagerDuty below.
PagerDuty Creates a real incident through PagerDuty’s Events API v2. Takes a service-scoped routing key — see Jira and PagerDuty below.

Go to Alerts and click one of the four self-serve channel types — Slack, Teams, webhook, or email — to create a channel. Jira and PagerDuty channels have no configuration form in the app yet; see below.

Jira and PagerDuty: channels that open tickets

Section titled “Jira and PagerDuty: channels that open tickets”

A Jira or PagerDuty channel doesn’t post a message — it creates a real artifact someone has to work: a Jira issue in a project you name, or a PagerDuty incident that can page an on-call. Both behave like any other channel otherwise: same subscriptions, same delivery log.

The credential is a different one from the event source

Section titled “The credential is a different one from the event source”

Plutus also has read-only Jira and PagerDuty event sources, which pull tickets and incidents onto the cost-chart timeline. The alert channel does not reuse that credential, and can’t. They authenticate differently and grant different things:

Integration Credential What it can do
Jira event source Base URL + email + API token, scoped for reading; a list of projects Read issues
Jira alert channel Its own base URL + email + API token, plus one project key and issue type Create issues in that project
PagerDuty event source An account-wide REST API key List incidents
PagerDuty alert channel A service-scoped Events API v2 integration (routing) key Trigger incidents on that one service

The PagerDuty distinction is the easy one to get wrong: the routing key is not the REST API key. You get it by adding an Events API v2 integration to a specific PagerDuty service and copying that integration’s routing key. It only ever reaches events.pagerduty.com — it’s carried in the request body as the authentication itself, and it can’t page any service other than the one it belongs to.

For Jira, give the channel a credential scoped to creating issues in the one project you want tickets in. A read-only credential you already set up for the event source is not upgraded or reused to gain ticket-creation access.

Jira and PagerDuty channels are backend-only for now. There’s no form to create or edit one in the app — opening an existing Jira or PagerDuty channel’s edit page shows a message saying the channel type has no configuration screen yet and to contact support, instead of a form. The channels themselves deliver normally; only the configuration UI is missing, and it’s a deliberate gap rather than a broken screen. Until it ships, these channels are set up through the alert-channels API or by asking support.

One ticket per incident, not one per check

Section titled “One ticket per incident, not one per check”

Both types dedupe on the incident, not the send. A budget that’s been exceeded for 30 days opens one ticket, not thirty.

  • PagerDuty uses its own native dedup key, so a repeat send re-triggers the same open incident rather than opening a second one.
  • Jira has no equivalent, so Plutus labels each issue it creates with a hash of the same incident key and looks for an open issue carrying that label before creating another. On a repeat, it adds a comment to the existing issue instead. If that search fails (Jira briefly unavailable), a second issue is created rather than the alert being dropped — the label still identifies the duplicate afterward.

Severity maps across where it can: a budget in exceeded or a high-severity anomaly opens a critical PagerDuty incident, and a commitment expiring in 7 days or fewer does too, while further-out and lower-severity alerts open a warning. For Jira, priority is best-effort — if your project’s priority scheme doesn’t recognize the name Plutus sends, the issue is created without a priority rather than failing.

Recovery: closed automatically when the condition clears

Section titled “Recovery: closed automatically when the condition clears”

Both channel types also close what they opened, when there’s a clear signal that the condition that triggered them has gone away:

  • A budget that drops back under its warning threshold — or a spend forecast that returns to on-track — resolves the incident or issue it opened.
  • Event-ingestion limit overage resolves once usage is back under the limit, or the billing cycle rolls over.
  • A cost anomaly resolves when it’s dismissed as expected from the anomaly panel.

PagerDuty resolves the same incident it opened, using its native dedup key. Jira transitions the issue to a “done”-category status for the project’s workflow (adding an explanatory comment first) rather than assuming a specific status name, since workflows differ project to project.

Two triggers have no recovery signal to resolve on, so their tickets and incidents have to be closed by hand: commitment expiration (a deadline passing isn’t itself a recovery), and automatically-detected cost anomalies that nobody dismisses (the detector reports a one-day spike, not an ongoing condition with a defined end). A test send from the channel card also opens nothing that later resolves.

Resolves don’t count against the 20-per-hour cap below, and don’t fail if it’s already been hit — closing a ticket is never blocked by how many were opened.

  • 20 tickets or incidents per channel per hour. Past that, further sends from that channel don’t go out and are recorded as failed in the delivery log, so the cap is visible rather than silent. Unlike a Slack message, every send here is something someone has to triage and close, so the cap backstops a mis-scoped budget or alert opening dozens of near-duplicate tickets before anyone notices. Ordinary use — a handful of alerts an hour — never approaches it.
  • Scheduled digests never go to these channels. A weekly or monthly cost summary is not an incident, so digest delivery deliberately excludes Jira and PagerDuty. Use a Slack, Teams, webhook, or email channel as a digest’s destination. Trigger-based alerts — budgets, anomalies, event overage, commitment expirations — deliver to them normally.

Connecting a workspace is separate from picking a channel inside it. You connect the workspace once; after that, adding more Slack alert channels is just picking a different channel from the same connection — no repeated authorization.

  1. Go to Alerts and click Slack.
  2. Click Connect Slack workspace. This starts an OAuth flow against Plutus’s Slack app and asks you to authorize it in your workspace.
  3. After authorizing, pick a channel from the list Plutus fetched from your workspace.
  4. Save.

Plutus can post to any public channel it’s authorized for without being invited first. For a private channel, invite the Plutus Slack app to that channel before alerts will deliver.

One workspace connection is shared by every Slack alert channel on the account. If you disconnect the workspace (Alerts → Slack → Disconnect), every channel still referencing it starts failing at send time with a clear “not connected” error, rather than silently doing nothing — reconnect the workspace and they resume without needing to be recreated.

If you’d rather not grant OAuth access, the manual form still works: create a Slack Incoming Webhook yourself and paste its URL in. A webhook-URL channel is fixed to whichever channel you created the webhook for.

A channel can be subscribed to three distinct kinds of trigger. A single channel can carry any combination of the three.

  • A specific budget. Subscribing a channel to a budget notifies it whenever that budget crosses its warning threshold or is exceeded. Set this from the budget’s detail page.
  • Account-wide alerts. Each channel card on the Alerts page has three checkboxes: “Cost spikes” (detected anomalies), “Event ingestion limit overage”, and “Commitment expiring” (an under-utilized AWS Reserved Instance or Savings Plan nearing its end date — see Savings & optimization). These aren’t tied to any one budget — they fire for the whole account.
  • A scheduled digest. A weekly or monthly cost summary sent to one channel. This is set up separately, under Alerts → Scheduled reports, not as a checkbox on the channel card — a digest carries its own cadence and scope (whole account, one cost source, or one tagged value like a team), which a checkbox can’t express.

For example: a #finops-budgets Slack channel subscribed to two budgets (Production AWS, Growth-tier overall) gets a message only when one of those two crosses its threshold. A separate #finops-digests Slack channel, set up as the destination for a weekly account-wide scheduled report, gets one summary message every Monday regardless of whether anything crossed a threshold that week. The same Slack channel can be the target of both a budget subscription and a scheduled digest at once — they’re independent.

Each Alerts page channel card shows how many budget thresholds it’s subscribed to. A channel with no budget subscriptions, no account-wide toggle on, and no scheduled digest pointed at it is flagged as subscribed to nothing, since it will never send anything.