Agent skill
VideoAsk Webhooks Skill
Receive and authenticate VideoAsk webhooks. Use when setting up a VideoAsk webhook endpoint, adding a secret header (Connect tab or API), debugging 401s, or handling form_response, form_response_transcribed, form_author_message, form_contact_message, form_contact_tagged and form_contact_untagged events.
Install this skill
npx skills add hookdeck/webhook-skills --skill videoask-webhooks
VideoAsk (the Typeform video-form product) sends a JSON POST when a respondent finishes a videoask, a message is exchanged or a contact is tagged. Requests are not signed. The way to authenticate them is a custom header you add to the webhook: in the videoask's Connect tab (Add a secret: a header name and value), or through the API (PUT /forms/{form_ with a headers object). Your endpoint then checks that header against the value you chose.
When to Use This Skill
- How do I receive VideoAsk webhooks?
- Does VideoAsk sign webhook payloads? (No: use a secret header)
- How do I add a secret header to a VideoAsk webhook?
- How do I handle
form_response,form_,response_ transcribed form_author_message,form_contact_messageor tag events? - Why does my VideoAsk webhook endpoint return 401?
Verification (core)
const crypto = require('crypto');
// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
const ha = crypto.createHash('sha256').update(String(a)).digest();
const hb = crypto.createHash('sha256').update(String(b)).digest();
return crypto.timingSafeEqual(ha, hb);
}
function verifyVideoAskRequest(headers, {
headerName = process.env.VIDEOASK_WEBHOOK_HEADER || 'secret',
secret = process.env.VIDEOASK_WEBHOOK_SECRET,
} = {}) {
if (!secret) return false; // never accept when unconfigured
const received = headers[headerName.toLowerCase()]; // Node lowercases header names
return Boolean(received) && safeEqual(received, secret); // compare the WHOLE value
}
- The header name and value are yours: you choose them under Add a secret in the Connect tab, or in the API's
headersobject (docs example:{"secret": "open-sesame"}). The name defaults tosecrethere; setVIDEOASK_WEBHOOK_HEADERif you used another. Look it up case-insensitively. VIDEOASK_WEBHOOK_SECRETis the exact, whole header value, including anyBearerprefix you typed. Do not strip or parse a prefix; compare the whole string.- Return
401for a missing or mismatched header,400for a body that isn't a JSON object,2xxonce handled (VideoAsk retries failures 3 times). - Read the body raw (
express.raw({ type: '*/*' })) and parse it only after the check passes. - A static shared credential authenticates the sender, not the body, and gives no replay protection (no signature, no timestamp). Use HTTPS only, and rotate the credential (edit the webhook's secret in the Connect tab or through the API, then your env var) if it leaks.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Event Types
The payload's event_type field carries the event name.
| Event | Sent When |
|---|---|
form_response | A videoask is completed or abandoned and all media is transcoded |
form_ | Same, and media is also transcribed (can take 3-4 minutes) |
form_author_message | The videoask creator sends a message to a contact (media transcoded and transcribed) |
form_contact_message | A contact sends a message (media transcoded and transcribed) |
form_contact_tagged | A tag is added to a contact |
form_contact_untagged | A tag is removed from a contact |
The tag events come from the help centre's event list; the docs show no example payload for them.
Environment Variables
VIDEOASK_WEBHOOK_HEADER=secret # Header name you set in the webhook's headers object
VIDEOASK_WEBHOOK_SECRET=open-sesame # Exact, whole header value
Local Development
VideoAsk can't reach localhost. Tunnel with the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 videoask --path /webhooks/videoask
Use the printed URL as the webhook url when you call the VideoAsk API.
Resources
- references/overview.md - What VideoAsk webhooks are, events and payload shape
- references/setup.md - Create the webhook with a secret header via the API
- references/verification.md - Header check details, limits, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests