For the complete documentation index, see llms.txt. This page is also available as Markdown.

AI Insights Webhooks

Subscribe a webhook to AI Insights events and react the moment a run finishes or someone actions a recommendation, instead of polling the Insights API on a timer.

Typical uses: post high-severity recommendations to Slack or PagerDuty, open a ticket for every finding above a severity threshold, or keep your own system in sync when anyone rates a recommendation or marks it as implemented.

The four events

Event
In Notification settings
Fires when

insight_run.completed

Run completed

A run finished and every investigator succeeded. Carries the finding and recommendation counts.

insight_run.partial

Run partial

A run finished with results, but at least one investigator failed. Names which succeeded and which did not.

insight_run.failed

Run failed

A run reached a terminal failed state. Carries a failure_reason.

recommendation_feedback.created

Feedback recorded

Feedback was recorded on a recommendation, whether from the dashboard or the API.

A run reports itself through exactly one of the three run events, and under normal delivery a single run is not reported as both finished and failed. Two silences are expected and worth designing around: a cancelled run emits nothing at all, and re-running an analysis that Revenium recognises as identical to a recent one emits nothing either, because it reuses that result instead of producing a new one. Treat the absence of an event as "no new result", never as "the run succeeded". "Delivery semantics" below covers the one case where two run events can arrive for the same run_id.

Subscribing

Subscriptions are per channel and per event, so one webhook can take everything while another takes failures only.

  1. Create the webhook. Open Guardrails under Spend Management in the sidebar, then the Channels tab, and use Add Webhook in the Webhooks section. Fill in Name and URL, and pick HMAC signing under Authentication. The signing secret is shown once — copy it. Signing is not a one-time decision: each webhook shows a Signing enabled or Signing disabled badge, and the Enable Signing button turns it on later (Rotate Secret once it is on).

  2. Pick the events. Open AI Insights and press the bell button, Notification settings, in the toolbar above the run. Every active webhook in the team appears as a row with a checkbox per event type. Check what that channel should receive and save.

  3. Verify. See "Testing" below.

Unchecking an event stops delivery for that channel immediately; other channels are unaffected. Deleting a webhook removes its subscriptions with it.

The envelope

Every event shares the same seven top-level fields.

Field
Meaning

event_type

One of the four tokens above.

run_id

The insights run the event belongs to. Feedback events carry the run the recommendation came from.

event_id

Unique per event, stable across retries of the same event.

schema_version

v1 today. A breaking payload change ships a new version.

occurred_at

ISO-8601 UTC timestamp of the event, not of the delivery attempt. Unchanged across retries.

livemode

false for non-production environments, true in production.

data

Event-specific payload, described below.

Payloads

insight_run.completed

Field
Type
Notes

team_id

number

The team the run belongs to.

status

string

Always completed.

triggered_by

string

user, api, system or schedule.

period_start, period_end

string

The analysed window, ISO-8601 UTC.

findings_count

number

Findings produced. 0 is normal: findings below the economic-value floor are filtered out.

recommendations_count

number

Recommendations produced. Can be 0 on a successful run with findings, when the recommendation step degraded and the findings were preserved on their own.

failed_investigators

string[]

Always empty here: a run is only completed when every investigator succeeded.

severity_histogram

object

Counts by critical, high, medium, low, info.

total_monthly_impact_usd

number

Estimated monthly impact across the findings.

findings_truncated

boolean

true when the finding list was capped.

total_duration_ms

number

Wall-clock duration of the run.

dashboard_url

string

Deep link to this run in the dashboard.

insight_run.partial

Same fields as completed, with status set to partial, failed_investigators non-empty, and one addition:

Field
Type
Notes

succeeded_investigators

string[]

Which investigators did produce results. The histogram covers only these.

insight_run.failed

Carries team_id, triggered_by, period_start, period_end, total_duration_ms and dashboard_url in the same positions as completed, plus:

Field
Type
Notes

status

string

Always failed.

failure_reason

string

analysis_failed, dispatch_failed, missing_config, invalid_payload or timed_out.

error_summary

string

Short cause, safe to show to a human.

failed_investigators

string[]

Always empty on this event. A failed run reports its cause through failure_reason, not per investigator.

severity_histogram

object

All zeros.

total_monthly_impact_usd

number

0.

Two shapes to expect on this event and not on the others: total_duration_ms is 0 when the run failed before it could be timed, and period_start / period_end fall back to the epoch sentinel 1970-01-01T00:00:00.000Z when the failure happened before the requested window was validated. Guard against that before rendering the window to a person.

recommendation_feedback.created

Field
Type
Notes

team_id

number

The team the recommendation belongs to.

recommendation_id

string

The recommendation the feedback is about.

action

string

One of acknowledged, dismissed, implemented, already_aware, not_applicable. See the mapping below.

confidence_rating

number

1, 0 or -1. Derived from the action, not entered by the person.

dismissal_reason

string

Free text, only ever populated by the thumbs-down path, and optional there.

realized_savings

number

Reported savings. The dashboard never sets it, so it is 0 unless the feedback came through the API.

realized_savings_currency

string

ISO currency code, USD by default.

realized_savings_measured_at

string | null

When the savings were measured, null unless reported through the API.

actor_type

string

user for the dashboard, api for an API caller.

Feedback events are not deduplicated: two pieces of feedback on the same run produce two events, which is what keeps multiple recommendations distinguishable.

What each dashboard control sends. A recommendation card carries two independent controls: an accuracy vote (the thumbs) and a status note (the overflow menu). A recommendation can therefore have both, recorded as separate events.

Control on the recommendation

action

confidence_rating

Thumbs up, under "Accurate?"

acknowledged

1

Thumbs down, with an optional "why" note

dismissed

-1

Overflow menu, "Mark as implemented"

implemented

0

Overflow menu, "Already aware"

already_aware

0

Overflow menu, "Not applicable"

not_applicable

-1

Read action rather than the rating when you care about intent: -1 covers both "this was inaccurate" and "this does not apply to us", and 0 covers a recommendation that was implemented as well as one that was already known.

Delivery semantics

  • Best effort, not guaranteed. Revenium retries a transient failure and then stops, so an event can be lost.

  • Retries. A 5xx or a network error is retried up to three attempts, roughly 10s then 20s apart. A 4xx is terminal and is not retried.

  • Retries are the same event. event_id, occurred_at and the signature headers are identical across attempts, so an endpoint that received an attempt without answering in time will see the same event again.

  • Terminal run events are deduplicated per run and event type, so a re-processed run does not fire the same terminal event twice.

  • If a run is ever retried at the infrastructure level, you can receive both a success and a failure for one run_id. Treat completed or partial as authoritative over failed.

  • Ordering is not guaranteed across channels or events. Use occurred_at.

Verifying deliveries

Enable HMAC on the webhook and verify the X-Revenium-Signature-256 header on every request. The algorithm, the 24-hour rotation overlap, the 300-second replay window and ready-to-use verifiers in Node, Python and Go are documented in Webhook Signing.

Testing

Two ways, both useful:

  • Synthetic delivery. Press Test on the webhook, on the Channels tab. It sends a test payload through the same signing and delivery path as a real event, so it exercises your endpoint and your verifier without waiting for a run. The API equivalent, and what a correct verifier looks like, are in Webhook Signing.

  • A real run. Subscribe one channel to insight_run.completed only, trigger a run from the Insights page, and confirm that exactly one delivery arrives and that no other event type does.

  1. Answer 2xx before you do the work. Acknowledge the delivery, then process asynchronously. A slow handler burns the retry budget, and a 4xx from your side is never retried.

  2. Deduplicate on event_id. A retry is the same event, not a new one, so keep a short window of processed identifiers rather than trusting one-shot arrival.

  3. Treat the event as a trigger, not as the record. Read the run back through the Insights API when you need the full findings or recommendations; the payload is a summary by design.

  4. Subscribe the narrowest set of events per channel. An on-call destination usually wants insight_run.failed alone, while a dashboard integration wants the terminal events but not feedback.

  5. Handle partial explicitly. It carries results and a list of investigators that failed, so a consumer that treats it as a plain success will report numbers built from an incomplete analysis.

If you need an event type that is not listed here, or delivery guarantees beyond at-most-once, contact support.

Last updated

Was this helpful?