Skip to content

Outbound webhook Growth+

A signed HTTPS POST to your endpoint every time a finding event happens. Useful for pushing CredWatch events into your own SIEM, ticketing system, or internal slack bot.

Set up

  1. Go to Integrations → Alerts & Tickets → Outbound Webhook.
  2. Enter your endpoint URL — must be https://.
  3. Click Save Endpoint.
  4. CredWatch generates a 32-byte secret and shows it to you once. Copy it into your endpoint's config — we never show it again.
  5. To rotate the secret later, re-save the URL — the Update Endpoint button regenerates the secret (and the new value is shown once, same as the initial save).

Events sent

Event When
finding.new A new finding has been detected and validated against the issuing service
finding.resolved A finding was marked resolved (manually or auto-resolved on rescan)
finding.false_positive A finding was marked false positive

Payload shape

{
  "event": "finding.new",
  "delivered_at": "2026-05-21T14:33:12Z",
  "client_slug": "acme",
  "finding": {
    "id": "a3f8c2d1-b4e5-46f0-9a8b-1c2d3e4f5a6b",
    "status": "active",
    "validation_status": "valid",
    "validation_confidence": "high",
    "composite_score": 87,
    "source_type": "repo",
    "source_visibility": "public",
    "source_url": "https://github.com/acme/web/blob/abc123/src/config.ts#L42",
    "repo_full_name": "acme/web",
    "file_path": "src/config.ts",
    "line_number": 42,
    "matched_text": "sk-a1****cd34",
    "pattern": {
      "name": "OpenAI API Key",
      "secret_type": "openai"
    },
    "first_seen_at": "2026-05-21T14:30:01Z"
  }
}

The matched_text is always masked — we never include the raw credential. The source_url will, however, include any tokens that were part of the original URL (e.g. a presigned S3 URL), so treat webhook bodies as sensitive.

Signature verification

Every request includes an HMAC-SHA256 signature in the X-CredWatch-Signature header:

POST /your-endpoint HTTP/1.1
Content-Type: application/json
X-CredWatch-Signature: sha256=8f4a3b2c...
User-Agent: CredWatch-Webhook/1.0

The signature is HMAC-SHA256(secret, raw_request_body) hex-encoded, prefixed with sha256=.

Verifying in Python

import hmac
import hashlib

def verify(request_body: bytes, signature_header: str, secret: str) -> bool:
    if not signature_header.startswith("sha256="):
        return False
    expected = hmac.new(
        secret.encode(),
        request_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature_header)

Verifying in Node.js

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, signatureHeader, secret) {
  if (!signatureHeader?.startsWith("sha256=")) return false;
  const expected = "sha256=" + createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader),
  );
}

Always verify the signature

Without signature verification, anyone who guesses your endpoint URL can post fake findings to it. The secret is the only thing that proves the request came from CredWatch.

Delivery semantics

  • Timeout — we wait 10 seconds for a response.
  • Success — any HTTP 2xx response.
  • Failure — non-2xx, timeout, or connection error. We do not retry. The event is logged to our audit trail but not re-attempted.
  • At-most-once delivery — for critical workflows, also pull from the API periodically as backstop.

If your endpoint is down for an extended period, you'll miss events. Plan accordingly.

Disable

Click Remove webhook to stop delivery. This clears both the URL and the secret — there's no separate "pause" state. To resume later, re-save the URL (a new secret is issued at that point).


See also: Slack & PagerDuty alerts — simpler than a webhook if you just want notifications.