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¶
- Go to Profile → Outbound webhook.
- Enter your endpoint URL — must be
https://. - Click Save.
- 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.)
- 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.