Agent skill
Rev AI Webhooks Skill
Receive and authenticate Rev AI (Rev.ai) speech-to-text webhooks. Use when setting up a Rev AI job callback endpoint, checking the Authorization header set in notification_config.auth_headers, debugging 401s, or handling transcribed and failed job notifications.
Install this skill
npx skills add hookdeck/webhook-skills --skill rev-ai-webhooks
Rev AI's asynchronous speech-to-text API sends one webhook (an HTTP POST) when a transcription job finishes: job.status is transcribed or failed. Payloads are not signed. The credential is the Authorization header you attach to the job in notification_config.
When to Use This Skill
- How do I receive Rev AI webhooks?
- How do I authenticate a Rev AI
notification_configcallback? - Does Rev AI sign webhook payloads? (No: a static Authorization header only)
- Why does my Rev AI webhook endpoint return 401?
- How do I handle
transcribedandfailedjob notifications and fetch the transcript?
Verification (core)
Submit the job with notification_config and an auth_headers object. Authorization is the only header allowed and its value must be <scheme> <token>:
{ "notification_config": { "url": "https://example.com/webhooks/rev-ai",
"auth_headers": { "Authorization": "Bearer <token>" } } }
Rev AI then sends that header on the callback. The key is the whole header value, scheme prefix included: compare the full Authorization header to REV_AI_AUTHORIZATION (e.g. Bearer <token>). Don't strip or parse the prefix:
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 verifyRevAiRequest(headers, expected = process.env.REV_AI_AUTHORIZATION) {
if (!expected) return false; // never accept when unconfigured
const received = headers['authorization']; // full value, e.g. "Bearer abc123"
return Boolean(received) && safeEqual(received, expected);
}
Return 401 when this fails, 400 for a body that isn't a JSON object, and 200 once handled. Read the body raw (express.raw({ type: '*/*' })) and parse JSON only after the check. Python and Next.js equivalents are in references/verification.md.
Limits of a static credential: it authenticates the sender, not the body, and gives no replay protection (no signature, no timestamp). Use HTTPS only, and rotate the credential if it leaks. The deprecated
callback_urlfield carries no auth at all, so usenotification_config.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Job Statuses in Webhooks
The webhook body is { "job": { ... } }. Rev AI sends it only when a job completes or fails:
job.status | Meaning | Useful fields |
|---|---|---|
transcribed | Transcript is ready | id, created_on, completed_on, duration_seconds |
failed | Job failed | failure (e.g. download_failure), failure_detail |
After transcribed, fetch the transcript with GET /speechtotext/v1/jobs/{id}/transcript. Rev AI retries every 30 minutes for up to 24 hours until your endpoint returns 200.
Environment Variables
REV_AI_AUTHORIZATION=Bearer replace-with-a-long-random-token # full header value
Local Development
npx hookdeck-cli listen 3000 rev-ai --path /webhooks/rev-ai
No account required. Use the printed URL as notification_config.url.
Resources
- references/overview.md - Job webhook payloads, statuses, failure codes, retries
- references/setup.md - Submitting jobs with notification_config and auth_headers
- references/verification.md - Header check in Node, Python and Next.js, gotchas
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests