Skip to main content
Workflows allow you to automate communications and actions based on booking events. Send email reminders, SMS notifications, WhatsApp messages, or trigger custom actions at specific times or events.

Overview

A workflow consists of:
  • Trigger: The event that starts the workflow (e.g., booking created, event starts soon)
  • Steps: Actions to take (e.g., send email, send SMS)
  • Timing: When to execute (immediately or at a specific time before/after the event)
  • Recipients: Who receives the notification (host, attendee, or custom recipients)
// From workflows types.ts:19
type Workflow = {
  id: number;
  name: string;
  trigger: WorkflowTriggerEvents;
  time: number | null;      // e.g., 24 for "24 hours"
  timeUnit: TimeUnit | null; // "HOUR", "DAY", "MINUTE"
  steps: WorkflowStep[];
};

Workflow Triggers

// From constants.ts:3
enum WorkflowTriggerEvents {
  BEFORE_EVENT                    // X time before event starts
  AFTER_EVENT                     // X time after event ends
  NEW_EVENT                       // Immediately when booked
  EVENT_CANCELLED                 // When booking is cancelled
  RESCHEDULE_EVENT               // When booking is rescheduled
  BOOKING_REQUESTED              // When approval is requested
  BOOKING_REJECTED               // When booking is rejected
  BOOKING_PAID                   // When payment is completed
  FORM_SUBMITTED                 // When routing form is submitted
  BOOKING_NO_SHOW_UPDATED        // When no-show status changes
}
Execute at a specific time relative to the event:
{
  trigger: "BEFORE_EVENT",
  time: 24,
  timeUnit: "HOUR"  // 24 hours before event
}
Time-based triggers (BEFORE_EVENT, AFTER_EVENT) require a time and timeUnit. Immediate triggers don’t.

Workflow Actions

// From constants.ts:20
enum WorkflowActions {
  EMAIL_HOST         // Send email to event host
  EMAIL_ATTENDEE     // Send email to attendee
  EMAIL_ADDRESS      // Send to custom email address
  SMS_ATTENDEE       // Send SMS to attendee
  SMS_NUMBER         // Send SMS to custom number
  WHATSAPP_ATTENDEE  // Send WhatsApp to attendee
  WHATSAPP_NUMBER    // Send WhatsApp to custom number
  CAL_AI_PHONE_CALL  // Trigger AI phone call
}

Email Actions

// Workflow step for email
type WorkflowStep = {
  action: "EMAIL_HOST" | "EMAIL_ATTENDEE" | "EMAIL_ADDRESS";
  sendTo: "[email protected]" | null;  // For EMAIL_ADDRESS only
  emailSubject: string;
  reminderBody: string | null;  // Email body
  template: WorkflowTemplates;
  includeCalendarEvent: boolean;  // Attach ICS file
};

EMAIL_HOST

Sends to the event host(s). No sendTo needed.

EMAIL_ATTENDEE

Sends to the booking attendee(s). No sendTo needed.

EMAIL_ADDRESS

Sends to a custom email address specified in sendTo.

SMS and WhatsApp Actions

{
  action: "SMS_ATTENDEE",
  reminderBody: "Your meeting is starting in 1 hour!",
  template: "REMINDER",
  numberRequired: true,            // Attendee must provide phone number
  numberVerificationPending: false // Verification status
}
SMS and WhatsApp actions require phone number verification. The first time a number is used, the sender must verify it.

Workflow Templates

// From constants.ts:33
enum WorkflowTemplates {
  CUSTOM      // Custom message
  REMINDER    // Default reminder template
  RATING      // Request feedback/rating
  CANCELLED   // Cancellation notification
  COMPLETED   // Event completed notification
  RESCHEDULED // Reschedule notification
}
Templates provide pre-filled content with dynamic variables.

Dynamic Variables

Use variables in your workflow messages:
// From constants.ts:57
[
  "event_name",              // Event type title
  "event_date",              // Event date
  "event_time",              // Event start time
  "event_end_time",          // Event end time
  "timezone",                // User's timezone
  "location",                // Meeting location
  "organizer_name",          // Host name
  "attendee_name",           // Attendee full name
  "attendee_first_name",     // Attendee first name
  "attendee_last_name",      // Attendee last name
  "attendee_email",          // Attendee email
  "additional_notes",        // Booking notes
  "meeting_url",             // Video meeting URL
  "cancel_url",              // Cancellation link
  "reschedule_url",          // Reschedule link
  "rating_url",              // Rating/feedback link
  "no_show_url",             // Mark as no-show link
  "attendee_timezone",       // Attendee's timezone
]

