AgentOSAgentOSv0.125.1

Webhooks

AgentOS can notify your server when key events happen — a run completes, fails, or needs human input. Configure a webhook URL in your agent settings and AgentOS will POST a signed payload to your endpoint.


Setup

  1. Open your agent and go to Settings → Webhooks.
  2. Enter your endpoint URL (must be publicly reachable).
  3. Click Save. AgentOS will send a test ping to verify the endpoint.

Webhook delivery is best-effort with up to 3 retries on failure (exponential backoff). For guaranteed processing, acknowledge quickly and handle async.


Event types

EventWhen it fires
run.completedA run finishes successfully
run.failedA run fails with an error
run.startedA run is created (useful for tracking)
approval.requestedAn agent is waiting for human approval
alert.triggeredAn alert condition was met

Payload shape

Every webhook POST has the same envelope:

{
  "event": "run.completed",
  "timestamp": "2026-05-17T10:00:00.000Z",
  "workspace_id": "uuid",
  "agent_id": "uuid",
  "data": { ... }
}

run.completed

{
  "event": "run.completed",
  "timestamp": "2026-05-17T10:00:00.000Z",
  "workspace_id": "uuid",
  "agent_id": "uuid",
  "data": {
    "run_id": "uuid",
    "trigger_type": "scheduled",
    "started_at": "2026-05-17T09:59:55.000Z",
    "completed_at": "2026-05-17T10:00:00.000Z",
    "duration_ms": 5000,
    "output": { "summary": "..." }
  }
}

run.failed

{
  "event": "run.failed",
  "data": {
    "run_id": "uuid",
    "error_message": "API timeout after 3 retries",
    "started_at": "2026-05-17T09:59:55.000Z",
    "failed_at": "2026-05-17T10:00:00.000Z"
  }
}

approval.requested

{
  "event": "approval.requested",
  "data": {
    "run_id": "uuid",
    "approval_id": "uuid",
    "tool": "send_email",
    "input": { "to": "ceo@company.com", "subject": "Q1 Report" },
    "expires_at": "2026-05-17T11:00:00.000Z"
  }
}

Verifying signatures

Every request includes an X-AgentOS-Signature header — a HMAC-SHA256 signature of the raw request body using your webhook secret.

Always verify the signature before processing a webhook. Without verification, anyone can send fake events to your endpoint.

import { createHmac } from "crypto";

export function verifyWebhook(
  rawBody: string,
  signature: string,
  secret: string,
): boolean {
  const expected = createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return `sha256=${expected}` === signature;
}

// Express example
app.post("/webhooks/agentos", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.headers["x-agentos-signature"] as string;
  if (!verifyWebhook(req.body.toString(), sig, process.env.WEBHOOK_SECRET!)) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(req.body.toString());
  // handle event...
  res.status(200).send("ok");
});
import hmac, hashlib

def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Use hmac.compare_digest (Python) or a constant-time comparison (Node.js crypto.timingSafeEqual) to prevent timing attacks.


Responding to webhooks

Return a 2xx status within 10 seconds. AgentOS marks delivery as failed and retries if it receives a non-2xx response or the connection times out.

Do the minimum work synchronously — acknowledge immediately and enqueue the rest:

app.post("/webhooks/agentos", async (req, res) => {
  // verify signature first
  if (!verifyWebhook(...)) return res.status(401).send();

  // acknowledge immediately
  res.status(200).send("ok");

  // process async
  await queue.enqueue(req.body);
});

Webhook secret

Your webhook secret is shown once when you save the webhook URL. Store it as an environment variable:

AGENTOS_WEBHOOK_SECRET=whsec_...

To rotate the secret, delete and re-add the webhook URL in agent settings. Update your environment variable before removing the old webhook to avoid downtime.