Docs contents
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.
- Go to Alerts and click New.
- In the New alert rule drawer, choose the agent and condition.
- Turn on the Webhook channel and enter your endpoint URL. It must use HTTPS and be publicly reachable; private and internal addresses are refused.
- 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"
}
| Field | Description |
|---|---|
alert_rule_id | The rule that fired |
alert_name | The rule's name |
condition_type | One of the condition types below |
workspace_id | Your workspace |
agent_id | The agent the rule watches, or null for a rule that covers all agents |
payload | Details of what triggered the rule; its shape depends on condition_type |
fired_at | When the rule fired (ISO 8601) |
Payload by condition
condition_type | payload fields |
|---|---|
run_failed | run_id, agent_id, runnable_kind (agent or script), error_message |
run_duration_exceeded | run_id, agent_id, runnable_kind (agent or script), duration_ms, threshold_ms |
error_rate | observed_pct, threshold_pct, window_runs |
no_activity | last_run_at (or null if the agent never ran), hours_threshold |
custom_event | event_id, event_type, run_id, agent_id |
intelligence_finding | target_agent_id, producer_agent_id, severity, previous_severity, summary, run_id |
spend_exceeded | budget_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
2xxstatus within 5 seconds to acknowledge the delivery. - A non-
2xxresponse, 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
tmore 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.