GET /v1/findings. Register a URL, pick the event types you want, and verify each delivery’s signature.
Registering a webhook
Webhooks are managed in the dashboard under Settings → Integrations → Webhooks (admin role required):- Click Add webhook and enter your endpoint URL (
https://recommended; internal addresses are fine for on-prem receivers). - Choose the event types to receive.
- Copy the signing secret (
whsec_...) shown after registration — like API keys, it is displayed exactly once.
delivered, retrying, failed, pending), the most recent attempt’s HTTP status code and error detail, and its created / next-retry / completed timestamps.
Event types
Detection-rule matches are delivered as
detection_rule.matched, not finding.created — subscribe to both event types to cover everything that appears in GET /v1/findings.
Events are scoped like everything else: a webhook only receives events for hosts its registering user can see.
Payload
Every delivery is aPOST with a JSON body:
finding.reviewedaddsstatus(accepted/denied),reviewed_by, andnotestodata.detection_rule.matchedaddsrule({id, name, label}) todata.data.finding_idis always present; use it withGET /v1/findings/{id}if you need the full object later.
Verifying signatures
Each delivery carries these headers:
Recompute the HMAC with your signing secret over the timestamp, a literal
., and the raw request body, then compare in constant time:
Delivery and retries
- Respond with any
2xxwithin 15 seconds to acknowledge a delivery. Redirects are not followed and count as failures. - On failure, delivery retries with increasing delays — 1 minute, 5 minutes, 30 minutes, then 2 hours — and is marked
failedafter 5 total attempts. Each delivery’s attempt count and latest outcome are recorded in the delivery log. - Delivery is at-least-once: rare duplicates are possible, so dedup on
X-Hilt-Event-Idif your handler isn’t idempotent. - A newly registered webhook receives events from that moment on — the existing backlog of historical findings is not replayed.
