Skip to main content
A webhook endpoint receives an HTTPS POST every time one of an agent’s runs changes state in a way you care about. Use them to update a ticket when a run completes, alert someone when one fails, or notify a reviewer that a run is waiting for them.

Add an endpoint

1

Open the Webhooks tab

Open the agent and its Webhooks tab. Environment admins add endpoints; members see them.
2

Add the endpoint

Click Add endpoint, enter the receiver URL (it must be https://) and pick the events it should receive.
3

Copy the signing secret

AgentOS shows the endpoint’s signing secret (whsec_…) once. Store it with your receiver: you need it to verify every delivery.
Members of the environment can see the endpoints’ URLs. Don’t put a token in the URL; authenticate deliveries by their signature instead.

Events

Runs of evals never send webhooks.

The payload

Each event is posted as JSON:
  • metadata is the run’s own metadata, as the caller passed it when starting the run. Use it to carry your own ids (a ticket, an order) through to the webhook.
  • data is the event’s own data. A hold.decided event’s data has the hold_id, the decided items (id, action) and reviewer_kind (person or service_account). Its by names the reviewer only when that name isn’t an email address (a service account’s name); a person’s email is left out.
Each request also carries these headers:

Verify the signature

The signature is the hex HMAC-SHA256 of "<t>.<raw body>", keyed with the endpoint’s signing secret. Verify it on the raw body bytes, before you parse or trust them, and refuse old timestamps:

Rotating the secret

Rotate secret on the endpoint shows a new secret once. The previous one stays valid for 24 hours: until then every request carries two signatures, t=…,v1=<new>,v1=<previous>. A receiver that accepts any matching v1, as both examples above do, keeps working while you switch it to the new secret.

Answering, retries and dead deliveries

Answer with any 2xx status. Only the status is read, never the body. Anything else is a failed attempt: another status, a timeout (10 seconds to connect or between bytes, 15 seconds for the whole answer), a refused connection, or a redirect (redirects are never followed). A failed delivery is retried 10 s, 1 min, 5 min and 30 min later. After the fifth attempt it is dead until someone replays it.
Delivery is at least once and unordered. The same event can arrive more than once, and a later event can arrive before an earlier one: deduplicate on the event id, and use at to order.
Each endpoint has at most one delivery in flight, so a receiver that hangs or fails only delays its own events, never other endpoints’.

Monitoring endpoints

The Endpoints list shows each endpoint’s status and how many of its attempted deliveries of the last 30 days arrived: Recent deliveries lists the latest deliveries with their endpoint, event, attempt and, for failures, why (HTTP 503, a timeout, blocked: …). The Dead filter lists every dead delivery of the agent.
  • Replay on a delivery sends it again (a delivered one too).
  • Replay all dead on an endpoint re-sends its dead deliveries, the latest 500 at a time.
  • Disable pauses an endpoint: its events are still queued, and sent once you Enable it again.

Where a receiver may live

A receiver must be reachable from AgentOS over HTTPS on a public or private address. Loopback and link-local addresses, and AgentOS’s own internal networks, are refused, both when you save the endpoint and again before every delivery. Your installation may refuse other internal ranges too; a refused delivery shows blocked: … with the reason.