Agent skill

Autotask Webhooks Skill

Receive and verify Autotask PSA webhooks (Datto, now Kaseya). Use when setting up Autotask webhook handlers, debugging X-Hook-Signature verification, or handling Company, Contact, Ticket and TicketNote Create, Update, Delete and Deactivated callouts.

Install this skill

npx skills add hookdeck/webhook-skills --skill autotask-webhooks


When to Use This Skill

  • How do I receive Autotask webhooks?
  • How do I verify the Autotask X-Hook-Signature header?
  • Why is my Autotask webhook signature verification failing?
  • How do I handle Ticket, Company or Contact Create/Update/Delete callouts?
  • How do I create an Autotask webhook with a SecretKey through the REST API?

Verification (core)

Autotask signs the raw request body with HMAC-SHA1, keyed with the SecretKey set when the webhook was created (up to 64 characters). The digest is base64 (keep the = padding) and is sent as X-Hook-Signature: sha1=<base64>, for example sha1=UaDXFl2DRDu9dnINVkFle7y5uAE=. There is no timestamp and Autotask ships no verification SDK, so verify manually.

const crypto = require('crypto');

function verifyAutotaskWebhook(rawBody, header, secret) {
  if (typeof header !== 'string' || !header.startsWith('sha1=')) return false;
  const received = header.slice('sha1='.length);
  const expected = crypto.createHmac('sha1', secret).update(rawBody).digest('base64');
  // Equal-length UTF-8 buffers, no lenient base64 decode of the header
  const a = Buffer.from(received, 'utf8');
  const b = Buffer.from(expected, 'utf8');
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

In Python, compare bytes so a non-ASCII header returns 401 instead of raising a 500: hmac.compare_digest(expected.encode(), received.encode()).

Always verify the raw body. In Express use express.raw({ type: '*/*' }) so any content type is verified; don't JSON.parse first.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Payload and Events

Autotask has no event-name string. Each callout is a JSON POST with Action, Guid, EntityType, Id, Fields, EventTime, SequenceNumber and PersonID. Dispatch on EntityType and Action.

ActionTriggered WhenFields
CreateA record is createdAll subscribed, non-null fields and UDFs
UpdateA subscribed field changesFields and UDFs that changed
DeleteA record is deletedBase payload only
DeactivatedThe webhook is deactivatedBase payload only; Guid identifies the webhook

Entities that support webhooks: Companies, Contacts, Assets (Configuration Items), Tickets and Ticket Notes. The examples handle Company, Contact, Ticket and TicketNote.

For the full reference, see Creating a webhook.

Environment Variables

AUTOTASK_WEBHOOK_SECRET=your_webhook_secret_key_here   # the SecretKey set when creating the webhook

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 autotask --path /webhooks/autotask

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 6, 2026

View on GitHub →