Alert webhooks

An alert rule can notify your server when it fires. Add the Webhook channel to a rule and AgentOS sends a JSON POST to your URL each time the rule fires.


Setup

Owners and admins can add a webhook on any paid plan.

  1. Go to Alerts and click New.
  2. In the New alert rule drawer, choose the agent and condition.
  3. Turn on the Webhook channel and enter your endpoint URL. It must use HTTPS and be publicly reachable; private and internal addresses are refused.
  4. Save the rule, then copy the signing secret shown once. You need it to verify deliveries.

There is no test delivery. The first request arrives the next time the rule fires.


Request

POST <your URL>
Content-Type: application/json
User-Agent: agentos-webhooks/0.1
X-AgentOS-Signature: t=1747476000,v1=5f2c…
{
  "alert_rule_id": "uuid",
  "alert_name": "Checkout agent failures",
  "condition_type": "run_failed",
  "workspace_id": "uuid",
  "agent_id": "uuid",
  "payload": {
    "run_id": "uuid",
    "agent_id": "uuid",
    "runnable_kind": "agent",
    "error_message": "API timeout after 3 retries"
  },
  "fired_at": "2026-05-17T10:00:00.000Z"
}
FieldDescription
alert_rule_idThe rule that fired
alert_nameThe rule's name
condition_typeOne of the condition types below
workspace_idYour workspace
agent_idThe agent the rule watches, or null for a rule that covers all agents
payloadDetails of what triggered the rule; its shape depends on condition_type
fired_atWhen the rule fired (ISO 8601)

Payload by condition

condition_typepayload fields
run_failedrun_id, agent_id, runnable_kind (agent or script), error_message
run_duration_exceededrun_id, agent_id, runnable_kind (agent or script), duration_ms, threshold_ms
error_rateobserved_pct, threshold_pct, window_runs
no_activitylast_run_at (or null if the agent never ran), hours_threshold
custom_eventevent_id, event_type, run_id, agent_id
intelligence_findingtarget_agent_id, producer_agent_id, severity, previous_severity, summary, run_id
spend_exceededbudget_usd, spend_usd, over_by_usd, period (YYYY-MM), agent_id

Example spend_exceeded payload:

{
  "budget_usd": 50,
  "spend_usd": 53.4,
  "over_by_usd": 3.4,
  "period": "2026-05",
  "agent_id": null
}

Delivery and retries

  • Return any 2xx status within 5 seconds to acknowledge the delivery.
  • A non-2xx response, a timeout or a connection error counts as a failure. AgentOS retries about 2 minutes later, then about 4 minutes after that: up to 3 attempts in total. After the third failure the delivery is dropped.
  • Acknowledge first, then do the work asynchronously so slow processing does not cause a timeout.
app.post("/hooks/agentos-7f3c9a", express.json(), async (req, res) => {
  res.status(200).send("ok");
  await queue.enqueue(req.body);
});

Verifying the signature

Every delivery carries an X-AgentOS-Signature header: t=<unix seconds>,v1=<hex>. v1 is the HMAC-SHA256, keyed with the rule's signing secret, of the string `${t}.${rawBody}`, where rawBody is the request body exactly as received. Verify it before you trust the payload:

import { createHmac, timingSafeEqual } from "node:crypto";

app.post("/hooks/agentos-7f3c9a", express.raw({ type: "application/json" }), (req, res) => {
  const header = req.get("x-agentos-signature") ?? "";
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = createHmac("sha256", process.env.AGENTOS_WEBHOOK_SECRET!)
    .update(`${t}.${req.body.toString("utf8")}`)
    .digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
  const valid = v1?.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
  if (!fresh || !valid) return res.status(400).send("bad signature");

  res.status(200).send("ok");
  void queue.enqueue(JSON.parse(req.body.toString("utf8")));
});
  • Compute the HMAC over the raw body. Re-serialising parsed JSON can change the bytes and break the match.
  • Reject a t more than five minutes from your clock, so a captured request can't be replayed later.
  • The secret is shown once, when you save the rule. Lost it? On Alerts, use the key icon on the rule to rotate it: deliveries are signed with the new secret straight away, so update your receiver at the same time.

Securing your endpoint

Use HTTPS and verify every signature as above. A long, random path segment, such as https://example.com/hooks/agentos-7f3c9a2e41b8, adds a second layer: nobody can post to an address they can't guess.