Workflow Builder
Design, configure, and deploy event-driven automations with the visual canvas editor. Connect triggers to actions using a drag-and-drop interface powered by React Flow.
Creating a Workflow
Follow these steps to create and activate your first workflow:
- Navigate to Workflows: From the main dashboard, click
Workflowsin the sidebar navigation. - Click "New Workflow": Click the
+ Newbutton in the top-right corner of the Workflows page. - Name your workflow: Enter a descriptive name (e.g., "Order Confirmation via WhatsApp") and optionally add a description.
- Set the trigger event: Select the event that will start your workflow from the trigger configuration panel. Use the
category.actionformat. - Design on the canvas: Drag nodes from the palette, connect them with edges, and configure each node by clicking on it.
- Activate: Toggle the workflow status to
Active. The workflow will now listen for its trigger event and execute automatically.
Pro Tip
Start from a template to save time. Clone any of the 42 pre-built templates and customize to your needs.
Trigger Events
Trigger events are the entry points that start workflow executions. They follow a category.action naming convention. When an event is fired in your system, all active workflows listening for that event will execute.
| Category | Events | Description |
|---|---|---|
| Lead | lead.created |
Fired when a new lead is captured in the CRM |
| Order | order.created, order.shipped, order.delivered |
E-commerce order lifecycle events |
| Cart | cart.abandoned |
Triggered after configurable inactivity period |
| Payment | payment.received |
Confirmed payment from any gateway |
| Invoice | invoice.created, invoice.overdue |
Billing lifecycle events |
| Ticket | ticket.created, ticket.resolved |
Support ticket state changes |
| Shipment | shipment.status_changed |
Courier tracking updates via webhook |
whatsapp.message_received |
Incoming WhatsApp message from customer | |
| Webhook | webhook.received |
Generic external webhook payload |
| Polling | trigger.polling |
Scheduled external API polling |
| HR | employee.hired |
New employee onboarding trigger |
| System | error.critical |
Critical application error detected |
| Scheduled | scheduled.* |
Cron-based scheduled triggers (wildcard) |
The Visual Canvas
The workflow canvas is a React Flow-based editor (@xyflow/react v12) that provides a visual, drag-and-drop interface for building automation logic.
Drag Nodes from the Palette
The left-side node palette contains all available node types organized by category:
- Flow: Trigger, End, Branch, Delay, Loop, Transform
- Action: HTTP Request, Log Message, Send Notification
- Integration: Send Email, Send WhatsApp, WhatsApp Template, Create Shipment, Get Tracking
- AI: AI Prompt
Drag any node from the palette onto the canvas to add it to your workflow.
Connect Nodes with Edges
Click and drag from a node's output handle (bottom) to another node's input handle (top) to create an edge. Edges define the execution flow — data passes from one node to the next along these connections.
Configure Nodes
Click on any node to open its configuration panel on the right side. Each node type has specific configuration fields (see Node Reference for details).
Canvas Features
- Auto-save: Changes are saved automatically as you edit. No manual save required.
- Undo / Redo: Use
Ctrl+Z/Ctrl+Shift+Z(orCmdon macOS) to undo and redo changes. - Zoom & Pan: Scroll to zoom, drag the background to pan.
- Multi-select: Hold
Shiftand drag to select multiple nodes at once. - Minimap: A minimap in the bottom-right corner provides an overview of large workflows.
Variable Interpolation
Use the {{"{{}}"}} syntax to inject dynamic data into node configurations. Variables are resolved at runtime with data from the trigger payload and previous node outputs.
Trigger Data
{{trigger.field}} — Access any field from the trigger event payload
{{trigger.customer.name}} — Dot notation for nested objects
{{trigger.items[0].sku}} — Array access with index
Previous Node Output
{{nodes.nodeId.field}} — Access the output of a specific node by its ID
{{nodes.http_request_1.body}} — e.g., HTTP response body
{{nodes.ai_prompt_1.response}} — e.g., AI-generated text
Loop Context
{{loop.item}} — The current item in the iteration
{{loop.index}} — Zero-based index of the current iteration
{{loop.count}} — Total number of items in the array
Transform Node & Pipes
The action.transform node allows you to reshape data between steps using pipe syntax for inline transformations.
Pipe Syntax
Pipes are applied using the | character after a variable reference. Multiple pipes can be chained:
{{trigger.name | upper}} — Convert to UPPERCASE
{{trigger.name | lower}} — Convert to lowercase
{{trigger.amount | default:0}} — Use 0 if value is null/undefined
{{trigger.date | date:Y-m-d}} — Format date as 2026-07-18
{{trigger.email | lower | trim}} — Chain multiple pipes
Transform Configuration
The transform node uses an assignments array where each entry defines a key-value mapping:
{
"assignments": [
{ "key": "full_name", "value": "{{trigger.first_name | upper}} {{trigger.last_name | upper}}" },
{ "key": "total", "value": "{{trigger.amount | default:0}}" },
{ "key": "formatted_date", "value": "{{trigger.created_at | date:Y-m-d}}" }
]
}
Error Handling
Each node supports an on_failure configuration that determines what happens when the node encounters an error during execution.
| Strategy | Behavior |
|---|---|
on_failure: continue |
(Default) Logs the error and continues execution to the next node. The workflow completes with partial status. |
on_failure: abort |
Stops the entire workflow execution immediately. The workflow is marked as failed. |
Execution Statuses
| Status | Description |
|---|---|
pending | Execution has been queued but not yet started |
running | Execution is currently in progress |
success | All nodes completed without errors |
partial | Completed with one or more node failures (continue mode) |
failed | Execution was aborted due to a critical error |
waiting | Execution is paused (e.g., at a Delay node) and will resume later |
Execution History
Every workflow execution is logged with full detail, allowing you to inspect, debug, and retry automations.
Viewing Executions
- Navigate to the Executions page from the main sidebar to view all executions across workflows.
- Alternatively, open a specific workflow and click the Executions tab to see only that workflow's runs.
Filtering
- By workflow: Select a specific workflow from the dropdown filter.
- By status: Filter by pending, running, success, partial, failed, or waiting.
- By date: Use the date range picker to narrow results to a specific timeframe.
Execution Detail View
Click any execution to open the step-by-step detail view:
- See each node that was executed in order
- Inspect the input data received by each node
- Inspect the output data produced by each node
- View error messages and stack traces for failed nodes
- See timing information (duration per node)
Retrying Failed Executions
Failed executions can be retried programmatically via the REST API:
POST /api/v1/executions/{execution_id}/retry
Authorization: Bearer {api_key}
Scheduling
Workflows can be triggered on a schedule using cron expressions, or by polling external APIs at configurable intervals.
Cron Expressions
Set a cron expression in the trigger configuration to run workflows on a schedule:
0 8 * * * — Every day at 8:00 AM
0 9 * * 1 — Every Monday at 9:00 AM
*/15 * * * * — Every 15 minutes
0 0 1 * * — First day of every month at midnight
0 */2 * * * — Every 2 hours
How Scheduling Works
The workflow:schedule Artisan command runs every minute via the Laravel scheduler. It checks all active scheduled workflows and fires their trigger events when their cron expression matches the current time.
Polling Triggers
Polling triggers (trigger.polling) allow workflows to periodically check an external API for new data. Configure:
- URL: The external API endpoint to poll
- Interval: How often to poll (in seconds, minimum 60)
- Method: HTTP method (typically GET)
- Headers: Authentication headers for the external API
The polling engine deduplicates results to avoid processing the same data twice.