Verify webhook signature
shieldlabs_verify_webhook_signatureValidate a received webhook by matching its X-Shield-Signature against the raw body and signing secret, and identify common body changes causing mismatches.
Instructions
Check a received ShieldLabs webhook delivery: does its X-Shield-Signature header match the raw body for the endpoint signing secret? For debugging a webhook endpoint. SHIELDLABS_WEBHOOK_SECRET is not set on this server, so pass secret.
The signature is "sha256=" plus the lowercase hex HMAC-SHA256 of the raw body, keyed with the full signing secret including its whsec_ prefix. While a secret is rotated, give several secrets separated by commas (in secret or in SHIELDLABS_WEBHOOK_SECRET): the delivery is valid when any of them matches, and matched_secret tells which. When the signature does not match a body of up to 64 KB, the tool tests common body changes (re-serialized JSON, unescaped characters, added newline) and says which one explains the mismatch. It never returns a secret or an expected signature.
Args:
payload (string): raw body exactly as received
signature_header (string): value of X-Shield-Signature
secret (string, optional): whsec_... signing secret of the endpoint, or several separated by commas
payload_encoding ('utf8' | 'base64'): default 'utf8'
response_format ('markdown' | 'json'): default 'markdown'
Returns (json): { "valid": boolean, "secret_source": "argument" | "environment", "secrets_checked": number, "matched_secret": number | null, "checks": [{ check, ok, detail }], "event": { event_type, schema_version, created_at, request_id, risk_score, risk_band } | null, "hint": string | null }
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| secret | No | Endpoint signing secret including its whsec_ prefix, or several separated by commas while you rotate. Defaults to SHIELDLABS_WEBHOOK_SECRET from the server environment. | |
| payload | Yes | The raw request body exactly as received: the bytes that were signed. Do not pretty-print, re-serialize or trim it. | |
| response_format | No | Output format: 'markdown' (default) for readable text, 'json' for structured data | markdown |
| payload_encoding | No | 'utf8' (default) when payload is the body text; 'base64' when payload is the body bytes encoded as base64 (use it when exact bytes such as a trailing newline matter) | utf8 |
| signature_header | Yes | Value of the X-Shield-Signature header, for example "sha256=ea26857...fdd8" |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| hint | Yes | ||
| event | Yes | ||
| valid | Yes | ||
| checks | Yes | ||
| secret_source | Yes | ||
| matched_secret | Yes | Position, from 1, of the secret that matches, in the order given; null when none | |
| secrets_checked | Yes | How many signing secrets were checked (several while a secret is rotated) |