Alert rules for Voice are not something you author per org. FirstByte evaluates them centrally in Grafana against the platform’s own telemetry. The only tenant-facing knob is delivery: where this org’s Voice alerts get posted. You supply a Slack incoming-webhook URL on the Alerts screen of the Contact Center or Voice AI console, and the control-plane API creates a per-org Grafana contact point named cc-<org>-voice that the Voice alert rules route to. That means there is exactly one delivery target per org per vertical. The Alerts screen in the Contact Center and Voice AI consoles (Analytics → Alerts) is pinned to the voice vertical.

What the platform evaluates for you

The alert rules live in Grafana, on the platform side. You do not create, edit, or list them from the console or from the tRPC API. When you save a Slack webhook, the control-plane API creates the contact point for your org. It then creates the Voice alert rules in a Grafana folder for your org. The rules route to that contact point and carry the label tenant=<org>. The success message on save reports both halves of that work: New rules are created paused. An operator reviews them and enables them. Until an operator enables a rule, it does not fire for your org, even when the save reported it as provisioned. If provisioned comes back false, the console reports “Saved · webhook stored.” The URL is stored against your org, but the contact point was not created on this attempt. Nothing is delivered yet. Save again to retry the provisioning step. Because evaluation is central, the signals behind these alerts are the same ones described in Telemetry and Telephony Metrics. Use those pages when you want to reproduce or investigate an alert in your own dashboards.

Configure Slack delivery for a vertical

  1. In Slack, create an incoming webhook (Apps → Incoming Webhooks) bound to the channel you want alerts in. Slack’s own webhook documentation covers app install and scopes.
  2. Open Alerts in the Contact Center or Voice AI console (Analytics → Alerts) with the target org selected.
  3. Paste the webhook URL into Slack incoming-webhook URL. The field is required and must be https. The console shows the validation error when you press Save, not before.
  4. Optionally set a Channel label such as #ops-alerts.
  5. Press Save.
Under the hood this is a single upsert, keyed on org plus vertical:
Saving again with a different URL replaces the stored value for that org/vertical pair — there is no list of multiple destinations. Save stays disabled until the form differs from the stored record. The current configuration is read back with alertChannels.get.query({ orgId, vertical: "voice" }), which returns the stored record (slack_webhook_url, slack_channel) or nothing when routing has never been configured. The console’s Configured badge is exactly this distinction.

Channel label is metadata

The Channel label field does not choose the Slack channel. A Slack incoming webhook is already bound to one channel at creation time, and that binding decides where messages land. The label is stored alongside the URL so that the console can show which channel an org expects its alerts in. To move alerts to a different Slack channel, create a new webhook in Slack for that channel and save its URL here.

Treat the webhook URL as a credential

Anyone holding the URL can post into your channel. It is stored against your org and copied into the Grafana contact point. To invalidate it, delete the webhook in Slack; removing it here stops FirstByte from using it, but only Slack can revoke the URL itself.

What a delivered alert looks like

Delivery is a plain Slack incoming-webhook POST from the Grafana contact point, so alerts appear as messages in the channel the webhook is bound to, posted by the Slack app that owns the webhook. The content is whatever the firing platform rule emits — rule name and the notification body configured on the rule — not a FirstByte-specific envelope you can template from the console. Two consequences worth planning around:
  • Messages are per firing rule for your org, not per call. There is no call_sid-level fan-out here; for per-call data use CDRs or webhooks.
  • Formatting is controlled centrally. If you need a machine-readable feed, consume the streams in Telemetry rather than parsing Slack messages.

Testing and troubleshooting delivery

Once a webhook is saved, Send test posts a test message straight to the stored URL:
The button is disabled until a configuration exists, because the test uses the stored webhook — not the text currently in the input. Save first, then test.

Removing routing and what stops arriving

Remove deletes the stored routing for that org and vertical after a confirmation prompt:
After removal:
  • The console clears both fields and the Configured badge.
  • Send test is disabled again, because there is no stored webhook.
  • Your org’s Voice alerts have no Slack destination. Central evaluation continues — you simply stop being notified.
Removal does not touch anything in Slack. The incoming webhook keeps existing in your workspace until you delete it there.

Alerts vs webhooks

These are two different delivery systems and they are easy to confuse: Rule of thumb: alerts go to humans in Slack so someone notices a Voice problem; webhooks go to your backend so your code reacts to a call. Routing alerts into Slack is not a substitute for consuming call events, and subscribing to webhooks does not give you the platform’s alert rules.
  • Telemetry — the metrics, traces, and CDRs the alert rules are evaluated against
  • Telephony Metrics — what the underlying numbers mean
  • Authentication — the API key your server uses to call these procedures