Skip to main content
A metric alert rule says “tell me when X% of calls …”: when a share of an agent’s recent calls crosses a threshold, Sempera records a trigger and notifies the people and systems the rule names. Every metric is computed from records Sempera already keeps; a metric Sempera does not record (cost, sentiment, audio quality) is not offered.

Routes

Writes need the owner role. A rule may only name agents the credential can reach, and a rule that names an agent the credential cannot read is left out of its list. Responses use the compatibility envelope {"data": ..., "errors": null}; the list is {"data": {"alerts": [...], "pagination": {"limit", "page", "total", "total_pages"}}}. Refusals use the standard error envelope (Errors and limits).

Editing together

To avoid overwriting another owner’s edit, send the rule’s updated_at back unchanged as expected_updated_at (a time with a zone):
The rule is saved only if it still has that updated_at. The check and save are one step, so of two saves carrying the same value exactly one is applied. Enabling or disabling a rule (enabled) takes the same guard. If another owner saved first, the answer is 409 conflict with reason: "stale_alert" and updated_at, the value now on file. Nothing is written or audited, and no firing state is cleared. Show the owner what changed, then either discard the edit or explicitly retry with expected_updated_at set to that newer updated_at. A value that is not a time with a zone (including null) is 400 validation_failed with field: "expected_updated_at". A rule of another workspace, or one deleted meanwhile, is 404 not_found and names no updated_at. Without the field a save behaves as before: the last save wins.

A rule

A rule read adds id, object: "alert", org_id, metric_label, category, severity (the highest threshold’s), lookback_window (the same number as lookback_minutes), status (ok, triggered or disabled), firing_severity, last_saved (also updated_at), last_triggered, last_evaluated and created_at. A detail read adds triggers, newest first and at most 100: each has id, kind (fired, worsened or recovered), severity, value_pct, threshold_pct, call_volume, matched, the window, agent_ids, notified, notify_failed, notify_error and at.

How a rule fires

Every evaluation measures the metric over the lookback window for the agents in scope. When the call volume reaches the minimum and the share is at or above a threshold, the rule fires once, records a trigger, raises an alert in the Sempera App and notifies each target. It records a second trigger only when it worsens to a higher severity, and a recovery when an evaluation finds it clear; a recovery notifies the same targets with a “Cleared” message. Changing a rule’s definition, or disabling it, clears its firing state. Webhook targets receive the signed metric_alert.triggered event (Webhooks); this event is delivered only to the endpoints a rule names, never by subscription. A rule’s tool runs through the same road, test mode and write rules as a tool step inside a call. A trigger’s notified counts the targets that accepted delivery. A firing is also the alert.fired event your automation triggers can listen for (GET /v1/automation/events). The App’s Add notification menu offers Email and Webhook from the channel catalogue, plus the separate Tool slot. A webhook selects an existing enabled workspace endpoint, never a new URL. Ten email/webhook destinations do not consume the tool slot. Phone-call notifications are not available. Fixture email records a local test message but does not count as delivery: notified stays zero for that target, with notify_failed: true and notify_error: email_environment_fixture. Provider acceptance counts as delivery, not proof that a person read it. Tool fixtures likewise do not count as delivery. POST /v1/alerts/{id}/evaluate answers {"evaluation", "alert", "triggers"}. evaluation.action is fired, worsened, recovered or none, beside value_pct, matched, call_volume, enough_volume, severity, threshold_pct, agent_ids and the window. DELETE answers {"id", "deleted": true}. POST /v1/alerts/preview takes the same body as POST /v1/alerts, checks it the same way, and replays it once a minute over the last hours. It saves no rule, records no trigger and sends nothing, so notifications_sent is always 0. It reads only the agents both the rule and the credential can reach, and any other hours is 400 validation_failed. It answers {"hours", "from", "to", "triggered", "evaluations", "interval_minutes", "windows", "call_volume", "notifications_sent"}: triggered counts each rise into a firing or higher severity, and windows holds the hourly measurements plus every change of severity. The call metrics read preview and simulator conversation records, the same records Attention reads in the App; phone calls kept only as call-log rows are not counted. judge_failures counts the Fail verdicts of this workspace’s own judges, and its volume is the number of verdicts in the window.

Refusals