BotsWorkflowsNode Types

Node Types

Workflows are built from 14 node types. Each performs a specific function and can pass data to downstream nodes via shared variables.


trigger

The entry point for every workflow. At least one trigger node is required.

FieldDescription
triggerTypeCurrently only message_received is supported

When a message arrives, the trigger node sets the following built-in variables and starts the workflow:

VariableValue
messageThe user’s message text
user_idPlatform-specific user identifier
user_nameUser’s display name (if available)
channel_idPlatform-specific channel identifier
platformtelegram, discord, whatsapp, slack, or custom
{
  "id": "trigger_1",
  "type": "trigger",
  "data": {
    "triggerType": "message_received",
    "label": "On Message"
  }
}

llm_call

Sends a prompt to the bot’s configured LLM and stores the response.

FieldRequiredDescription
promptYesThe prompt to send. Supports {{variable}} interpolation.
outputVariableNoVariable name to store the LLM response.
labelNoDisplay label for the node.

The response object contains text, tokensInput, and tokensOutput. Access the response text downstream with {{outputVariable.text}}.

{
  "id": "classify_1",
  "type": "llm_call",
  "data": {
    "prompt": "Classify this customer message into exactly one category: billing, refund, other.\n\nMessage: {{message}}\n\nRespond with only the category name.",
    "outputVariable": "intent",
    "label": "Classify Intent"
  }
}

LLM call nodes use the bot’s configured provider and model. Temperature is set to 0.3 for more deterministic outputs.

Use case: Intent classification, data extraction, response generation, summarization, translation.


logic

Conditional branching. Routes execution to different downstream nodes based on conditions.

if_else

Evaluates a condition and follows the true or false edge.

{
  "id": "check_1",
  "type": "logic",
  "data": {
    "logicType": "if_else",
    "condition": "{{intent.text}} == billing",
    "label": "Is Billing?"
  }
}

Connect edges with sourceHandle:

{ "source": "check_1", "target": "billing_node", "sourceHandle": "true" },
{ "source": "check_1", "target": "other_node", "sourceHandle": "false" }

switch

Matches a variable against multiple cases.

{
  "id": "switch_1",
  "type": "logic",
  "data": {
    "logicType": "switch",
    "variable": "intent",
    "cases": ["billing", "support", "general"],
    "label": "Route by Intent"
  }
}

Connect edges with sourceHandle: "case_billing", sourceHandle: "case_support", etc. Unmatched values follow sourceHandle: "case_default".

wait

Pauses execution until the next user message. Currently a placeholder for future multi-turn workflow support.

See Variables & Conditions for the full condition syntax reference.


mcp_tool

Calls any MCP tool from the bot’s workspace.

FieldRequiredDescription
toolNameYesFully qualified tool name (e.g., stripe__get_payment)
argumentsNoJSON string with {{variable}} interpolation. Default: {}
outputVariableNoVariable name to store the tool result.

The result is truncated to 3000 characters and stored in outputVariable.

{
  "id": "lookup_1",
  "type": "mcp_tool",
  "data": {
    "toolName": "orders__get_order",
    "arguments": "{\"order_id\": \"{{order_id}}\"}",
    "outputVariable": "order_data",
    "label": "Look Up Order"
  }
}
⚠️

If the tool name is not found in the workspace, or if the arguments JSON is malformed, the node returns an error object in the output variable rather than throwing an exception. Always check the result before using it in downstream nodes.

Use case: Query databases, process payments, create tickets, search knowledge bases, call any external API exposed through an MCP server.


send_message

Sends a message to the user.

FieldRequiredDescription
messageNoMessage text with {{variable}} interpolation. If omitted, sends the last AI response.
useTemplateNoWhether to treat the message as a template (default: true).
{
  "id": "respond_1",
  "type": "send_message",
  "data": {
    "message": "Your order #{{order_id}} is currently {{order_data.status}}. Shipped on {{order_data.shipped_date}}.",
    "label": "Send Order Status"
  }
}

If no message is provided, the node sends the value of ctx.variables.ai_response (the most recent LLM call output).

A workflow can have multiple send_message nodes. All messages are collected and sent in order when the workflow completes.


action

Performs side effects that don’t produce user-facing messages.

