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 Profile → Outbound webhook.
  2. Enter your endpoint URL — must be https://.
  3. Click Save.
  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. (If you lose it, click Rotate secret to issue a new one.)
  5. Click Send test event to verify your endpoint is reachable.

Events sent

Event When
finding.validated A new finding has been 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.validated",
  "delivered_at": "2026-05-21T14:33:12Z",
  "client_slug": "acme",
  "finding": {
    "id": "01HXYZ...",
    "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

To stop webhook delivery without losing the secret, set the URL to empty and save. To fully revoke, click Remove — this clears both the URL and the secret.


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