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

Website widget
All plans
Telegram
Pro plan
VK
Pro plan, RU region
MAX
Pro plan, RU region

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.

Svyazio chatbot builder — buttons node configuration with three options (Orders, Support, Questions)

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.

Graceful fallback on channels without inline keyboards. On Avito the engine sends a numbered text list instead ("1. Orders  2. Support  3. Questions"). The visitor replies with the number. The bot treats it as the corresponding click. You don't write any of that fallback logic; the dispatcher handles it.

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.

Svyazio chatbot builder — input node configured to collect email with validation

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.

Svyazio chatbot builder — action node setting a visitor profile field to the collected email

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:

{ "url": "https://api.your-crm.com/customers/{{email}}", "method": "GET", "headers": { "Authorization": "Bearer sk_live_xxx" }, "timeoutMs": 5000, "responseMapping": { "customer_name": "data.full_name", "customer_tier": "data.tier", "order_count": "data.stats.orders" } }

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

Safety rails. Every webhook call runs through an SSRF guard that blocks localhost, private IP ranges (10.x, 172.16/12, 192.168.x, 169.254.x), and IPv6 loopback/link-local addresses. Non-HTTPS URLs are rejected. Responses larger than 256 KB are dropped (and the 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:

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.

  1. StartMessage ("Hi! Quick question: what brings you here today?")
  2. Buttons (Pricing / Integrations / Just looking) → saves choice to intent
  3. Input (email, type = email) → saves to email
  4. Input (company size: solo / 2-10 / 11-50 / 50+) → saves to size
  5. Condition: intent == "Pricing" AND size != "solo" → go to "hot lead" branch
  6. Action: assign_department(Sales) on hot lead branch
  7. Message on cold branch ("Thanks! Here's a walkthrough you might like: [link]")
  8. 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.

  1. Input (order number, type = text) → order_id
  2. Input (email on the order, type = email) → email
  3. Delay (1500 ms) + Message ("Looking that up...")
  4. WebhookGET https://shop-api.example/orders/{{order_id}}?email={{email}}, map status and tracking_url
  5. On success: Message ("Your order is {{status}}. Tracking: {{tracking_url}}") → Buttons ("All good, thanks" / "Something's wrong")
  6. On "All good": Action: close
  7. 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:

  1. Start → Message ("We're offline right now, but we'll get back to you in the morning.")
  2. Input (email) → Input (what's your question?)
  3. Action: set_visitor_field(email) + set_visitor_field(phone if collected)
  4. Webhook → POST to a Telegram channel webhook with the summary, so the morning shift sees it first thing
  5. 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:

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

Do I need to code to build a chatbot?
No. The builder is fully visual — drag nodes, connect them, fill in text fields. The only node where code-like thinking helps is the webhook node, and there you're just pasting a URL and mapping JSON paths. If you can write a spreadsheet formula, you can write a webhook response mapping.
Does one flow really work on both website and Telegram?
Yes. The chatbot engine is channel-agnostic. A dispatcher translates each node into the right transport — Socket.IO events for the widget, inline_keyboard payloads for Telegram, keyboard JSON for VK, attachment inline_keyboards for MAX. You see the same flow in the editor regardless of where it's going to run.
Can I call my own API from a chatbot?
Yes, through the webhook node. HTTPS only. The call runs with a configurable timeout (1–15 seconds), SSRF protections against private networks, and a 256 KB response cap. Map any fields of the response JSON into session variables and branch on success/error.
What happens if the visitor goes silent mid-flow?
The session has a configurable timeout. When it fires, the session transitions to TIMED_OUT, the conversation flags as needing attention, and agents can pick it up from the dashboard. Nothing gets silently abandoned.
How do I stop the bot when an agent wants to take over?
Every conversation panel with an active bot shows a "Stop bot" button. One click removes pending inline keyboards from Telegram/MAX, ends the session, and flags the conversation for the agent. All collected variables stay visible in the visitor profile.
Can I version my flows?
Drafts and published versions are separated. You can iterate on a draft without affecting the live bot, then publish when ready. The published version runs for incoming sessions; in-flight sessions continue on whatever version they started on.
Are there analytics on flow performance?
Yes. Every session logs the nodes it visited. The analytics view shows, per node: how many unique sessions reached it, funnel-style drop-off, average session duration, and breakdown by end status (completed, handed off, timed out). Use it to find dead ends and tighten flows.

Build your first flow today

7 days of Pro on the house. No card required. Full chatbot builder, all channels.

Start 7-day Pro trial

Keep reading

Live chat vs chatbot: when each wins Telegram support: complete guide Connect Telegram in 2 minutes