Agent skill
CloudTalk Webhooks Skill
Receive and verify CloudTalk webhooks (cloud call center). Use when setting up CloudTalk webhook handlers, debugging Svix signature verification (svix-id, svix-timestamp, svix-signature, whsec_ secret), deduplicating on event_id, or handling events like call.started, call.answered, call.ended, call.recording_ready, contact.created, message.received, transcript.ready and user.status_changed.
Install this skill
npx skills add hookdeck/webhook-skills --skill cloudtalk-webhooks
CloudTalk is a cloud call center. Its account-level webhooks (Settings → Webhooks in the Dashboard) push call, contact, user, message, Conversation Intelligence, AI Voice Agent and Dialer events to your HTTPS endpoint as JSON. They are signed with the Svix scheme.
When to Use This Skill
- How do I receive CloudTalk webhooks?
- How do I verify a CloudTalk webhook signature (
svix-signature)? - How do I handle
call.started,call.answeredandcall.endedevents? - How do I get a call recording after
call.ended(call.recording_ready)? - Why is my CloudTalk webhook signature verification failing?
- Why am I processing the same CloudTalk event twice?
Verification (core)
| Header | Value |
|---|---|
svix-id | Delivery id. Same on every retry of the same event |
svix-timestamp | Unix seconds when the request was sent |
svix-signature | Space-delimited list of v1,<base64> signatures |
Signed content is {svix-id}.{svix-timestamp}.{raw body}, HMAC-SHA256, base64. The key is the base64-decoded part of the secret after whsec_. The svix library (npm and PyPI) does this, enforces a 5-minute timestamp tolerance, and compares in constant time. Hookdeck retries and replays resend the original svix-timestamp, so the library rejects them once they are more than 5 minutes old. If you receive through Hookdeck and need late retries to pass, use the manual check in references/verification.md and drop or widen its timestamp window.
import { Webhook } from 'svix'; // svix 2.x is ESM-only
// rawBody: the exact bytes received (express.raw({ type: '*/*' }) / request.text()), NOT re-serialised JSON
function verifyCloudTalkWebhook(rawBody, headers) {
const secret = process.env.CLOUDTALK_WEBHOOK_SECRET; // whsec_...
if (!secret) throw new Error('CLOUDTALK_WEBHOOK_SECRET not set'); // fail closed → 500
new Webhook(secret).verify(rawBody, {
'svix-id': headers['svix-id'],
'svix-timestamp': headers['svix-timestamp'],
'svix-signature': headers['svix-signature'],
}); // throws WebhookVerificationError → 400
return JSON.parse(rawBody.toString('utf8')); // svix 2.x verify() returns nothing
}
Python: from svix.webhooks import Webhook, then Webhook(secret).verify(raw_ followed by json.loads(raw_body).
svix 2.x gotcha:
verify()no longer returns the parsed payload (JS since 2.2, Python since 2.0). CloudTalk's docs showevent = wh.verify(...), which givesundefined/Noneon current svix. Verify, then parse the raw body yourself.
Manual verification (no SDK) is in references/verification.md.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
What Is Not Signed This Way
Only the account-level webhooks from Settings → Webhooks carry these headers. The Call Flow Designer Webhook step, an AI Voice Agent's Send via Webhook option and Workflow Automation actions send their own payloads over their own delivery path. They are not signed with this scheme, and the retry, replay and retention behaviour here does not apply to them. Authenticate those the way their own setup screen describes, and don't point them at a handler that requires svix-* headers.
Event Envelope and Deduplication
Every delivery has the same envelope; only data differs. Route on type, and ignore types you don't recognize because new ones are added over time.
{ "event_id": "3f9a2b4c-8d1e-8a2b-9c3d-4e5f60718293", "type": "contact.created", "version": "v1",
"occurred_at": "2026-08-17T09:34:21.512Z", "company_id": "123456",
"data": { "id": "44210", "name": "Jane Doe", "phones": ["+12025550143"] } }
Delivery is at-least-once, so de-duplicate on event_id (same on every retry; claim it before doing the work, and keep it for 30 days because Resend and Recover replay that far back). Order is not guaranteed: sort by occurred_at.
Common Event Types
| Event | Fired when |
|---|---|
call.started | A call begins, before anyone picks up |
call.ringing | A call rings on a specific user |
call.answered | A call is picked up |
call.held / call.resumed | A call is put on or taken off hold |
call.ended | A call finishes, with durations, contacts and the handling user |
call.recording_ready | A recording or voicemail is stored (async, after call.ended) |
call.tags_modified | Tags are added to or removed from a call |
contact.created / contact.updated / contact.deleted | A contact changes (deleted carries the id only) |
user.created / user.updated / user.deleted / user.status_changed | Team changes and user availability |
message.sent / message.received | An SMS, MMS or WhatsApp message is sent or arrives |
transcript.ready / cidata.ready | Transcript, or AI analysis (summary, sentiment, topics, score), is ready |
voice_ | An AI Voice Agent hands over extracted data |
dialer.disposition_ / dialer.survey_filled | Dialer campaign disposition or survey response |
See references/overview.md for payload details.
Delivery Semantics
- Return a
2xxwithin 15 seconds.3xxredirects are not followed and count as failures. Verify, enqueue, return200, process asynchronously. - Retries: up to 50 over about 11.5 hours (5s, 30s, 2m, 5m, 10m, then every 15m). An endpoint failing continuously for about 5 days is disabled, then re-enabled automatically if it recovers within 12 hours.
- Payloads are retained for 30 days for Resend and Recover in the delivery log.
Environment Variables
CLOUDTALK_WEBHOOK_SECRET=whsec_xxxxx # Settings > Webhooks > the endpoint > signing secret (one per endpoint)
Local Development
# Express / Next.js (use 8000 for FastAPI). No install or account required.
npx hookdeck-cli listen 3000 cloudtalk --path /webhooks/cloudtalk
Add the printed URL as an endpoint under Settings → Webhooks, then use Send test event.
Reference Materials
- references/overview.md - Envelope, all 22 event types, payload highlights
- references/setup.md - Creating an endpoint, signing secret, test events, replay
- references/verification.md - SDK and manual verification, gotchas, debugging