Visual drag-and-drop workflow automation built on xyflow. Create flows that connect triggers, conditions, and actions into automated pipelines.
The Flow Engine lets workspace admins build multi-step automations without code. Flows are stored as xyflow graph definitions (nodes + edges) and executed server-side by the flow-engine edge function.
Access: /admin/flows
Edge Functions:
flow-engine — Executes and tests flowsflow-scheduler-cron — Runs scheduled flows on cron intervalsflow-webhook — Triggers flows from external webhooksAdmin builds flow (drag-and-drop xyflow canvas)
↓
Flow saved to DB (flows table — nodes + edges JSON)
↓
Triggered by: cron schedule | incoming webhook | manual | event emission
↓
flow-engine edge function walks the graph:
- Resolves {{template}} variables from execution context
- Evaluates condition nodes (branches to true/false/case_N)
- Executes action nodes (SMS, email, HTTP, notification, etc.)
↓
Execution log written to flow_runs table
Define when a flow starts. One trigger node per flow.
| Trigger Type | Description |
|---|---|
manual |
Triggered via UI or API call |
cron |
Runs on a schedule (managed by flow-scheduler-cron) |
webhook |
Triggered by incoming webhook POST to flow-webhook |
event |
Fires on platform events (product created, quote submitted, etc.) |
Branch the flow based on data values.
| Condition Type | Description |
|---|---|
if_else |
Evaluates field vs value → true / false branches |
switch |
Matches field against N cases → case_0, case_1, … branches |
filter |
Evaluates multiple conditions with AND / OR logic |
delay |
Pauses execution for a duration (capped at 30s in edge function) |
Supported Operators for if_else:
| Operator | Meaning |
|---|---|
equals |
Exact match |
not_equals |
Not equal |
contains |
String contains substring |
not_contains |
String does not contain |
starts_with |
String prefix |
ends_with |
String suffix |
gt / gte |
Greater than / greater than or equal |
lt / lte |
Less than / less than or equal |
is_empty |
Empty string, undefined, or null |
is_not_empty |
Non-empty value |
Perform side effects. Templated values like {{trigger.data.user_email}} are resolved at runtime.
| Action Type | What it does | Cost |
|---|---|---|
send_sms |
Sends SMS via messaging-api |
Twilio per-message |
send_email |
Sends email via email-api |
SES per-message |
http_request |
Makes outbound HTTP call (GET/POST/PUT/DELETE) | None |
create_notification |
Inserts record into notifications table |
None |
send_quote |
Generates and sends quote PDF via generate-quote-pdf |
Included |
Action configs support {{path.to.value}} syntax. The context is built from execution data:
{{trigger.data.field}} — data from the trigger event
{{node_id.output.field}} — output of a previous node
Example: An SMS action with to: "{{trigger.data.customer_phone}}" resolves the phone number from whatever data triggered the flow.
execute-flowRuns the flow for real. All actions fire (SMS sent, emails sent, etc.).
POST /functions/v1/flow-engine
{
"action": "execute-flow",
"flow_id": "uuid",
"trigger_data": { "customer_phone": "+30...", "name": "Basil" }
}
test-flowDry-run. Templates are resolved but no external actions fire. Returns the resolved config for each node so you can verify the output.
POST /functions/v1/flow-engine
{
"action": "test-flow",
"flow_id": "uuid",
"trigger_data": { "customer_phone": "+30...", "name": "Basil" }
}
trigger-eventAuto-dispatch mode used by DB triggers and internal services. Finds all flows with trigger_type = 'event' and event_type matching the event, then runs them.
POST /functions/v1/flow-engine
{
"action": "trigger-event",
"event_type": "quote.submitted",
"event_data": { ... }
}
flow-scheduler-cron runs every minute (pg_cron). It:
trigger_type = 'cron' and enabled = trueflow-engine with action: 'execute-flow' for each due flowlast_run_at and next_run_at in the flows tableflow-webhook exposes a public endpoint for external systems to trigger flows:
POST /functions/v1/flow-webhook?flow_id=<uuid>
Content-Type: application/json
{ "any": "payload", "from": "external-system" }
The payload is passed as trigger.data in the execution context.
Security: Flows with webhook triggers can optionally require an HMAC signature header (X-Webhook-Signature).
| Table | Purpose |
|---|---|
flows |
Flow definitions (name, graph JSON, trigger config, enabled state) |
flow_runs |
Execution log (status, duration, node results, errors) |
Individual actions may consume credits (e.g., send_sms via Twilio, http_request to paid APIs). Credit deduction is handled by the individual invoked functions, not the flow engine itself.
flow_runs records the error and which node failed.delay nodes conservatively (capped at 30s).{{path}} returns the literal {{path}} string — execution continues.Last Updated: March 2026