Intro to Webhooks
Overview
SafeWeb webhooks deliver signed HTTP POST requests to your endpoint whenever key events occur. Instead of polling the API, register a URL and SafeWeb will push event data to you in real time.
Quick Start
- Register an endpoint —
POST /api/integrations/webhookswith your URL and the events you want - Store your secret — the response includes an HMAC signing secret (only shown once)
- Handle deliveries — accept POST requests at your URL and return a
2xxstatus - Verify signatures — validate the
X-SafeWeb-Signatureheader to confirm authenticity
curl -X POST https://connect.safeweb.co/api/integrations/webhooks \
-H "Content-Type: application/json" \
-H "SW-PARTNER-ID: your-partner-id" \
-H "SW-API-KEY: your-api-key" \
-d '{
"url": "https://yourapp.com/webhooks/safeweb",
"events": ["breach.new", "breach.resolved", "breach.unresolved", "email.added", "email.removed"]
}'Event Types
| Event | Trigger |
|---|---|
breach.new | New breach(es) discovered for a customer during a scan |
breach.resolved | A breach is marked as resolved |
breach.unresolved | A previously resolved breach is marked as unresolved |
email.added | One or more email addresses added to monitoring |
email.removed | One or more email addresses removed from monitoring |
Delivery Format
Every delivery is an HTTP POST with a JSON body and three headers:
| Header | Description |
|---|---|
Content-Type | application/json |
X-SafeWeb-Event | The event type, e.g. breach.new |
X-SafeWeb-Signature | sha256=<hex_digest> — HMAC-SHA256 of the raw request body |
The JSON body follows this structure:
{
"event": "breach.new",
"data": { ... },
"created_at": "2026-03-18T14:30:00.000Z"
}Payload by Event Type
breach.new
{
"event": "breach.new",
"data": {
"customer_uuid": "550e8400-e29b-41d4-a716-446655440000",
"breaches_found": 3,
"new_breach_names": ["LinkedIn-2024", "Adobe-2023"],
"emails_scanned": 5,
"timestamp": "2026-03-18T14:30:00.000Z"
},
"created_at": "2026-03-18T14:30:00.000Z"
}breach.resolved / breach.unresolved
{
"event": "breach.resolved",
"data": {
"customer_uuid": "550e8400-e29b-41d4-a716-446655440000",
"breach_name": "LinkedIn-2024",
"emails": ["user@example.com"],
"timestamp": "2026-03-18T14:30:00.000Z"
},
"created_at": "2026-03-18T14:30:00.000Z"
}email.added / email.removed
{
"event": "email.added",
"data": {
"customer_uuid": "550e8400-e29b-41d4-a716-446655440000",
"emails": ["user@example.com", "admin@example.com"],
"timestamp": "2026-03-18T14:30:00.000Z"
},
"created_at": "2026-03-18T14:30:00.000Z"
}Verifying Signatures
Every delivery is signed with your endpoint's secret using HMAC-SHA256. Compute the signature over the raw request body and compare it to the X-SafeWeb-Signature header.
const crypto = require('crypto');
function verifySignature(body, secret, signatureHeader) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}Always use a constant-time comparison to prevent timing attacks.
Retries
If your endpoint returns a non-2xx status code or the request times out (2 seconds), SafeWeb retries delivery up to 3 times with exponential backoff. After all attempts are exhausted the delivery is logged as failed.
Managing Endpoints
All management endpoints use the standard SW-PARTNER-ID and SW-API-KEY authentication headers.
Create an endpoint
POST /api/integrations/webhooks| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Your HTTPS endpoint URL |
events | string[] | Yes | Event types to subscribe to |
active | boolean | No | Defaults to true |
Returns the endpoint including the secret. Store it securely — it is not returned on subsequent requests.
List endpoints
GET /api/integrations/webhooksReturns all webhook endpoints for your organization.
Update an endpoint
PATCH /api/integrations/webhooks/{id}Provide any combination of url, events, or active to update. At least one field is required.
Delete an endpoint
DELETE /api/integrations/webhooks/{id}Permanently removes the endpoint and all associated delivery logs.
Best Practices
- Respond quickly — return a
2xxwithin a few seconds and process the payload asynchronously. Deliveries time out after 2 seconds. - Use HTTPS — webhook URLs must be publicly reachable HTTPS endpoints.
- Verify every delivery — always validate the
X-SafeWeb-Signatureheader before trusting the payload. - Handle duplicates — in rare cases the same event may be delivered more than once. Use the
created_atand payload fields to deduplicate. - Monitor failures — if your endpoint is consistently failing, disable it and investigate before re-enabling.
Get partner analytics GET
Retrieve high-level analytics about your partner account including total customers, active monitors, and breach statistics. Requires valid partner authentication via SW-PARTNER-ID and SW-API-KEY headers.
List webhook endpoints GET
Returns all webhook endpoints registered for the authenticated partner organization, ordered by most recently created first.