Agent skill
Vanta Webhooks Skill
Receive and verify Vanta webhooks (delivered via Svix). Use when setting up Vanta webhook handlers, debugging svix-signature verification, or handling compliance events like v1.questionnaire.status-changed, v1.vendor.decision.created, v1.trust-center.access-request.approved, and v1.evidence.status-changed.
Install this skill
npx skills add hookdeck/webhook-skills --skill vanta-webhooks
Vanta (compliance automation) sends webhooks through Svix. Every delivery is an HTTP POST with a JSON body and three signature headers: svix-id, svix-timestamp, and svix-signature.
When to Use This Skill
- How do I receive Vanta webhooks?
- How do I verify Vanta webhook signatures (
svix-signature)? - How do I handle
v1.questionnaire.status-changedorv1.vendor.decision.createdevents? - How do I react to Trust Center access requests (
v1.trust-center.access-request.received)? - Why is my Vanta webhook signature verification failing?
Verification (core)
Signed content is {svix-id}.{svix-timestamp}.{raw body}. Vanta signs it with HMAC-SHA256 using the base64-decoded secret (the part after whsec_), base64-encodes the result, and sends one or more space-delimited v1,<signature> entries. Vanta recommends the official svix library, which also enforces the 5-minute timestamp window and compares signatures in constant time.
import { Webhook } from 'svix'; // svix 2.x is ESM-only
const wh = new Webhook(process.env.VANTA_WEBHOOK_SECRET); // "whsec_..."
// rawBody: the raw Buffer/string, never re-serialized JSON
wh.verify(rawBody, {
'svix-id': req.headers['svix-id'],
'svix-timestamp': req.headers['svix-timestamp'],
'svix-signature': req.headers['svix-signature'],
}); // throws WebhookVerificationError on a bad signature or stale timestamp
const body = JSON.parse(rawBody.toString('utf8')); // parse only after verify passes
from svix.webhooks import Webhook, WebhookVerificationError
wh = Webhook(os.environ["VANTA_WEBHOOK_SECRET"])
wh.verify(raw_body, {"svix-id": msg_id, "svix-timestamp": ts, "svix-signature": sig})
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Common Event Types
Event types follow v1.<domain>.<entity>.<action>. The event reference documents each event's payload (for example {"questionnaire": {"id": "123", "status": "COMPLETE"}}); it does not document a type field in the body. The examples read type from an envelope if one is present and otherwise fall back to the payload's top-level key.
| Event | Triggered When |
|---|---|
v1.questionnaire.status-changed | A questionnaire's status changes (e.g. COMPLETE, APPROVED) |
v1.questionnaire.export-completed | A requested questionnaire export is ready |
v1.vendor.decision.created | A vendor risk decision is recorded |
v1.trust-center.access-request.received | Someone requests access to your Trust Center |
v1.trust-center.access-request.approved | A Trust Center access request is approved |
v1.evidence.status-changed | Audit evidence status changes (Audit Partner accounts only) |
See references/overview.md for all 25 events.
Environment Variables
# Settings → Webhooks → your endpoint → Signing Secret (starts with whsec_)
VANTA_WEBHOOK_SECRET=whsec_xxxxx
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 vanta --path /webhooks/vanta
Register the tunnel URL in Vanta under Settings → Webhooks → Add Endpoint, then use the endpoint's Testing tab to Send Example events.
Reference Materials
- references/overview.md - Vanta webhook concepts, full event list, payloads, retries
- references/setup.md - Register an endpoint and get the signing secret
- references/verification.md - Signature verification details and gotchas