Using Variables

{
  emailSubject: "Reminder: {event_name} in 24 hours",
  reminderBody: `
    Hi {attendee_first_name},
    
    This is a reminder that you have "{event_name}" scheduled for:
    {event_date} at {event_time} ({timezone})
    
    Location: {location}
    Meeting URL: {meeting_url}
    
    Need to reschedule? {reschedule_url}
    
    See you soon!
    {organizer_name}
  `
}
Variables are automatically replaced with actual values when the workflow executes.

Creating a Workflow

1

Navigate to Workflows

Go to Settings → Workflows from your dashboard
2

Create New Workflow

Click “New Workflow” and give it a descriptive name
3

Select Trigger

Choose when the workflow should run (e.g., “Before Event”)
4

Set Timing

For time-based triggers, specify how long before/after (e.g., 24 hours)
5

Add Steps

Add one or more actions (email, SMS, etc.)
6

Configure Each Step

Set recipient, template, and message content
7

Assign to Event Types

Select which event types should use this workflow

Workflow Schema

// From schema.prisma:1556
model Workflow {
  id          Int                   @id
  name        String
  userId      Int?                  // Owner (if personal)
  teamId      Int?                  // Owner (if team)
  trigger     WorkflowTriggerEvents
  time        Int?                  // Time value
  timeUnit    TimeUnit?             // DAY, HOUR, MINUTE
  steps       WorkflowStep[]
  
  // Activation
  activeOn             WorkflowsOnEventTypes[]    // Event types using this
  activeOnTeams        WorkflowsOnTeams[]         // Teams using this
  activeOnRoutingForms WorkflowsOnRoutingForms[]  // Routing forms using this
  isActiveOnAll        Boolean @default(false)    // Apply to all event types
}

model WorkflowStep {
  id            Int      @id
  stepNumber    Int      // Order of execution
  workflowId    Int
  action        WorkflowActions
  sendTo        String?  // Custom recipient
  emailSubject  String?
  reminderBody  String?
  template      WorkflowTemplates
  
  // Phone/SMS specific
  numberRequired            Boolean?
  numberVerificationPending Boolean @default(true)
  sender                    String?  // SMS sender ID
  
  // Options
  includeCalendarEvent Boolean @default(false)
  autoTranslateEnabled Boolean @default(false)
  sourceLocale         String?
}

Assigning Workflows

To Event Types

// From schema.prisma:1598
model WorkflowsOnEventTypes {
  workflowId  Int
  eventTypeId Int
  workflow    Workflow
  eventType   EventType
}
Assign workflows to specific event types from the workflow editor or event type settings.

To Teams

// From schema.prisma:1622
model WorkflowsOnTeams {
  workflowId Int
  teamId     Int
  workflow   Workflow
  team       Team
}
Team workflows apply to all team event types.

To Routing Forms

// From schema.prisma:1610
model WorkflowsOnRoutingForms {
  workflowId    Int
  routingFormId String
  workflow      Workflow
  routingForm   App_RoutingForms_Form
}
Workflows can trigger when routing forms are submitted.

Workflow Reminders

// From schema.prisma:1652
model WorkflowReminder {
  id              Int      @id
  bookingUid      String
  booking         Booking
  workflowStepId  Int
  workflowStep    WorkflowStep
  method          String   // EMAIL, SMS, WHATSAPP
  scheduled       Boolean  // Has been scheduled
  scheduledDate   DateTime // When to send
  referenceId     String?  // External reference (e.g., email ID)
}
When a booking is created, workflow reminders are scheduled based on the trigger time.
Reminders are stored in the database and executed by a background job at the scheduled time.

Common Workflow Examples

24-Hour Reminder

