Open-Source Wikis

/

Cal.com

/

Features

/

Webhooks and Tasker

calcom/cal.com

Webhooks and Tasker

Active contributors: Joe, Pedro, Romit

Purpose

Cal.diy needs two kinds of asynchronous work to keep bookings reliable:

  • Webhooks — outbound HTTP callbacks fired on booking events (BOOKING_CREATED, BOOKING_RESCHEDULED, BOOKING_CANCELLED, MEETING_ENDED, RECORDING_READY, ...) that customers and integrations subscribe to.
  • Tasker — an in-process deferred-job queue backed by a Postgres table for short-lived work that should not block the booking response (sending reminder emails, scheduling no-show triggers, post-booking follow-ups).

Both live under packages/features/.

Where the code lives

Concern Code
Webhook subscriptions Webhook model in packages/prisma/schema.prisma
Webhook dispatch packages/features/webhooks
Webhook payload schemas packages/features/webhooks/lib/
Tasker queue packages/features/tasker
Task model Task (or similar) in packages/prisma/schema.prisma
Trigger.dev (heavy / scheduled jobs) packages/features/trigger.config.ts + per-feature jobs
GitHub Actions cron .github/workflows/cron-*.yml

Webhooks

The Webhook Prisma model stores subscriber URL, secret (for HMAC signing), event types, and scope (user / team / event-type / app). On a booking event, the booking pipeline calls into packages/features/webhooks which:

  1. Resolves which webhooks match the event type and scope.
  2. Builds the payload (canonical Cal.com event JSON).
  3. HMAC-signs the payload using the per-webhook secret.
  4. Enqueues delivery through the tasker (so a slow subscriber doesn't slow the booking response).
  5. Records delivery attempts and exposes a retry endpoint.

Cron workflow .github/workflows/cron-webhooks-triggers.yml retries failed deliveries.

Tasker

The tasker is an in-process queue that uses Postgres as the durable backing store. The Task table holds rows like:

id        | uuid
type      | string  (e.g., "send-reminder-email")
payload   | jsonb
runAt     | timestamp
attempts  | int
status    | enum (pending, in_progress, succeeded, failed)

Producers enqueue tasks; consumers (the web app or a worker process) pull tasks where runAt <= now() and execute them. Failed tasks are retried with backoff. The queue is configured per-environment.

Why not Redis or a cloud queue? Cal.diy is designed to be self-hostable with a single Postgres dependency. The tasker keeps the deployment story simple. Trigger.dev (which does use cloud infrastructure) handles the heavier-duty scheduled jobs.

Trigger.dev

packages/features/trigger.config.ts registers Trigger.dev jobs (e.g., long-running calendar syncs, monthly digest emails). The config wires job declarations from individual features into the Trigger.dev workspace. Yarn scripts:

yarn dev:trigger              # local Trigger.dev dev server
yarn deploy:trigger:staging
yarn deploy:trigger:prod

Logs from Trigger.dev jobs route through packages/lib/triggerDevLogger.ts so they integrate with the rest of the observability stack.

Cron workflows

.github/workflows/cron-*.yml runs scheduled HTTP calls into the web app. Examples:

  • cron-bookingReminder.yml — drains booking reminder queue
  • cron-scheduleEmailReminders.yml, cron-scheduleSMSReminders.yml, cron-scheduleWhatsappReminders.yml
  • cron-monthlyDigestEmail.yml
  • cron-changeTimeZone.yml
  • cron-checkSmsPrices.yml
  • cron-syncAppMeta.yml
  • cron-stale-issue.yml
  • cron-downgradeUsers.yml
  • cron-webhooks-triggers.yml

Each one is a short YAML that invokes a known endpoint with a shared secret.

Integration points

  • Bookings are the primary producer of both webhooks and tasker jobs.
  • Workflows (legacy EE) used to build on top of these; their runtime is being removed.
  • Audit log (packages/features/booking-audit) records every webhook attempt for debuggability.

Entry points for modification

  • Add a webhook event type: extend the WebhookTriggerEvents enum, add a payload builder under packages/features/webhooks/lib/, and emit from the relevant feature.
  • Add a tasker task type: register the type in the tasker config, add a producer (call tasker.enqueue(...)), and a consumer.
  • Add a Trigger.dev job: declare it in packages/features/trigger.config.ts (or wire from a feature) and deploy with yarn deploy:trigger:prod.
  • Add a cron: drop a YAML in .github/workflows/ and an HTTP handler in apps/web/pages/api/cron/.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Webhooks and Tasker – Cal.com wiki | Factory