# Configure Workflow Triggers (/how-to/workflows/configure-workflow-triggers)



This guide is a comprehensive reference for every component you can use when building a workflow. It covers trigger events, condition types and operators, and all available actions with their configuration options.

Trigger events [#trigger-events]

The event node defines when a workflow fires. Select one of the following event types:

| Event type            | Label               | Fires when                                                                                                                         |
| --------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `booking_created`     | Booking Created     | A new booking is submitted (any status except Draft).                                                                              |
| `booking_confirmed`   | Booking Confirmed   | A booking's status changes to Confirmed. This is derived from `booking_status_changed` events where the new status is "Confirmed". |
| `booking_canceled`    | Booking Canceled    | A booking is canceled by the customer, staff, or system.                                                                           |
| `booking_rescheduled` | Booking Rescheduled | A booking's date or time is changed.                                                                                               |
| `payment_received`    | Payment Received    | A payment is successfully processed for a booking.                                                                                 |
| `payment_failed`      | Payment Failed      | A payment attempt fails.                                                                                                           |
| `customer_registered` | Customer Registered | A new customer record is created.                                                                                                  |
| `reminder_scheduled`  | Reminder Scheduled  | A reminder event is generated by the system.                                                                                       |

Event data available in context [#event-data-available-in-context]

Each event type populates a set of variables that conditions and actions can reference:

**Booking events** (`booking_created`, `booking_confirmed`, `booking_canceled`, `booking_rescheduled`):

| Variable      | Type     | Description                              |
| ------------- | -------- | ---------------------------------------- |
| `bookingId`   | GUID     | The unique identifier of the booking.    |
| `locationId`  | GUID     | The location where the booking was made. |
| `customerId`  | GUID     | The customer who made the booking.       |
| `activityId`  | GUID     | The activity that was booked.            |
| `totalAmount` | decimal  | The grand total of the booking.          |
| `startTime`   | datetime | The booking start time in UTC.           |
| `endTime`     | datetime | The booking end time in UTC.             |
| `status`      | string   | The current booking status.              |

**Status change events** (`booking_confirmed`, `booking_canceled`) also include:

| Variable    | Type   | Description                                                     |
| ----------- | ------ | --------------------------------------------------------------- |
| `oldStatus` | string | The previous booking status.                                    |
| `newStatus` | string | The new booking status.                                         |
| `changedBy` | string | Who triggered the change (e.g., "customer", "staff", "system"). |
| `reason`    | string | Optional reason for the change.                                 |

**Rescheduled events** also include:

| Variable        | Type     | Description                                  |
| --------------- | -------- | -------------------------------------------- |
| `oldStartTime`  | datetime | The original start time before rescheduling. |
| `newStartTime`  | datetime | The new start time after rescheduling.       |
| `oldEndTime`    | datetime | The original end time.                       |
| `newEndTime`    | datetime | The new end time.                            |
| `rescheduledBy` | string   | Who initiated the reschedule.                |

***

Condition types [#condition-types]

Condition nodes evaluate a property and branch the workflow based on the result. The following condition types are available:

Booking conditions [#booking-conditions]

| Condition type            | Label              | Value returned                                                        |
| ------------------------- | ------------------ | --------------------------------------------------------------------- |
| `booking_status`          | Booking Status     | The current status string (e.g., "Pending", "Confirmed", "Canceled"). |
| `booking_value`           | Booking Value      | The `GrandTotal` as a decimal.                                        |
| `booking_date`            | Booking Date       | The booking date.                                                     |
| `booking_time`            | Booking Time       | The booking start time.                                               |
| `booking_start_time`      | Booking Start Time | The start time of the booking.                                        |
| `booking_end_time`        | Booking End Time   | The end time of the booking.                                          |
| `booking_equipment_count` | Equipment Count    | Number of equipment items on the booking.                             |
| `booking_has_addons`      | Has Add-Ons        | `true` if any equipment on the booking has add-ons selected.          |

Customer conditions [#customer-conditions]

| Condition type    | Label           | Value returned                                             |
| ----------------- | --------------- | ---------------------------------------------------------- |
| `customer_type`   | Customer Type   | Currently returns `"individual"`.                          |
| `customer_email`  | Customer Email  | The customer's primary email address.                      |
| `customer_phone`  | Customer Phone  | The customer's phone number.                               |
| `customer_name`   | Customer Name   | The customer's full name.                                  |
| `customer_is_new` | Is New Customer | `true` if the customer was created within the last 7 days. |
| `customer_count`  | Customer Count  | The calculated guest count for the booking.                |

Equipment conditions [#equipment-conditions]

| Condition type   | Label          | Value returned                                            |
| ---------------- | -------------- | --------------------------------------------------------- |
| `equipment_type` | Equipment Type | A comma-separated list of equipment names on the booking. |

Activity conditions [#activity-conditions]

| Condition type                 | Label               | Value returned                                                                         |
| ------------------------------ | ------------------- | -------------------------------------------------------------------------------------- |
| `activity_name`                | Activity Name       | The name of the booked activity.                                                       |
| `activity_type`                | Activity Type       | One of: `equipment_rental`, `tour`, `dynamic_duration_equipment_rental`, or `unknown`. |
| `activity_is_equipment_rental` | Is Equipment Rental | `true` if the activity type is an equipment rental or dynamic-duration rental.         |

Location conditions [#location-conditions]

| Condition type      | Label             | Value returned                                           |
| ------------------- | ----------------- | -------------------------------------------------------- |
| `location_name`     | Location Name     | The location's display name.                             |
| `location_timezone` | Location Timezone | The IANA timezone identifier (e.g., `America/New_York`). |

Time-based conditions [#time-based-conditions]

These use the **location's timezone**, not the server's timezone:

| Condition type | Label       | Value returned                                      |
| -------------- | ----------- | --------------------------------------------------- |
| `time_of_day`  | Time of Day | The current hour (0-23) in the location's timezone. |
| `day_of_week`  | Day of Week | The day name (e.g., `Monday`, `Saturday`).          |
| `is_weekend`   | Is Weekend  | `true` if today is Saturday or Sunday.              |

Event data conditions [#event-data-conditions]

Any variable name not matching the built-in types above is looked up in the event data dictionary. This lets you write conditions against custom event properties.

***

Condition operators [#condition-operators]

Every condition uses an operator to compare the actual value against your configured value:

| Operator                | Label                 | Behavior                                   |
| ----------------------- | --------------------- | ------------------------------------------ |
| `equals`                | Equals                | Case-insensitive string equality.          |
| `not_equals`            | Does Not Equal        | Case-insensitive string inequality.        |
| `contains`              | Contains              | Case-insensitive substring match.          |
| `not_contains`          | Does Not Contain      | Inverse of contains.                       |
| `greater_than`          | Greater Than          | Numeric or date comparison.                |
| `less_than`             | Less Than             | Numeric or date comparison.                |
| `greater_than_or_equal` | Greater Than or Equal | Numeric or date comparison.                |
| `less_than_or_equal`    | Less Than or Equal    | Numeric or date comparison.                |
| `starts_with`           | Starts With           | String prefix match.                       |
| `ends_with`             | Ends With             | String suffix match.                       |
| `is_empty`              | Is Empty              | True if the value is null or empty string. |
| `is_not_empty`          | Is Not Empty          | True if the value is not null/empty.       |

Numeric operators parse both sides as decimals first, then try datetime parsing, and fall back to case-insensitive string comparison.

***

Action types [#action-types]

Action nodes perform work. Each action type has its own configuration options.

Send Email (`send_email`) [#send-email-send_email]

Sends a custom or template-based email.

| Config field | Required    | Description                                                                                                                  |
| ------------ | ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `to`         | Yes         | Recipient email. Supports template variables like `{{customer.email}}`.                                                      |
| `subject`    | Conditional | Email subject line. Required if not using a predefined template.                                                             |
| `body`       | Conditional | HTML email body. Required if not using a predefined template.                                                                |
| `template`   | No          | A predefined template name: `booking_confirmation`, `booking_rescheduled`, `refund_notification`, or `booking_status_alert`. |
| `templateId` | No          | The UUID of a custom communication template created in the Marketing section.                                                |

When a `templateId` is provided, the template's subject and body are loaded from the database and variable replacement is applied. When a predefined `template` is used, the system generates a fully branded email using booking data.

Send SMS (`send_sms`) [#send-sms-send_sms]

Sends an SMS message via Twilio.

| Config field | Required    | Description                                                                           |
| ------------ | ----------- | ------------------------------------------------------------------------------------- |
| `to`         | Yes         | Recipient phone number. Supports template variables.                                  |
| `message`    | Conditional | The SMS body text. Required if `templateId` is not set.                               |
| `templateId` | No          | UUID of an SMS communication template.                                                |
| `fromNumber` | No          | Override the sender phone number. Defaults to the company's configured Twilio number. |

Send Template (`send_template`) [#send-template-send_template]

Sends a communication template (email, SMS, or both) with automatic recipient resolution.

| Config field      | Required    | Description                                                                                                                                                |
| ----------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `templateId`      | Yes         | UUID of the communication template to send.                                                                                                                |
| `recipientType`   | Yes         | One of: `customer` (uses the booking's customer email/phone), `facilitator` (uses the location contact), `admin` (uses the location contact), or `custom`. |
| `customRecipient` | Conditional | Required when `recipientType` is `custom`. An email address or phone number. Supports template variables.                                                  |

The template type (email, SMS, or both) is determined by the template's configuration in the database. For SMS, phone numbers are automatically formatted with country codes.

Send Survey Email (`send_survey_email`) [#send-survey-email-send_survey_email]

Sends a post-booking survey email with a unique, time-limited survey link.

This action requires no manual configuration fields -- it automatically:

* Loads the location's survey settings and default survey.
* Generates a cryptographically secure, single-use survey token.
* Builds a branded email using the survey settings' subject and body with variable replacement.
* Includes links to Yelp, Google, and TripAdvisor review pages if configured.

Update Booking (`update_booking`) [#update-booking-update_booking]

Modifies a field on the triggering booking.

| Config field | Required | Description                                                |
| ------------ | -------- | ---------------------------------------------------------- |
| `field`      | Yes      | The booking field to update. Currently supports: `status`. |
| `value`      | Yes      | The new value to set (e.g., `Confirmed`, `Canceled`).      |

Status changes are processed through the standard booking status change pipeline, which validates the transition and publishes follow-up events. The workflow system is marked as the change source to prevent re-triggering.

Add Booking Note (`add_booking_note`) [#add-booking-note-add_booking_note]

Adds an internal note to the booking's timeline.

| Config field | Required | Description                                                                                                |
| ------------ | -------- | ---------------------------------------------------------------------------------------------------------- |
| `note`       | Yes      | The note text. Supports `{{variable}}` placeholders. The note is prefixed with `[Workflow]` automatically. |

Create Task (`create_task`) [#create-task-create_task]

Creates a task for follow-up. (This action is currently a placeholder -- the task management system is under development.)

| Config field  | Required | Description                                                   |
| ------------- | -------- | ------------------------------------------------------------- |
| `title`       | Yes      | Task title. Supports variable replacement.                    |
| `description` | No       | Task description.                                             |
| `dueInHours`  | No       | Hours until the task is due. Defaults to 24.                  |
| `priority`    | No       | Task priority: `low`, `normal`, `high`. Defaults to `normal`. |

Send Webhook (`webhook`) [#send-webhook-webhook]

Sends an HTTP request to an external URL.

| Config field | Required | Description                                                                                           |
| ------------ | -------- | ----------------------------------------------------------------------------------------------------- |
| `url`        | Yes      | The target URL. Supports `{{variable}}` placeholders.                                                 |
| `method`     | No       | HTTP method: `GET`, `POST`, `PUT`, `DELETE`, or `PATCH`. Defaults to `POST`.                          |
| `headers`    | No       | A dictionary of HTTP headers. Values support variable replacement.                                    |
| `body`       | No       | The request body (for POST/PUT/PATCH). Use `{{eventData}}` to include the full event payload as JSON. |

Webhook requests have a 30-second timeout. The URL is validated against SSRF protections -- requests to localhost, private IP ranges (10.x, 172.16.x, 192.168.x), link-local addresses, and cloud metadata endpoints are blocked.

Add Tag (`add_tag`) [#add-tag-add_tag]

Tags the booking or customer with a label. (Under development.)

| Config field | Required | Description              |
| ------------ | -------- | ------------------------ |
| `tag`        | Yes      | The tag string to apply. |

Remove Tag (`remove_tag`) [#remove-tag-remove_tag]

Removes a tag from the booking or customer. (Under development.)

| Config field | Required | Description               |
| ------------ | -------- | ------------------------- |
| `tag`        | Yes      | The tag string to remove. |

Assign Facilitator (`assign_facilitator`) [#assign-facilitator-assign_facilitator]

Automatically assigns a facilitator (guide, instructor, operator) to the booking.

| Config field    | Required | Description                                     |
| --------------- | -------- | ----------------------------------------------- |
| `facilitatorId` | Yes      | The UUID of the location facilitator to assign. |

The action checks for duplicate assignments and verifies that the facilitator belongs to the workflow's location before creating the assignment.

Wait / Delay (`wait` or `delay`) [#wait--delay-wait-or-delay]

Pauses the workflow for a specified duration or until a time relative to the booking.

**Fixed delay:**

| Config field | Required | Description                                        |
| ------------ | -------- | -------------------------------------------------- |
| `delayType`  | No       | Set to `fixed` (default) for a fixed duration.     |
| `duration`   | Yes      | The number of time units to wait.                  |
| `unit`       | Yes      | The time unit: `minute`, `hour`, `day`, or `week`. |

**Relative delay (time-anchored to booking):**

| Config field      | Required | Description                                                       |
| ----------------- | -------- | ----------------------------------------------------------------- |
| `delayType`       | Yes      | Set to `relative`.                                                |
| `referencePoint`  | Yes      | The anchor: `booking_start`, `booking_end`, or `booking_created`. |
| `offsetHours`     | Yes      | Number of hours offset from the reference point.                  |
| `offsetDirection` | Yes      | `before` or `after` the reference point.                          |

Relative delays are booking-aware: if a booking is rescheduled after a relative delay is scheduled, the system automatically recalculates the delay time on the next job execution. If the recalculated time is in the past, the workflow resumes immediately.

Delays are implemented using Hangfire scheduled jobs. The workflow execution is paused and a resumption job is enqueued at the calculated time.

***

Template variables [#template-variables]

Actions that support template variables use the `{{variableName}}` syntax. Available variables include:

* All event data fields (e.g., `{{bookingId}}`, `{{totalAmount}}`, `{{status}}`).
* Customer fields (via `TemplateVariableReplacer`): `{{customer.name}}`, `{{customer.email}}`, etc.
* Booking fields: `{{booking.confirmationCode}}`, `{{booking.status}}`, etc.
* Activity and location fields from the template context.
* The special `{{eventData}}` placeholder (webhook action only) serializes the entire event payload as JSON.
