Skip to content

Node Types

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


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"
}
}

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"
}
}

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


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

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" }

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".

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.


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"
}
}

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


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.


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

Sets a variable in the execution context.

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

Stops the workflow and closes the conversation.

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

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.

Creates a support ticket notification and continues.

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

Iterates over arrays or a fixed count.

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.

Iterates a fixed number of times.

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

Iterates while a condition is true.

FieldDescription
loopTypewhile
conditionCondition string (same syntax as logic nodes)

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.


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:

Bot asks for email/phone

User provides contact, OTP sent

User provides correct code

Max attempts exceeded

awaiting_contact

awaiting_otp

verified

failed

{
"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

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.


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.


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.


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.


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.


TypeInputsOutputsSide Effects
triggerPlatform messageBuilt-in variablesNone
llm_callPrompt templateoutputVariable with text, tokensLLM API call
logicCondition/variableEdge routing (if_else or switch)None
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.variables or return valueNone
TypeInputsOutputsSide Effects
agent_loopSystem prompt, toolsoutputVariable with final responseMulti-turn LLM + tool calls
confidence_routerInput variable, thresholdsEdge routing by confidence scoreLLM call for scoring
guardrailInput variable, guardrail typePass/fail + outputVariableLLM-based content check
llm_routerModels list, promptoutputVariable with responseTries models in sequence
structured_outputJSON schema, promptoutputVariable with typed JSONLLM call
vision_analyzeImage URL, promptoutputVariable with analysisVision LLM call
image_generatePrompt, modeloutputVariable with image URLImage generation API
document_parseDocument URLoutputVariable with extracted textDocument processing
knowledge_retrievalQuery, vectorize indexoutputVariable with RAG resultsVectorize search
memory_storeKey, valueNoneWrites to persistent KV
TypeInputsOutputsSide Effects
function_callFunction ID, argumentsoutputVariable with resultCalls deployed function via dispatch
auth_gateProvider, contact typeoutputVariable with identitySends OTP/magic link
delegate_to_botTarget bot IDoutputVariable with responseCalls another bot
sub_workflowWorkflow ID, input varsoutputVariable with resultRuns nested workflow
data_transformJavaScript expressionoutputVariable with resultNone
TypeInputsOutputsSide Effects
parallelNoneNoneFan-out marker
wait_delayDuration (seconds)NonePauses execution
schedule_messageMessage, delayNoneQueues future message
send_proactiveMessage, targetNoneSends to different channel
error_handlerNoneNoneCatches upstream errors