set_variable

Sets a variable in the execution context.

{
  "type": "action",
  "data": {
    "actionType": "set_variable",
    "variable": "greeting",
    "value": "Hello, {{user_name}}!",
    "label": "Set Greeting"
  }
}

end_conversation

Stops the workflow and closes the conversation.

{
  "type": "action",
  "data": {
    "actionType": "end_conversation",
    "label": "End"
  }
}

human_handoff

Pauses the workflow and notifies a human reviewer. The reviewer receives the conversation context, the escalation reason, and approve/reject controls. See Human Handoffs for the complete guide.

{
  "type": "action",
  "data": {
    "actionType": "human_handoff",
    "reason": "Refund request over $500 for order {{order.id}}",
    "label": "Escalate to Finance"
  }
}

The workflow pauses at this point. When the reviewer approves, execution resumes on the approved path. When rejected, execution follows the rejected path.

create_ticket

Creates a support ticket notification and continues.

{
  "type": "action",
  "data": {
    "actionType": "create_ticket",
    "subject": "Issue with order {{order_id}}",
    "label": "Create Ticket"
  }
}

The create_ticket action sends a notification message. For creating actual tickets in external systems (Zendesk, Jira, etc.), use an mcp_tool node connected to the appropriate MCP server.


loop

Iterates over arrays or a fixed count.

for_each

Iterates over an array variable.

FieldDescription
loopTypefor_each
arrayVariableName of the variable containing the array
itemVariableVariable name for the current item (default: item)
maxIterationsMaximum iterations (capped at 50)
{
  "type": "loop",
  "data": {
    "loopType": "for_each",
    "arrayVariable": "order_items",
    "itemVariable": "current_item",
    "maxIterations": 10,
    "label": "Process Each Item"
  }
}

Connect edges with sourceHandle: "loop_body" (for the loop body) and sourceHandle: "loop_done" (for after the loop completes).

Use case: Process each item in a shopping cart, send a message for each search result, iterate over a list of tickets.

count

Iterates a fixed number of times.

FieldDescription
loopTypecount
iterationsNumber of iterations
itemVariableVariable name for the current index (default: index)

while

Iterates while a condition is true.

FieldDescription
loopTypewhile
conditionCondition string (same syntax as logic nodes)

code_block

Runs JavaScript code in a sandboxed context.

FieldDescription
codeJavaScript code to execute

Available in the sandbox:

ObjectAvailable
ctx.variablesRead/write workflow variables
ctx.messageUser’s message text
ctx.user_idUser identifier
JSON, Math, Date, String, Number, Array, ObjectYes
parseInt, parseFloat, isNaNYes
encodeURIComponent, decodeURIComponentYes
fetch, require, importNo (blocked)
{
  "type": "code_block",
  "data": {
    "code": "const items = ctx.variables.order_items || []; ctx.variables.total = items.reduce((sum, item) => sum + item.price, 0); ctx.variables.item_count = items.length;",
    "label": "Calculate Total"
  }
}

Use case: Data transformation, calculations, string manipulation, filtering arrays, formatting output, business logic that does not require external calls.

⚠️

Code blocks run in a sandboxed environment. They cannot make network requests or access the filesystem. Do not expose code block configuration to untrusted users.


auth_gate

Runs a multi-turn identity verification flow inside the conversation. The bot prompts the user for their email or phone number, sends a one-time code via one of the supported providers, and verifies the code before allowing the workflow to continue.

FieldDescription
providerresend, ses, twilio, msg91, or custom_http
contact_typeemail or phone
outputVariableVariable to store the verified identity

State machine:

{
  "type": "auth_gate",
  "data": {
    "provider": "resend",
    "contact_type": "email",
    "outputVariable": "verified_identity",
    "label": "Verify Customer Email"
  }
}

Connect edges with sourceHandle: "verified" and sourceHandle: "failed":

{ "source": "auth_1", "target": "proceed_node", "sourceHandle": "verified" },
{ "source": "auth_1", "target": "deny_node", "sourceHandle": "failed" }

After verification, {{verified_identity}} contains the verified email or phone number.

Use case: Verify identity before accessing account data, processing refunds, or changing settings. Required for any workflow that handles sensitive personal information.

