Agent skill
Velt Webhooks Skill
Receive and verify Velt webhooks (Advanced V2, Enterprise, signed with Standard Webhooks). Use when setting up Velt webhook handlers, debugging webhook-signature verification, or handling events like comment_annotation.add, comment.add, huddle.join, crdt.update_data, recorder.done, and execution.completed.
Install this skill
npx skills add hookdeck/webhook-skills --skill velt-webhooks
Velt is an SDK for in-app collaboration: comments, huddles, CRDT sync, recordings and review workflows. Its Advanced (V2) webhooks, available on Enterprise only, are delivered through Svix and signed with Standard Webhooks headers: webhook-id, webhook-timestamp and webhook-signature. The event name is the top-level event field of a JSON body shaped {actionType, data, event, platform, source, webhookId}.
Requirement. Hookdeck's configuration alert for this source reads: "Only Velt Advanced (V2) webhooks, available on Enterprise, are signed. Basic (V1) webhooks send an auth token instead and fail verification." Basic (V1) webhooks only send an optional auth token in the
Authorizationheader asBasic <token>.
When to Use This Skill
- How do I receive Velt webhooks?
- How do I verify Velt webhook signatures (
webhook-signature,whsec_secret)? - How do I handle
comment_annotation.add,comment.add,crdt.update_dataorrecorder.doneevents? - Why is my Velt webhook signature verification failing, or rejecting Hookdeck retries?
- Why do Velt Basic (V1) webhooks fail signature verification?
Verification (core)
Signed content is {webhook-id}.{webhook-timestamp}.{raw body}. Velt signs it with HMAC-SHA256 using the base64-decoded secret (the part after whsec_), base64-encodes the result, and sends one or more space-separated v1,<signature> entries. Use a Standard Webhooks library (standardwebhooks on npm and PyPI), which compares in constant time. Read the webhook-* headers, and when webhook-id is absent fall back to the svix-* headers (svix-id, svix-timestamp, svix-signature), as Hookdeck does.
const { Webhook } = require('standardwebhooks');
const prefix = req.get('webhook-id') ? 'webhook' : 'svix';
const headers = {
'webhook-id': req.get(`${prefix}-id`),
'webhook-timestamp': req.get(`${prefix}-timestamp`),
'webhook-signature': req.get(`${prefix}-signature`),
};
// rawBody: the raw Buffer/string, never re-serialized JSON
const event = new Webhook(process.env.VELT_WEBHOOK_SECRET).verify(rawBody, headers);
// throws on a bad signature or a timestamp outside the window; returns the parsed body
from standardwebhooks.webhooks import Webhook, WebhookVerificationError
wh = Webhook(os.environ["VELT_WEBHOOK_SECRET"]) # "whsec_..."
event = wh.verify(raw_body, {"webhook-id": id_, "webhook-timestamp": ts, "webhook-signature": sig})
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Each endpoint has its own secret in the Velt console. It starts with whsec_. Keep the full value in VELT_WEBHOOK_SECRET. Handlers fail closed: with the variable unset they return 500 instead of accepting anything. A missing header or a bad signature returns 400. The raw body is required, so in Express use express.raw({ type: '*/*' }) and parse the body only after the check.
Hookdeck retries and replays hit the 5-minute window
The Standard Webhooks libraries always enforce a fixed 5-minute timestamp window, and it can't be configured. Velt re-signs each attempt with a fresh webhook-timestamp, but Hookdeck retries and replays resend the original timestamp, so the library rejects any retry or replay that happens more than 5 minutes after the original delivery. If you verify behind Hookdeck (or replay old events), use the manual verifier in references/verification.md, where the window can be dropped or widened. Deduplicate on webhook-id instead of relying on the timestamp.
Common Event Types
33 events are documented, and the list may not be exhaustive. The name is event in the JSON body. The examples handle all of these:
| Event | Triggered When |
|---|---|
comment_annotation.add | A comment thread is created with its first comment |
comment_ | A thread is assigned to a user |
comment_ | A thread's status changes |
comment_ | A thread's priority changes |
comment_ | A custom list item is added or changed on a thread |
comment_ / .unsubscribe | A user subscribes to or leaves a thread |
comment_ / .reject / .approve | A moderator acts on a thread (Moderator Mode only) |
comment_ / .suggestion_reject | A suggestion is accepted or rejected (opt-in) |
comment.add / .update / .delete | A comment is added, edited or removed |
comment.reaction_add / .reaction_delete | A reaction is added or removed |
huddle.create / huddle.join | A huddle is created or joined |
crdt.update_data | CRDT data is updated (5-second debounce) |
recorder.done | A recording finishes processing |
execution.dispatched / .completed / .failed / .cancelled | Review workflow execution lifecycle |
step.awaiting-approval / .completed / .failed / .breached / .cancelled | Review workflow step lifecycle |
group.quorum-met, loop.iteration-started, loop.exhausted | Review workflow groups and loops |
data holds actionUser, the feature object (commentAnnotation, crdtData, ...) and metadata (apiKey, document, organization, pageInfo). Encoded (Base64) or encrypted deliveries are opt-in and have no top-level event. See references/overview.md for the full list and shape.
Environment Variables
# Signing secret of the Advanced (V2) webhook endpoint (Standard Webhooks format, starts with whsec_)
VELT_WEBHOOK_SECRET=whsec_xxxxx
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 velt --path /webhooks/velt
Add the tunnel URL as an endpoint in the Velt console, then send an example event from its Testing tab.
Reference Materials
- references/overview.md - Velt webhook concepts, all 33 events, payload shape, encoded and encrypted payloads
- references/setup.md - Add an endpoint in the Velt console, get the secret, test, delivery and retries
- references/verification.md - Standard Webhooks verification details, header fallback, manual verifier, timestamp window