{
  name: "24 Hour Reminder",
  trigger: "BEFORE_EVENT",
  time: 24,
  timeUnit: "HOUR",
  steps: [
    {
      action: "EMAIL_ATTENDEE",
      template: "REMINDER",
      emailSubject: "Reminder: {event_name} tomorrow",
      reminderBody: `Hi {attendee_first_name},\n\nYour meeting "{event_name}" is scheduled for tomorrow at {event_time}.\n\nJoin here: {meeting_url}`,
      includeCalendarEvent: true
    }
  ]
}

Booking Confirmation

{
  name: "Booking Confirmed",
  trigger: "NEW_EVENT",
  time: null,
  timeUnit: null,
  steps: [
    {
      action: "EMAIL_ATTENDEE",
      template: "CUSTOM",
      emailSubject: "Booking Confirmed: {event_name}",
      reminderBody: `Thank you for booking!\n\nDetails:\n- Event: {event_name}\n- Date: {event_date}\n- Time: {event_time}\n- Location: {location}\n\nNeed to reschedule? {reschedule_url}`,
      includeCalendarEvent: true
    },
    {
      action: "EMAIL_HOST",
      template: "CUSTOM",
      emailSubject: "New Booking: {event_name}",
      reminderBody: `New booking from {attendee_name}\n\nScheduled for {event_date} at {event_time}`
    }
  ]
}

Follow-Up After Meeting

{
  name: "Post-Meeting Follow-Up",
  trigger: "AFTER_EVENT",
  time: 1,
  timeUnit: "HOUR",
  steps: [
    {
      action: "EMAIL_ATTENDEE",
      template: "RATING",
      emailSubject: "How was your meeting?",
      reminderBody: `Hi {attendee_first_name},\n\nThank you for meeting with us!\n\nWe'd love your feedback: {rating_url}`
    }
  ]
}

SMS Reminder

{
  name: "SMS 1 Hour Before",
  trigger: "BEFORE_EVENT",
  time: 1,
  timeUnit: "HOUR",
  steps: [
    {
      action: "SMS_ATTENDEE",
      template: "REMINDER",
      reminderBody: "Reminder: {event_name} starts in 1 hour. Join: {meeting_url}",
      numberRequired: true
    }
  ]
}

Multi-Channel Reminder

{
  name: "Multi-Channel Reminder",
  trigger: "BEFORE_EVENT",
  time: 2,
  timeUnit: "HOUR",
  steps: [
    {
      action: "EMAIL_ATTENDEE",
      template: "REMINDER",
      emailSubject: "Starting soon: {event_name}",
      reminderBody: "Your meeting starts in 2 hours."
    },
    {
      action: "SMS_ATTENDEE",
      template: "REMINDER",
      reminderBody: "{event_name} in 2 hours. Join: {meeting_url}"
    },
    {
      action: "WHATSAPP_ATTENDEE",
      template: "REMINDER",
      reminderBody: "Reminder: {event_name} at {event_time}"
    }
  ]
}

Best Practices

Don't Over-Notify

Too many reminders can annoy attendees. One 24-hour reminder is usually sufficient.

Use Clear Subject Lines

Make email subjects descriptive with dynamic variables

Include Action Links

Always provide reschedule/cancel links in reminders

Test Your Workflows

Create a test booking to verify workflow messages before going live

Advanced Features

Auto-Translation

// From WorkflowStep schema.prisma:1549-1550
{
  autoTranslateEnabled: true,
  sourceLocale: "en"  // Translate from English to attendee's locale
}

Time Unit Options

// From constants.ts:31
enum TimeUnit {
  MINUTE  // For very short reminders
  HOUR    // Most common
  DAY     // For advance reminders
}

Workflow Types

enum WorkflowType {
  EVENT_TYPE    // Standard booking workflows
  ROUTING_FORM  // Routing form workflows
}

Troubleshooting

Workflow Not Triggering

  1. Check activation: Verify workflow is assigned to the event type
  2. Review trigger conditions: Ensure booking meets trigger criteria
  3. Check timing: For time-based triggers, verify the scheduled time
  4. Verify workflow is active: Workflows can be disabled

Reminders Not Sent

  1. Check WorkflowReminder records: Verify reminders were created
  2. Review scheduled date: Ensure it’s in the future
  3. Check email deliverability: Emails might be in spam
  4. Verify phone numbers: For SMS, ensure number is verified

Build docs developers (and LLMs) love