Supported providers:

  • Resend — Email OTP via Resend API
  • SES — Email OTP via Amazon SES
  • Twilio — Phone OTP via Twilio SMS
  • MSG91 — Phone OTP via MSG91
  • Custom HTTP — Your own OTP endpoint

schedule_message

Sends a message at a future time.

FieldDescription
messageMessage text with {{variable}} interpolation
delay_minutesMinutes from now to send the message
scheduled_timeISO 8601 timestamp for exact scheduling
{
  "type": "schedule_message",
  "data": {
    "message": "Reminder: Your appointment is in 1 hour. Reply to confirm or cancel.",
    "delay_minutes": 1380,
    "label": "24h Reminder"
  }
}

Use case: Appointment reminders, follow-up messages after support interactions, daily digests, shift notifications.


send_proactive

Sends a message to a different channel or user than the one who triggered the workflow.

FieldDescription
messageMessage text with {{variable}} interpolation
target_channel_idThe channel/user to send to
target_platformThe platform to send on (can differ from trigger platform)
{
  "type": "send_proactive",
  "data": {
    "message": "Alert: Customer {{user_name}} reported a critical issue. Details: {{message}}",
    "target_channel_id": "ops-alerts-channel",
    "target_platform": "slack",
    "label": "Notify Ops Channel"
  }
}

Use case: Notify a team channel when a customer reports an issue, alert on-call engineers, send summaries to management channels, cross-platform notifications.


delegate_to_bot

Calls another bot, passing the current message and context. The target bot processes the message using its own workspace and tools, and the response is returned to the current workflow.

FieldDescription
target_bot_idThe bot ID to delegate to
outputVariableVariable to store the delegated bot’s response
contextOptional JSON context to pass to the target bot
{
  "type": "delegate_to_bot",
  "data": {
    "target_bot_id": "bt_billing_specialist",
    "outputVariable": "specialist_response",
    "context": "{\"customer_id\": \"{{verified_identity}}\"}",
    "label": "Route to Billing Bot"
  }
}

Maximum 3 delegation hops to prevent infinite loops. See Bot Teams & Delegation for architecture patterns and examples.

Use case: Reception bot routes to specialist bots (billing, technical support, HR). Each specialist has its own workspace with domain-specific tools.


error_handler

Catches errors from upstream nodes and provides a fallback path.

{
  "type": "error_handler",
  "data": {
    "label": "Handle Errors",
    "fallback_message": "Something went wrong while processing your request. A support agent will follow up shortly."
  }
}

If a node throws an error, the error is recorded in the execution log and the workflow continues following the error_handler’s edges.

Use case: Send a graceful fallback message instead of leaving the user with no response. Log the error for debugging.


parallel

A structural node for fan-out execution. When the graph walker encounters a node with multiple outgoing edges, it follows all of them in breadth-first order. The parallel node is a visual marker for this behavior.

{
  "type": "parallel",
  "data": { "label": "Fan Out" }
}

Connect multiple outgoing edges from the parallel node to execute multiple paths simultaneously:

{ "source": "parallel_1", "target": "lookup_order" },
{ "source": "parallel_1", "target": "lookup_account" },
{ "source": "parallel_1", "target": "check_inventory" }

Use case: Fetch data from multiple MCP tools at the same time, send notifications to multiple channels, run independent processing steps in parallel.


Node Type Summary

TypeInputsOutputsSide Effects
triggerPlatform messageBuilt-in variablesNone
llm_callPrompt templateoutputVariable with text, tokensLLM API call
logicCondition/variableEdge routingNone
mcp_toolTool name, argumentsoutputVariable with tool resultMCP tool call
send_messageMessage templateNoneSends message to user
actionAction-specific fieldsVariable (set_variable)Depends on action type
loopArray/count/conditionitemVariable per iterationNone
code_blockJavaScript codeVia ctx.variablesNone
auth_gateProvider, contact typeoutputVariable with identitySends OTP
schedule_messageMessage, delayNoneQueues future message
send_proactiveMessage, targetNoneSends to different channel
delegate_to_botTarget bot IDoutputVariable with responseCalls another bot
error_handlerFallback configNoneFallback message
parallelNoneNoneFan-out marker