> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runaegis.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Register an HTTPS endpoint to receive signed JSON payloads from Aegis whenever a governance event fires: approvals, denials, rewrites, anomalies, and more.

Webhooks let you pipe Aegis governance events into your own systems, incident trackers, on-call tools, audit pipelines, or custom dashboards. When an event fires, Aegis sends a signed JSON payload to every registered endpoint. You verify the signature using your signing secret and process the event however your system needs.

## Add a webhook endpoint

<Steps>
  <Step title="Open webhook settings">
    In the Aegis dashboard, go to **Settings → Webhooks**.
  </Step>

  <Step title="Enter your endpoint URL">
    In the **Endpoints** card, paste your HTTPS endpoint URL into the input field. The URL must be publicly reachable by Aegis.
  </Step>

  <Step title="Click Add">
    Click **Add**. The endpoint is registered immediately with the default event set: `approval` and `denied`. You can see the active events listed next to the endpoint URL.
  </Step>
</Steps>

You can register multiple endpoints. Aegis delivers each event to all registered endpoints in parallel.

## Supported events

Aegis forwards the following event types to your webhook endpoints:

| Event      | When it fires                                                                                           |
| ---------- | ------------------------------------------------------------------------------------------------------- |
| `approval` | An agent action has been held in the approval queue and is waiting for human review.                    |
| `denied`   | A policy blocked an agent action from executing.                                                        |
| `rewrite`  | Aegis redirected an agent action to a safer path, such as converting a direct push into a pull request. |
| `policy`   | A configured governance rule evaluated and fired on an agent action.                                    |
| `anomaly`  | Aegis detected unusual behavior in an agent session.                                                    |
| `budget`   | Token spend reached 75%, 90%, or 100% of your configured budget cap.                                    |

New endpoints receive `approval` and `denied` events by default.

## Webhook payload structure

Aegis delivers events as HTTP POST requests with a `Content-Type: application/json` header. Each payload includes the following fields:

| Field            | Type   | Description                                                                        |
| ---------------- | ------ | ---------------------------------------------------------------------------------- |
| `event`          | string | The event type: `approval`, `denied`, `rewrite`, `policy`, `anomaly`, or `budget`. |
| `timestamp`      | string | ISO 8601 timestamp of when the event occurred.                                     |
| `agent_name`     | string | The name of the agent that triggered the event.                                    |
| `tool_name`      | string | The GitHub MCP tool the agent called (e.g. `create_pull_request`, `push_files`).   |
| `decision`       | string | The governance decision: `ALLOW`, `DENY`, `REWRITE`, or `REQUIRE_APPROVAL`.        |
| `action_summary` | string | A plain-language description of what the agent was trying to do.                   |

Example payload:

```json theme={null}
{
  "event": "denied",
  "timestamp": "2025-05-21T14:32:07Z",
  "agent_name": "claude-code",
  "tool_name": "push_files",
  "decision": "DENY",
  "action_summary": "Push 3 files to main branch of acme/api, blocked by Protected Branch Denial policy"
}
```

## Verify webhook signatures

Every request Aegis sends includes an `X-Aegis-Signature` header. Use your signing secret to verify the header value before processing the payload, this confirms the request came from Aegis and was not tampered with in transit.

Your signing secret is displayed in the **Signing secret** card under **Settings → Webhooks**. It starts with `whsec_`.

The verification flow:

<Steps>
  <Step title="Read the raw request body">
    Capture the raw bytes of the POST body before parsing the JSON. Signature verification must run against the raw body, not a re-serialized version.
  </Step>

  <Step title="Compute an HMAC-SHA256 digest">
    Compute `HMAC-SHA256(raw_body, signing_secret)` using your `whsec_...` value as the key.
  </Step>

  <Step title="Compare to the header">
    Compare your computed digest to the value in the `X-Aegis-Signature` header using a constant-time comparison. If they match, the payload is authentic.
  </Step>
</Steps>

<CodeGroup>
  ```python verify.py theme={null}
  import hmac
  import hashlib

  def verify_aegis_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
      key = secret.encode("utf-8")
      expected = hmac.new(key, raw_body, hashlib.sha256).hexdigest()
      return hmac.compare_digest(expected, signature_header)
  ```

  ```typescript verify.ts theme={null}
  import { createHmac, timingSafeEqual } from "crypto";

  function verifyAegisSignature(
    rawBody: Buffer,
    signatureHeader: string,
    secret: string
  ): boolean {
    const expected = createHmac("sha256", secret)
      .update(rawBody)
      .digest("hex");
    return timingSafeEqual(
      Buffer.from(expected, "hex"),
      Buffer.from(signatureHeader, "hex")
    );
  }
  ```
</CodeGroup>

<Warning>
  Reject any request where the signature does not match. Do not process the payload or return a 200 until verification passes.
</Warning>

## Rotate your signing secret

If your signing secret is exposed or you want to rotate it as part of regular key hygiene:

1. Go to **Settings → Webhooks**.
2. In the **Signing secret** card, click **Rotate**.
3. Copy the new `whsec_...` value.
4. Update your signature verification code with the new secret.

<Warning>
  Aegis starts using the new secret immediately after you rotate. Update your verification logic before rotating, or deploy the new secret at the same time. Requests signed with the old secret will fail verification once it is replaced.
</Warning>

## Webhook failure handling

If your endpoint returns a non-2xx status code or does not respond within the timeout window, Aegis marks the delivery as failed. Aegis retries failed deliveries with exponential backoff. If your endpoint remains unreachable after repeated retries, Aegis marks the webhook as **failing**, you will see this status badge next to the endpoint URL in **Settings → Webhooks**.

<Tip>
  Return a `200` response as quickly as possible, ideally before doing any processing, to avoid Aegis treating a slow handler as a failure. Handle the event asynchronously in a background job or queue.
</Tip>
