SurfacedBySurfacedBy Docs

Webhooks Overview

Registering endpoints, delivery behaviour, retries, and the delivery log for outbound webhooks.

Ask an AI:Open in ChatGPTOpen in Claude

Outbound webhooks push SurfacedBy events to an endpoint you control, so you can react to completed checks, alerts, and other events without polling the API.

Registering an endpoint

Webhook endpoints are managed in the dashboard under Settings > Integrations > Webhooks. Dashboard webhooks need a paid plan (the trial included). Workspace owners and admins whose access is not limited to certain domains can add, edit, disable, and delete endpoints, send test events, and replay deliveries; every member can see the endpoints and their deliveries. Endpoints belong to the workspace that is active when you create them, and receive events about that workspace's dashboard domains.

A workspace that moves below a paid plan keeps its endpoints, but nothing is delivered to them, and they cannot be added, changed, tested, or replayed, until the workspace is on a paid plan again. Events that happen in the meantime are not queued for later delivery.

Endpoints registered in the Console are separate: they are not limited by plan, they receive events only about that Console account's domains, and they do not appear in the dashboard's webhook list. Dashboard endpoints never receive events about Console domains.

Each endpoint has:

  • The destination URL. It must start with https://, must not contain a username or password, and must resolve to a public address. Plain http:// is not accepted: the signature proves a delivery came from SurfacedBy, but only TLS keeps its contents private. To test locally, expose your receiver through an HTTPS tunnel or point the endpoint at a request inspector.
  • The event types it subscribes to. Pick at least one from the event list.
  • An optional description of up to 200 characters.
  • A signing secret that SurfacedBy generates and uses to sign every delivery. It is shown once, when the endpoint is created.

A workspace can register several endpoints with different event subscriptions. For example, you might send scan.completed to an analytics pipeline and alert.triggered to a chat bot.

Delivery

Each delivery is an HTTP POST with a JSON body (Content-Type: application/json, User-Agent: SurfacedBy-Webhook/1.0). Alongside the signature headers described in Signatures, every delivery carries:

HeaderMeaning
X-SurfacedBy-Event-IdThe event id. Identical to id in the body and stable across retries and replays.
X-SurfacedBy-Event-TypeThe event type, for example scan.completed.
X-SurfacedBy-Delivery-IdThe id of this delivery. A replay gets a new delivery id.
X-SurfacedBy-AttemptThe attempt number for this delivery, starting at 1.

Any 2xx response counts as delivered. Anything else counts as a failed attempt: a non-2xx status, a redirect (redirects are not followed), a connection error, or no response within 10 seconds. Respond quickly and do slow work asynchronously.

Delivery is at-least-once. Retries and replays can bring the same event to your endpoint more than once, so deduplicate on the event id.

Retries

A failed attempt is retried on a fixed schedule. After the first failed attempt SurfacedBy waits 10 seconds, then 30 seconds, 1 minute, 5 minutes, 30 minutes, 2 hours, and 6 hours between attempts. After the eighth failed attempt, roughly eight and a half hours after the first, the delivery is marked dead-lettered and is not retried again.

Delivery log and replay

Open an endpoint's Details in Settings > Integrations > Webhooks to see its 100 most recent deliveries, newest first. Each entry shows the status (Pending, Delivering, Delivered, Dead lettered), the attempt number, the last HTTP status your endpoint returned, the first 1,024 characters of the response body, and the time of the next attempt while one is scheduled. When no HTTP response came back, the entry shows a short note instead of a body: "Your endpoint did not respond in time.", "Could not connect to your endpoint.", or "The request to your endpoint failed before a response came back."

Replay re-sends any delivery in the log as a new delivery with the same event id and payload. The original entry is kept. Use it after you fix a receiver that was dead-lettering events.

Endpoint status

The endpoint list shows a status for each endpoint:

  • Awaiting first event - enabled, and no real event has been delivered to it successfully yet.
  • Active - enabled, at least one real event has been delivered, and fewer than three attempts in a row have failed.
  • Failing - three or more delivery attempts in a row failed. The badge is advisory: SurfacedBy keeps retrying on the schedule above and never disables an endpoint on its own.
  • Disabled - you turned the endpoint off. Nothing is delivered to it until you enable it again.

Test events do not affect the status or the failure count.

Testing

In an endpoint's Details, Send test event queues one delivery to that endpoint. The delivery carries the endpoint's first subscribed event type and "livemode": false. Its data has exactly the shape of a real event of that type, as described in the event reference, filled with example values and placeholder ids, plus your real workspace_id and workspace_slug. It is signed with the endpoint's real secret, so you can check your signature verification end to end. A request inspector or a local tunnel is useful while you build the receiver.

Security

Every delivery is signed with HMAC-SHA256 using the endpoint's signing secret. Verify the signature and the timestamp before trusting a payload; an attacker who learns your endpoint URL could otherwise POST arbitrary JSON to it. See Signatures.

On this page