Contents
- Why a visual builder beats code and decision trees
- Channels where one flow works
- Anatomy of a flow
- Message node
- Buttons node
- Input node (with validation)
- Condition node
- Action node (handoff, variables)
- Delay node
- Webhook node (HTTP to any API)
- Variables and template syntax
- Three real-world flows you can copy
- Human handoff and session control
- Pricing and limits
- FAQ
Most chatbot platforms make you choose between two bad options. Either you drag boxes around a canvas and end up with a glorified decision tree that can't talk to your systems, or you open a code editor, learn yet another YAML dialect, and spend a week wiring up something nobody on the team can edit. Svyazio's flow builder is visual, but it has an escape hatch for every serious requirement: validated inputs, branching conditions, real HTTP webhooks with response mapping, variables that flow through the entire session, and handoff to a real human the moment the bot reaches its limit.
The same flow runs on every channel Svyazio supports — the website widget, Telegram bots, VK communities, and MAX. Inline keyboards are rendered natively on each platform. On channels without keyboard support, buttons fall back to numbered text options so the visitor can still reply with "1" or "2". You build the flow once; the engine figures out how to speak each channel's language.
Why a visual builder beats code and decision trees
The case for a visual flow builder isn't just "non-developers can edit it." The real wins are subtler:
Flows are readable as diagrams. Anyone on your team — support lead, product manager, head of marketing — can open the editor and understand what the bot does in thirty seconds. Code-based bot definitions require reading. Visual flows are perceived as shapes. That alone cuts review cycles from days to minutes.
Edge cases have a home. A classic decision tree collapses under real traffic because every interesting flow has loops, retries, timeouts, and handoffs. Svyazio lets you wire those explicitly — a failing webhook routes to an error branch, a missing input triggers a retry prompt, a session timeout opens the inbox for a human. All visible, all attached to specific nodes.
Variables make the bot stateful. Every input node writes to a variable. Every webhook can map parts of its response into variables. Every later node can interpolate them into messages — Hello {{name}}, your order {{order_id}} ships tomorrow. The bot remembers things instead of starting from zero on every step.
Channels where one flow works
The website widget speaks Socket.IO. Telegram and MAX accept inline keyboards. VK has its own keyboard format. The chatbot engine translates each node to the right transport: the buttons node becomes an inline_keyboard on Telegram, a keyboard payload on VK, Socket.IO events on the widget. You see the same flow in the editor regardless.
Anatomy of a flow
Every flow starts with a single start node. From there you chain nodes together by dragging connections between them. Each node has 0 or 1 incoming edges and 1 or more outgoing edges. Nodes can loop back, branch, and merge — the engine follows edges one step at a time.
The builder showing a buttons node being edited. Left panel: node palette. Canvas: the flow. Right panel: properties of the selected node.
The left panel lists every available node type. The canvas is where the flow lives. The right panel shows the properties of whatever node is selected. Changes save when you click Save; they go live when you click Publish. Drafts and published versions are separate, so you can iterate without breaking the bot that's in production.
1. Message node
message
Sends plain text from the bot. Supports variable interpolation with {{variable_name}} syntax. Has an optional delay before send in milliseconds — use this to avoid the "instant wall of text" effect that makes bots feel robotic.
A typical use: a welcome message with the visitor's name pulled from the widget's visitor profile, followed by a quick pause before the next question. The delay is bounded to prevent accidents: 0 to 10 seconds, enforced server-side.
2. Buttons node
buttons
A message + inline keyboard. Each button has a label and its own outgoing edge. When the visitor taps a button, the engine follows the matching edge. The session pauses between sending the buttons and receiving the click.
Buttons are where most of your branching logic actually lives. A three-button menu ("Orders / Support / Questions") generates three distinct outgoing paths — each one can lead to its own sub-flow with completely different logic. The engine waits for the click, respects rate limits (30 events per minute per session), and on Telegram/MAX it deletes the inline keyboard after the click so the visitor can't double-tap.
3. Input node (with validation)
input
Asks for free text and stores it in a variable. Built-in validation for text, email, and phone. On invalid input the bot re-prompts without advancing. On valid input the answer is saved under session.variables[name] and the flow moves forward.
Input node set to capture an email. The variable is named email, validation type is Email, and the placeholder hints at the expected format.
Validation is strict but helpful: the email check rejects obviously malformed addresses, the phone check accepts international formats and normalizes them, and the text check simply enforces a non-empty response. The node holds onto the session until the visitor sends something that passes. If nothing arrives within the session timeout, the bot hands off to a human instead of looping forever.
Variables captured here become available to every subsequent node. A later message can greet the visitor by name, a later webhook can include their email in the payload, and the final action node can set their profile field so their answers persist beyond this conversation.
4. Condition node
condition
Branches based on variables or visitor fields. Each branch is a set of AND-conditions. The engine evaluates them top to bottom; the first match wins. If nothing matches, the flow falls through to the default branch.
Conditions are how you turn data into flow control. Did the visitor type "cancel" during the input step? Route them to the cancellation flow. Is their visitor profile marked as a returning customer? Skip the intro. Did the webhook respond with status = "vip"? Jump to the priority queue. Every comparison operator you'd expect is there: equals, not equals, contains, starts with, numeric greater/less, boolean true/false, and regex for the cases where nothing else fits.
5. Action node (handoff, variables, profile)
action
Side effects without user interaction. Five subtypes: assign_department, assign_agent, close, set_variable, and set_visitor_field. The first three end the bot session — they're the handoff story.
Action node writing the collected email into the visitor's profile, so agents see it without asking again.
The handoff actions are critical. A bot's job is usually to qualify, collect, and route — not to replace the agent. assign_department drops the conversation into the right queue (Sales, Support, Billing), assign_agent pins it to a specific person, and close marks the conversation as resolved when the bot finishes on its own (delivery status lookup, FAQ question answered, etc). The visitor never sees these as separate events — the conversation just continues seamlessly with a human.
set_visitor_field is quieter but equally useful. It writes to the visitor's persistent profile. The email the bot collected becomes their profile email. The phone becomes their phone. Next time they come back — from any channel — the data is already there.
6. Delay node
delay
Pauses the flow for a fixed duration. Useful between back-to-back messages to avoid the "bot typed three paragraphs in 200ms" giveaway. Bounded from 0 to 10 seconds.
Delays are the difference between a bot that feels like a keyboard shortcut and one that feels like a conversation. 300–800 ms between short messages is usually enough. Longer delays (2–3 seconds) work well before a message that acknowledges work being done — "one moment, checking your order" — especially paired with a webhook call in progress.
7. Webhook node (HTTP to any API)
webhook
The escape hatch for serious logic. Calls any HTTPS URL with a method, optional headers, optional body, and a timeout. The response can be mapped into session variables; the flow then branches on success or error.
This is the node that turns Svyazio from a chatbot toy into an integration platform. Look up an order in your backend, query your CRM, ping a loyalty points service, call a GPT completion endpoint — whatever HTTP can do, the webhook node can do. Both the URL, the headers, and the body support variable interpolation, so every call is contextual to the current session.
A typical configuration:
After this node runs, {{customer_name}}, {{customer_tier}}, and {{order_count}} are available to every downstream node. The very next step is typically a condition node that branches on customer_tier == "vip".
error branch is taken). The maximum timeout is 15 seconds, after which the request is aborted. You don't have to think about any of this; it's on by default.
The webhook node has two outgoing edges: success (HTTP 2xx) and error (4xx/5xx, timeout, SSRF block, malformed response). If you only wire up the success branch, failures fall back to the default edge — so nothing ever stalls silently.
Variables and template syntax
Variables are the glue. Every input node, every webhook response mapping, every set_variable action writes into session.variables. Every message, buttons, and webhook URL/body can read from it via {{variable}} interpolation. The dot notation works too: if a webhook maps order to the whole response object, you can later reference {{order.tracking_number}}.
Hard limits to keep sessions sane:
- At most 100 variables per session
- At most 2,000 characters per variable value
- The session path log (used by analytics) caps at 500 node traversals
You will not hit these limits with a normal flow. They exist to protect you from the pathological case of a runaway loop writing into variables until memory runs out.
Three real-world flows you can copy
Example 1: Lead qualification bot for a SaaS
Goal: ask three questions, score the lead, route hot leads to Sales, cold leads to the onboarding flow.
- Start → Message ("Hi! Quick question: what brings you here today?")
- Buttons (Pricing / Integrations / Just looking) → saves choice to
intent - Input (email, type = email) → saves to
email - Input (company size: solo / 2-10 / 11-50 / 50+) → saves to
size - Condition:
intent == "Pricing"ANDsize != "solo"→ go to "hot lead" branch - Action: assign_department(Sales) on hot lead branch
- Message on cold branch ("Thanks! Here's a walkthrough you might like: [link]")
- Action: close after cold branch message
Total build time: ~10 minutes. No code. Works on the website widget and Telegram identically.
Example 2: Order status lookup for e-commerce
Goal: visitor asks for an order status, bot looks it up in the shop backend, returns tracking info, offers a handoff if something's wrong.
- Input (order number, type = text) →
order_id - Input (email on the order, type = email) →
email - Delay (1500 ms) + Message ("Looking that up...")
- Webhook →
GET https://shop-api.example/orders/{{order_id}}?email={{email}}, mapstatusandtracking_url - On success: Message ("Your order is {{status}}. Tracking: {{tracking_url}}") → Buttons ("All good, thanks" / "Something's wrong")
- On "All good": Action: close
- On "Something's wrong" OR on webhook error: Action: assign_department(Support)
Example 3: Night bot that hands off when operators are online
Goal: run only when all agents are offline, collect the essentials, drop a ticket in Telegram for the morning shift.
Triggered by the operators_offline = offline condition on the widget trigger (not a flow node — this is configured on the bot's when to run settings). The bot itself is a simple flow:
- Start → Message ("We're offline right now, but we'll get back to you in the morning.")
- Input (email) → Input (what's your question?)
- Action: set_visitor_field(email) + set_visitor_field(phone if collected)
- Webhook → POST to a Telegram channel webhook with the summary, so the morning shift sees it first thing
- Action: close
Human handoff and session control
Agents always have the last word. Anywhere in the dashboard, when a chatbot session is active on a conversation, a banner appears: "Bot X is handling this conversation" with a Stop bot button. One click and the bot is done — the session transitions to HANDED_OFF, any pending inline keyboards are removed from Telegram/MAX, and the conversation flags as needing attention. The agent takes over from there.
This isn't just a panic button. It's the main integration point between bots and humans. Bots handle the routine stuff; agents step in when things get interesting. The variables the bot collected are visible to the agent, so they don't restart from zero.
On the engine side, a few safety nets run in the background:
- A Redis-backed lock serializes concurrent clicks — the visitor can't double-tap a button and trigger two paths.
- A rate limiter caps each session to 30 events per minute, so a script can't drive a bot into an infinite loop.
- A cron sweep runs every minute and times out sessions that have been waiting for input beyond their limit — the conversation reopens for humans, nothing gets stuck.
Pricing and limits
Chatbots are a Pro plan feature. The plan also bundles the AI writing assistant, triggers and auto-messages, departments, analytics, unlimited agents, white-label, and 10 Telegram bots. Both paid plans include a 7-day free trial, no credit card required.
See the chatbots landing for a quick product tour, the full pricing page for plan details, or jump straight to creating an account.
FAQ
TIMED_OUT, the conversation flags as needing attention, and agents can pick it up from the dashboard. Nothing gets silently abandoned.