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

# Webhook events

> Receive vulnerability status and assignment changes in your service.

Register a hook with `POST /hooks` to receive events at your service’s HTTPS endpoint. Each hook subscribes to one event type. Your handler checks the change and decides what to do next.

## Event types

| Type | When it is sent | Values |
| - | - | - |
| `vulnerability.status_changed` | A vulnerability is created or its status changes. | `previous` and `current` contain lifecycle statuses. `previous` is `null` on creation. |
| `vulnerability.assignee_changed` | The assignee changes. | `previous` and `current` contain a team member’s email or an agent name. Either can be `null` for an unassigned vulnerability. |

A request that changes both fields emits one event of each type. Setting a field to its existing value does not emit an event.

## Payload

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "event_123",
  "type": "vulnerability.assignee_changed",
  "vulnerabilityId": "vuln_123",
  "previous": null,
  "current": "our-remediation-agent",
  "createdAt": "2026-09-13T10:00:00Z"
}
```

| Field | Meaning |
| - | - |
| `id` | Stable event ID. Retries keep the same ID. |
| `type` | Event type. |
| `vulnerabilityId` | Vulnerability whose status or assignment changed. |
| `previous` | Value before the change. |
| `current` | Value after the change. |
| `createdAt` | Time the change was recorded, in UTC. |

Use `GET /vulnerabilities/{id}` when your handler needs the current vulnerability, and `GET /evidence?vulnerabilityId={id}` for its supporting files.

## Verify a delivery

Creating a webhook returns a signing `secret` once. Store it in your receiving service. Each delivery includes these headers:

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
Antigen-Timestamp: 1789293600
Antigen-Signature: sha256=<hex-encoded-signature>
Content-Type: application/json
```

The signature is an HMAC-SHA256 of the timestamp, a period, and the raw request body. Use the signing secret exactly as returned, encoded as UTF-8:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
HMAC-SHA256(secret, timestamp + "." + rawBody)
```

Verify the signature before parsing or acting on the event. Compare it using a constant-time comparison, and reject timestamps more than five minutes from your service’s current time. Each retry gets a fresh delivery timestamp and signature while retaining the original event ID and payload.

Do not reserialize the JSON before verification. Whitespace or field-order changes alter the signed bytes.

## Acknowledge and process

Return a `2xx` response within 10 seconds after durably accepting the event. Queue work that takes longer, such as launching an agent, and process it separately.

Timeouts and non-`2xx` responses are retried for up to 24 hours. Delivery can occur more than once, so record the event ID and avoid repeating work for an event you have already accepted. Events may arrive out of order; retrieve the vulnerability’s current state before acting when your workflow depends on it.

For example, a remediation handler can check that the current assignee still matches its agent before launching a run.

## Default hooks

`GET /hooks` includes the built-in triage, remediation, and verification hooks. They have `builtIn: true` and no public webhook destination.

| Hook ID | Trigger |
| - | - |
| `triage` | A vulnerability enters `open`. |
| `remediation` | A vulnerability is assigned to `remediation-agent`. |
| `verification` | A vulnerability enters `remediated`. |

Use `PATCH /hooks/remediation` with `{"enabled": false}` to disable the default remediation hook when replacing that workflow. Custom webhooks work alongside defaults unless you disable them. See [Assigning to your own agents](/docs/vulnerability-lifecycle/assigning-to-your-own-agents) for choosing which workflow to replace.
