Webhooks Overview
Delivery guarantees, retries, and failure handling for outbound webhooks.
Outbound webhooks push SurfacedBy events to an HTTPS endpoint you control. They are the recommended way to react to scan completions, alerts, and other events in real time without polling the API.
Registering an endpoint
You register webhook endpoints under Settings -> Integrations in the dashboard. Each endpoint has:
- The destination URL (must be HTTPS).
- The set of event types you want to subscribe to.
- A signing secret that SurfacedBy uses to sign every delivery.
A single workspace can register multiple endpoints with different event subscriptions. For example, you might send scan.completed to an analytics pipeline and alert.triggered to a Slack bot.
Delivery guarantees
SurfacedBy guarantees at-least-once delivery. In normal operation you will see each event exactly once, but during retries or after a network partition your endpoint may receive the same event twice. Every delivery includes a unique event id that you can use to deduplicate.
Retries
If your endpoint returns a non-2xx response, or does not respond within the delivery timeout, SurfacedBy retries with exponential backoff. Retry attempts continue for a bounded window, after which the event is moved to the dead-letter queue.
A 2xx response (any 200 to 299 status) counts as successful delivery. Your endpoint should respond as fast as it can; do the actual work asynchronously if it might take more than a couple of seconds.
Dead-letter queue
Deliveries that exhaust retries are stored in the dead-letter queue so you can investigate rather than silently losing data. From Settings -> Integrations you can:
- View recent failed deliveries and their response bodies.
- Replay individual events once the underlying issue is fixed.
- Pause an endpoint if it is failing at scale, so retries do not saturate your infrastructure.
Security
Every delivery is signed with HMAC-SHA256 using the endpoint's signing secret. The signature is in the X-SurfacedBy-Signature header and the request timestamp is in the X-SurfacedBy-Timestamp header. Your handler must verify both before trusting the payload. See Signatures.
Never accept a webhook payload without verifying the signature. An attacker who learns your endpoint URL could otherwise POST arbitrary JSON to it.
Testing
Use a request inspector (for example, webhook.site or a local tunnel) during development. Test keys can register their own webhook endpoints that only receive sandbox events, so you can integrate end to end without touching production traffic.