Agent skill
TIMIFY Webhooks Skill
Receive and authenticate TIMIFY webhooks. Use when setting up a TIMIFY webhook subscription endpoint, checking the custom "Include header name" header, debugging 401s, or handling appointment scheduling events like Event Created, Customers Updated and Resource Deleted.
Install this skill
npx skills add hookdeck/webhook-skills --skill timify-webhooks
TIMIFY (appointment scheduling) sends an HTTP POST with a JSON body to your Server URL when something happens in a webhook subscription's scope: a booking is created, a customer is deleted, a resource is updated. Webhooks are not signed. The only built-in protection is the optional custom header: enable Include header name when you create the subscription and TIMIFY adds that header, with the secret value you entered, to every request. Your endpoint authenticates the request by comparing the header with the value you stored.
Sync-type webhooks, such as Before Confirmations, expect a synchronous answer and aren't supported.
When to Use This Skill
- How do I receive TIMIFY webhooks?
- How do I authenticate TIMIFY webhook requests? (No signature: use the custom header)
- How do I use "Include header name" on a TIMIFY webhook subscription?
- How do I handle
Eventcreated, updated or deleted webhooks? - Why does my TIMIFY 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 verifyTimifyRequest(headers, secret = process.env.TIMIFY_WEBHOOK_SECRET,
name = process.env.TIMIFY_WEBHOOK_HEADER || 'Authorization') {
if (!secret) return false; // never accept when unconfigured
const received = headers[name.toLowerCase()]; // Node lowercases header names
return Boolean(received) && safeEqual(received, secret); // WHOLE value, no Bearer parsing
}
- The header name is whatever you typed in the subscription, so read it from
TIMIFY_WEBHOOK_HEADER(defaultAuthorization) and look it up case-insensitively. - Compare the whole header value with
TIMIFY_WEBHOOK_SECRET. If you enteredBearer abc123, the secret isBearer abc123; do not strip or parse the prefix. - Return
401for a missing header or a mismatch,400for a body that isn't a JSON object,200once handled. - Read the body raw (
express.raw({ type: '*/*' })) and authenticate before parsing it. - Know the limits. 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 value in the subscription and in
TIMIFY_WEBHOOK_SECRETif it leaks.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Webhooks and Types
TIMIFY's webhook overview lists these webhooks (the scope table) and their types. The overview page does not document the payload field names, so the examples dispatch defensively on an illustrative webhook and type and acknowledge anything they don't recognise.
| Webhook | Types |
|---|---|
| Customers | Created Updated Deleted |
| Event | Created Updated Deleted |
| Events | Deleted |
| Services | Created Updated Deleted |
| Resource | Created Updated Deleted |
| Company | Created Updated Deleted |
| Manager | Created Updated Deleted |
| Enterprise | Updated |
| Customer Fields | Created Updated Deleted |
| Shift | Created Updated Deleted |
| Notification | Created |
| Service Groups | Created Updated Deleted |
| Before Confirmations, Before Reminders | Sync (not supported) |
The Developer Platform application needs the scopes each webhook requires (see references/overview.md).
Environment Variables
TIMIFY_WEBHOOK_HEADER=Authorization # the header name you entered in the subscription
TIMIFY_WEBHOOK_SECRET=your-secret-value # the exact, whole header value
Local Development
TIMIFY can't reach localhost. Tunnel with the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 timify --path /webhooks/timify
Use the printed URL as the Server URL of the webhook subscription.
Resources
- references/overview.md - What TIMIFY webhooks are, webhooks, types and scopes
- references/setup.md - Create a subscription and enable Include header name
- references/verification.md - Header check details, gotchas, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests