A reference for flow.json — the file the visual editor generates
flow.json describes the whole bot scenario: nodes, the edges between them and the
project settings. The editor validates the file against a JSON Schema
(schemaVersion: "1.0"), so any exported config is guaranteed to load
back. Manual edits are safe too: load the file via "Import JSON" and the editor
checks it with the same schema.
{
"schemaVersion": "1.0",
"name": "my-bot",
"version": "1.0.0",
"platforms": ["telegram", "alisa"],
"database": { "type": "file", "config": {} },
"nodes": [],
"edges": [],
"fallback": { "text": "Sorry, I didn't understand." },
"welcome": { "text": "Hello!" }
}
| Field | Description |
|---|---|
| schemaVersion | Format version, currently always "1.0" |
| name | Project name — used in package.json and the folder name |
| version | Project version (semver) |
| platforms |
Platform list: telegram, alisa,
marusia, vk, max_app,
viber, smart_app
|
| database | Data storage: file, mongo or none |
| nodes | All scenario blocks (see the types below) |
| edges | Connections between blocks |
| welcome | Welcome message shown when the dialog starts |
| fallback | Reply to unrecognized input |
| variables | Variable comments: name → description |
| Type | Purpose |
|---|---|
| command | Command — reacts to trigger words |
| step | Step — waits for the user's reply and saves it to a variable |
| condition | Condition — branches on a variable |
| action | Action — HTTP requests, variables, random numbers |
| response | Response — shows text and buttons without asking for input |
| end | End — closes the dialog |
{
"type": "command",
"id": "node_123",
"name": "greeting",
"slots": ["hello", "hi"],
"isPattern": false,
"saveTo": "lastGreeting",
"response": { "text": "Hi, {{userName}}!", "buttons": [] }
}
| Field | Description |
|---|---|
| slots | Trigger words, case-insensitive |
| isPattern | When true, slots are treated as regular expressions |
| saveTo | Save the user's input to a variable |
| response | Reply text, TTS, buttons, card, dialog end |
{
"type": "step",
"id": "node_456",
"name": "ask_name",
"prompt": { "text": "Nice to meet you, {{userName}}!" },
"saveTo": "userName",
"saveAs": "original"
}
A step runs on the user's reply: the question is asked by the block before the step,
and the optional prompt.text is sent after the reply.
saveAs: "original" keeps the input as typed, "lowercase"
lowercases it. Where to go next is defined by the next edge.
{
"type": "condition",
"id": "node_789",
"name": "check_age",
"variable": "age",
"operator": "gte",
"value": 18
}
The yes/no branches are defined by branch_true and
branch_false edges. The value may be a number, a string or a variable
name.
| Code | Check |
|---|---|
| eq / neq | Equals / not equals |
| gt / gte / lt / lte | Greater / greater-or-equal / less / less-or-equal |
| contains | String contains a substring |
| isEmpty / isNotEmpty | Variable is empty / not empty |
| isSayTrue / isSayFalse | User answered "yes" / "no" (natural language) |
| isUrl | Value is a valid URL |
Three action types: set_variable (evaluate an expression and write it
to a variable), random_number (a random number between min and max)
and http_request (a GET/POST request with headers, body and saving the
response to a variable). The {{variable}} substitution works in URLs,
bodies and expressions.
{ "from": "node_123", "to": "node_456", "type": "next" }
| Type | Description |
|---|---|
| next | Sequential transition to the next block |
| branch_true | The "yes" branch from a condition |
| branch_false | The "no" branch from a condition |
| slot_match | Transition on a slot match |
Use {{name}} in any text — the value is substituted automatically:
"Hello, {{userName}}!" → setText(ctrl, `Hello, ${ctrl.userData.userName}!`)
Block names with spaces and special characters are automatically turned into valid identifiers. The editor catches typical errors before export: empty replies, unreachable blocks, duplicate names after sanitization, missing connections. Conditions inside one block are isolated — two conditions on the same variable in one block don't conflict.