Logic & Flow Nodes
Logic nodes control how the conversation flows -- branching based on conditions, looping over data, composing sub-flows, managing variables, and introducing delays. They do not produce visible messages on their own but determine which path the conversation takes.
Condition
Type: condition
Branches the flow into two paths based on a variable comparison. The node evaluates the condition and routes to either the true or false output.
Properties
| Property | Type | Description |
|---|---|---|
variable | string | The variable name to evaluate |
operator | equals | contains | greater | less | isEmpty | Comparison operator |
value | string | The value to compare against (not used with isEmpty) |
trueNodeId | string | Node to route to when the condition is true |
falseNodeId | string | Node to route to when the condition is false |
Operators
- equals -- Exact string or numeric match.
- contains -- Checks if the variable value includes the comparison string (case-insensitive).
- greater / less -- Numeric comparison. Values are parsed as numbers.
- isEmpty -- True when the variable is undefined, null, or an empty string. Ignores the
valueproperty.
Use cases
- Check if the user provided an email before sending a confirmation
- Route VIP customers (score > 100) to a priority path
- Skip a step when a variable is already populated
Set Variable
Type: set_variable
Stores a value in a flow variable. The variable becomes available to all downstream nodes.
Properties
| Property | Type | Description |
|---|---|---|
variable | string | The variable name to set |
source | static | from_last_message | ai_extract | expression | Where the value comes from |
value | string | The static value (used when source is static) |
expression | string | A JavaScript expression (used when source is expression) |
Sources
- static -- Sets the variable to a fixed value. Useful for flags, counters, or default values.
- from_last_message -- Captures the user's most recent message text as the variable value.
- ai_extract -- Uses the LLM to extract a specific piece of information from the conversation history (e.g., "extract the user's budget" or "extract the product name they mentioned").
- expression -- Evaluates a JavaScript expression with access to all current variables. For example,
variables.price * variables.quantityorvariables.name.toUpperCase().
Use cases
- Store a computed total: source
expression, expressionvariables.price * variables.quantity - Capture raw user input for later processing: source
from_last_message - Set a flag after a step completes: source
static, valuetrue
Loop
Type: loop
Iterates over an array variable or catalog records, executing the loop body once per item. The current item is available as a variable inside the loop body.
Properties
| Property | Type | Description |
|---|---|---|
loopSource | variable | catalog | Whether to iterate over a variable array or catalog records |
loopVariableName | string | Variable name for the current item on each iteration |
loopCatalogId | string | The Data Catalog to iterate over (when source is catalog) |
loopFilterField | string | Catalog field to filter on |
loopFilterOperator | equals | not_equals | greater_than | less_than | contains | Filter comparison operator |
loopFilterValue | string | Value to filter against |
loopLimit | number | Maximum records to fetch from catalog |
loopMaxIterations | number | Hard cap on iterations (safety limit) |
loopContinueOnError | boolean | When true, errors in one iteration do not stop the loop |
Outputs
The Loop node has two output handles:
- Each Item -- Connects to the first node in the loop body. Executes once per item.
- Complete -- Connects to the node that runs after all iterations finish.
Catalog filters
When loopSource is catalog, you can filter records before iterating. The filter applies server-side, so only matching records are fetched. Combine with loopLimit to cap the result set.
Use cases
- Send a personalized message for each product in a recommendation list
- Process each row in a data table and call an API per record
- Iterate over survey responses and classify each one
Loop End
Type: loop_end
Marks the end of a loop body. Every Loop node needs a corresponding Loop End node to define where the loop body ends and iteration continues.
Properties
| Property | Type | Description |
|---|---|---|
loopNodeId | string | The Loop node this end marker belongs to |
breakConditionVariable | string | Variable to evaluate for an early exit |
breakConditionOperator | equals | not_empty | is_true | How to evaluate the break condition |
breakConditionValue | string | Value to compare against (used with equals) |
Break conditions
By default, the loop runs through every item. To exit early, configure a break condition:
- equals -- Break when the variable matches the specified value.
- not_empty -- Break when the variable has any non-empty value.
- is_true -- Break when the variable is truthy.
When the break condition is met, the loop stops and execution continues from the Loop node's Complete output.
Use cases
- Stop iterating once a matching product is found
- Exit a retry loop when an API call succeeds
- Limit processing to the first item that meets a threshold
Sub-Flow
Type: sub_flow
Routes execution to another flow on the same agent. Sub-flows let you break complex journeys into modular, reusable pieces.
Properties
| Property | Type | Description |
|---|---|---|
subFlowId | string | ID of the target flow |
subFlowName | string | Display name of the target flow (for readability in the editor) |
shareVariables | boolean | When true, the sub-flow has full read/write access to the parent's variables |
inputMapping | object | Maps parent variables to sub-flow input variables |
outputMapping | object | Maps sub-flow output variables back to parent variables |
Variable passing
There are two approaches:
- Explicit mappings -- Use
inputMappingandoutputMappingto pass specific variables in and out. This is the safer option because it makes data flow explicit and prevents unintended side effects. - Share variables -- Enable
shareVariablesto give the sub-flow direct access to the parent's full variable scope. Changes made by the sub-flow are visible in the parent immediately. Use this when the sub-flow needs broad context and you want to avoid mapping many variables individually.
When both are configured, explicit mappings take precedence for the mapped variables, and shareVariables provides access to everything else.
Use cases
- A main greeting flow that routes to "Product Recommendations", "Support", or "FAQ" sub-flows based on user intent
- A reusable "Collect Shipping Address" sub-flow shared across multiple checkout journeys
- A modular lead qualification flow that can be dropped into any sales agent
Converge
Type: converge
Merges multiple branches back into a single path. Place a Converge node after a Condition or AI Categorizer to rejoin divergent paths before continuing the flow.
Properties
| Property | Type | Description |
|---|---|---|
awaitAll | boolean | When true, waits for all incoming branches to complete before continuing |
Behavior
Without a Converge node, each branch continues independently until it reaches a terminal node. A Converge node collects branches and funnels them into a single downstream path.
When awaitAll is false (default), execution continues as soon as the first branch reaches the Converge node. When awaitAll is true, the node waits until every connected branch has completed before proceeding.
Use cases
- Rejoin true/false branches after a Condition so both paths lead to the same follow-up message
- Merge categorized paths back together before a shared closing sequence
- Synchronize parallel branches that must all complete before the next step
Delay
Type: delay
Pauses the conversation for a specified duration. Useful for simulating natural typing cadence or introducing timed gaps between messages.
Properties
| Property | Type | Description |
|---|---|---|
delayDuration | number | Pause duration in milliseconds |
delayMessage | string | Optional message shown to the user during the pause (e.g., "One moment...") |
Behavior
During the delay, the conversation appears paused. If delayMessage is set, the user sees that message (often with a typing indicator) until the delay completes. After the delay, execution continues to the next connected node.
Use cases
- Add a 1-2 second pause between messages for a more natural conversational rhythm
- Show "Looking that up for you..." before an API call that may take time
- Introduce a deliberate wait before revealing a result for dramatic effect
Wait
Type: wait
Pauses execution until a condition is met. Unlike Delay (which pauses for a fixed time), Wait can pause indefinitely until an external event occurs, a specific time arrives, or a duration elapses.
Properties
| Property | Type | Description |
|---|---|---|
waitMode | duration | until_time | webhook | What the node waits for |
waitDurationSeconds | number | Seconds to wait (used with duration mode) |
waitUntilTime | string | ISO 8601 timestamp to wait until (used with until_time mode) |
waitMaxSeconds | number | Maximum wait time before timeout (applies to all modes) |
waitTimeoutAction | stop | continue | error_branch | fallback_message | What happens when the wait times out |
waitTimeoutMessage | string | Message shown on timeout (used with fallback_message action) |
Wait modes
- duration -- Pauses for a fixed number of seconds. Similar to Delay but measured in seconds and with timeout handling.
- until_time -- Pauses until a specific date and time. Useful for scheduled follow-ups (e.g., "resume this conversation tomorrow at 9 AM").
- webhook -- Pauses until an external system sends a webhook to resume the flow. The flow instance ID is included in the webhook URL so the correct conversation is resumed.
Timeout handling
If waitMaxSeconds elapses before the wait condition is met, the waitTimeoutAction determines what happens:
- stop -- End the flow.
- continue -- Proceed to the next node as if the wait completed normally.
- error_branch -- Route to the error handling path.
- fallback_message -- Show
waitTimeoutMessageto the user and continue.
Use cases
- Wait for an external approval before proceeding with an order
- Schedule a follow-up message for a specific time ("We'll check back with you tomorrow at 10 AM")
- Pause until a payment webhook confirms a transaction
Login
Type: login
Authenticates the visitor within the conversation. Presents a login interface with configurable authentication methods and maps the authenticated user's data to flow variables.
Properties
| Property | Type | Description |
|---|---|---|
loginTitle | string | Heading text for the login prompt (e.g., "Sign in to continue") |
loginSubtitle | string | Secondary text below the title |
loginMethods | object | Which authentication methods to enable: { emailOtp, phoneOtp, googleOAuth } |
skipIfAuthenticated | boolean | When true, skips the login step if the user is already authenticated |
loginRequired | boolean | When true, the user cannot proceed without authenticating |
loginVariableMapping | object | Maps authenticated user fields to flow variables (e.g., email, name, phone, customerId) |
Authentication methods
- Email OTP -- Sends a one-time password to the user's email address.
- Phone OTP -- Sends a one-time password via SMS to the user's phone number.
- Google OAuth -- Redirects to Google for authentication.
You can enable any combination. At least one method must be enabled.
Variable mapping
After successful authentication, the node populates flow variables based on loginVariableMapping. For example:
- Map
emailtouser_email - Map
nametouser_name - Map
phonetouser_phone - Map
customerIdtocustomer_id
These variables are then available to all downstream nodes for personalization, lookups, or API calls.
Use cases
- Gate a support flow behind authentication so the agent can pull up the user's order history
- Identify returning customers to personalize product recommendations
- Collect verified contact information before processing a high-value request
Filter Items
Type: filter_items
Filters, sorts, and limits an array of items stored in a flow variable. The filtered results are written to a new variable.
Properties
| Property | Type | Description |
|---|---|---|
inputVariable | string | The variable containing the array to filter |
outputVariable | string | The variable to store the filtered results |
conditions | array | Filter conditions, each with field, operator, and value |
conditionLogic | AND | OR | How multiple conditions are combined |
sortBy | string | Field name to sort results by |
sortOrder | asc | desc | Sort direction |
limit | number | Maximum number of items to return |
countVariable | string | Optional variable to store the count of filtered results |
Condition logic
When multiple conditions are specified:
- AND -- All conditions must be true for an item to be included.
- OR -- At least one condition must be true for an item to be included.
Each condition specifies a field (property name on each item), an operator (equals, not_equals, greater_than, less_than, contains, not_contains, is_empty, is_not_empty), and a value to compare against.
Use cases
- Filter a product list to only items under $50: condition
price less_than 50 - Sort leads by score descending and take the top 10: sortBy
score, sortOrderdesc, limit10 - Narrow search results to a specific category and count the matches
- Chain with a Loop node to iterate over filtered results