Delivery payloads
Forhttp webhooks the body is the raw event:
type is policy_deny, anomaly, or session_suspended. For policy_deny events from the LLM gateway, toolName holds the model name, serverId is the connection slug, and sessionId is an empty string. Slack and Discord webhooks receive a formatted message instead. Delivery is fire-and-forget: a failed delivery is not retried.
Signing
http webhooks are signed. Slack and Discord webhooks are not, because they cannot verify custom headers.
Each delivery carries two headers:
The HMAC key is the full secret string, including the
whsec_ prefix. The signed message is the timestamp, a dot, then the exact raw request body bytes.
The secret is shown once, when you create the webhook and when you rotate it. Store it then. In the dashboard, rotate from Settings → Webhooks with the Rotate signing secret row action.
When you verify a delivery:
- Compute the HMAC over the raw body, not a re-serialized JSON object.
- Reject timestamps more than 5 minutes from your clock, to block replays.
- Compare signatures with a constant-time function.
Rotate a secret
secret. It returns 400 for Slack and Discord webhooks.