SafeWeb API

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

  1. Register an endpointPOST /api/integrations/webhooks with your URL and the events you want
  2. Store your secret — the response includes an HMAC signing secret (only shown once)
  3. Handle deliveries — accept POST requests at your URL and return a 2xx status
  4. Verify signatures — validate the X-SafeWeb-Signature header 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

EventTrigger
breach.newNew breach(es) discovered for a customer during a scan
breach.resolvedA breach is marked as resolved
breach.unresolvedA previously resolved breach is marked as unresolved
email.addedOne or more email addresses added to monitoring
email.removedOne or more email addresses removed from monitoring

Delivery Format

Every delivery is an HTTP POST with a JSON body and three headers:

HeaderDescription
Content-Typeapplication/json
X-SafeWeb-EventThe event type, e.g. breach.new
X-SafeWeb-Signaturesha256=<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
FieldTypeRequiredDescription
urlstringYesYour HTTPS endpoint URL
eventsstring[]YesEvent types to subscribe to
activebooleanNoDefaults to true

Returns the endpoint including the secret. Store it securely — it is not returned on subsequent requests.

List endpoints

GET /api/integrations/webhooks

Returns 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 2xx within 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-Signature header before trusting the payload.
  • Handle duplicates — in rare cases the same event may be delivered more than once. Use the created_at and payload fields to deduplicate.
  • Monitor failures — if your endpoint is consistently failing, disable it and investigate before re-enabling.

On this page