General Chain Architecture
A MyCode.Bot scenario is built as a chain of nodes. Each node has its own role in the scenario: starts execution, shows a message, waits for input, calls an API, checks a condition, stores data, or finishes execution.
A node starts working when execution reaches its input. After it finishes, it either passes control to the next node, shows a screen and waits for a new user action, or ends the scenario.
How to Read a Schema
| Concept | Meaning |
|---|---|
| Input | A connection that brings execution into a node. Multiple previous nodes can lead to the same input. |
| Standard output | A NextAction transition to one next node. |
| Special output | A separate branch, such as True / False, Prompt / Invalid, or a specific button output. |
| Entry point | A node that starts a new scenario: Trigger, Agent trigger, Error, or a system event. |
| Terminal node | A node without a next transition. For example, JSON output returns JSON, and Chat transfers the dialog to an operator. |
The editor stores connections as action strings. Regular nodes use node:{id}, screens use go_to_screen:{id}, and event/webhook nodes can have a system or custom action. In the panel, connect nodes through connectors instead of entering these service strings manually.
Quick Catalog
| Node | Technical name | Main purpose | Outputs | Waits for user | Typical mode |
|---|---|---|---|---|---|
Event |
Event |
Starts a scenario from an event. See Event Types. | 1 | No | Messenger |
HTTP webhook Soon |
HttpWebhook |
Starts a scenario from an external HTTP POST | 1 | No | Webhook |
Screen |
Screen |
Shows a message, image, and buttons | Buttons + fallback | Yes | Messenger |
Keyboard Screen |
Screen |
Shows a screen with keyboard answer options | Buttons + fallback | Yes | Messenger |
Carousel screen |
CarouselScreen |
Shows a carousel of cards with buttons (Instagram only) | Card buttons + fallback | Yes | |
Share phone screen |
SharePhoneScreen |
Asks the user to share a phone number | 1 | Yes | Messenger |
Input |
UserInput |
Validates and normalizes the entered value | Next / Prompt / Invalid |
As needed | Messenger |
Viber survey |
ViberSurvey |
Shows a survey and branches by answer | One per option + fallback | Yes | Viber Business |
HTTP request |
HttpRequest |
Calls an external HTTP API | 1 | No | Messenger / AI tool |
JSON processor |
JsonProcessor |
Converts JSON or text into variables | 1 | No | Messenger / AI tool |
Condition |
Condition |
Selects a true or false branch with a JS condition | 2 | No | Messenger / AI tool |
Switch |
SwitchNode |
Routes the scenario by an exact value | One per case + default | No | Messenger |
Set user tag |
SetUserTag |
Adds a tag to the current member | 1 | No | Messenger |
Get user tag |
GetUserTag |
Reads the member tags into a variable (JSON array) | 1 | No | Messenger |
User has tag |
UserHasTagNode |
Checks the member tags and branches | 2 (True / False) |
No | Messenger |
Remove user tag |
RemoveUserTagNode |
Removes one tag of the current member | 1 | No | Messenger |
Set memory |
SetMemory |
Stores a field set across executions | 1 | No | Messenger |
Get memory |
GetMemory |
Reads stored fields into variables | 1 | No | Messenger |
Chat Soon |
Chat |
Transfers the dialog to an operator | 0 | No | Messenger handoff |
JSON output |
JsonOutput |
Returns the final JSON from an AI tool | 0 | No | AI tool |
Processor is visible in GET /api/BotSchema/node-types with code 3, but it is only a reserved enum value. It has no concrete node, DTO/mapper, settings form, CRUD endpoint, or runtime behavior, so it cannot be created and used as a node.
HttpWebhook has a backend creation API and runtime endpoint, but the current backend does not have HttpWebhookNodeMapper. Because of this, the node is not returned in the general schema DTO response and is not fully available in the standard editor UI.
It is not currently used on the frontend; until the integration is clarified, it is marked as Soon.
Event Types
Event is the technical node behind several entry points. The quick catalog shows it as Event, but the concrete startup scenario is selected by EventType.
EventType |
When it is used |
|---|---|
OnMemberFollow |
Initial entry flow for Telegram /start and Viber conversation_started; can also run for an existing member. |
OnEnd |
Reserved end event; no automatic host trigger was found in the checked backend. |
OnError |
Separate error-handling branch. In the builder, it can appear as Error. |
OnTrigger |
Startup by custom action/parameter. |
OnChatClosed |
New scenario after an operator chat is closed. |
OnAgentTriggered |
Entry into a synchronous AI tool; corresponds to Agent trigger in the builder. |
How Execution Works
Within one execution, nodes run sequentially: a node receives control on its input, performs its action, and passes control through a standard or special output.
Event -> HTTP request -> Condition -> Screen
If a node shows a screen and waits for a user action, the current execution ends. The next message or button click starts a new execution. The backend carries the current input and system member context into it, but not the whole result dictionary from the previous run.
Because of this, data that must survive several user messages should be stored separately: with Set memory / Get memory or in the user tags.
#var Variables
A variable is stored in context without #, but in templates its key is written with #:
#member.name
#node.12.http.statusCode
#node.25.customerName
Names can contain Latin letters, numbers, _, and dot-separated segments. For example, #node.12.http.statusCode is a valid key, while a key with a hyphen is not read as one variable. Key lookup is case-insensitive, but keeping one writing style improves readability.
In regular text, a missing variable is replaced with an empty string. So Hello, #member.name! becomes Hello, ! if the name is not set.
There is no separate escape syntax for a literal #name: that sequence is treated as a variable and disappears from the result if the key is missing.
System Variables
When a scenario starts with member context, these variables are available:
| Variable | Meaning |
|---|---|
#member.name |
Member name |
#member.phone |
Member phone |
#member.second_name |
Second name or surname from the member model |
#member.nick |
Member nickname |
#member.external_id |
Member ID in the external messenger |
#member.tags |
Member tags as a JSON array string, for example ["vip","kyiv"]. Updated during the current execution after Set user tag or Remove user tag. |
#bot.name |
Bot name |
In a webhook without a matched member, and in an AI tool, member context is absent, so these values are empty or unavailable.
Variables Created by Nodes
Most nodes write their result under #node.{id}.*. For example, if HTTP request has ID 12, the response code is available as #node.12.http.statusCode.
| Source | Typical key |
|---|---|
Input after Screen or Keyboard Screen |
#node.{screenId}.{TargetKey} |
Input |
#node.{id}.{TargetKey} |
Viber survey |
#node.{id}.{TargetKey} |
Event |
#node.{id}.event_triggered, #node.{id}.trigger_param |
HTTP request |
#node.{id}.http.statusCode, #node.{id}.http.isSuccess, #node.{id}.http.rawBody, #node.{id}.http.reasonPhrase, #node.{id}.http.queued in async mode, and JSON fields |
JSON processor |
JSON fields or #node.{id}.json.source |
Condition |
#node.{id}.condition.result, #node.{id}.condition.action, sometimes #node.{id}.condition.error |
User has tag |
#node.{id}.userHasTag.result |
Switch |
#node.{id}.switch.result, #node.{id}.switch.action |
Get user tag |
#node.{id}.{OutputKey} |
Get memory |
#node.{id}.{memoryField} |
JSON output |
#node.{id}.json.raw before execution ends |
The exact list of available values for a node can be taken from the variable picker. Values in that list can be empty: this is a hint about a key, not a promise that runtime already has data.
Variable Lifetime
Regular #var values live only within one chain execution. When the bot shows a Screen and stops, the user's next message starts a new execution.
The backend carries the current input and system member context into the new execution, but not the whole result dictionary from the previous run.
Practical rule:
- use regular variables between nodes that run without a pause;
- after
Screen, the new input is guaranteed as#node.{screenId}.{TargetKey}; - to preserve other data across several messages, use
Set memory/Get memoryor user tags.
Where Substitution Works
| Field | #var |
{{ JS }} |
|---|---|---|
Screen: message title/text/photo URL |
Yes | Yes |
Share phone screen: message and share-button text |
Yes | Yes |
Viber survey: question text |
Yes | Yes |
HTTP request: body template |
Yes | Yes |
HTTP request: header values |
Yes | Yes |
HTTP request: URL |
Yes | Yes |
JSON processor: JSON template |
Yes | Yes |
JSON output: JSON template |
Yes | Yes |
Set memory: value template |
Yes | Yes |
Set user tag: tag value |
No | No |
Condition: expression |
Yes | Yes, as a boolean expression |
Regular Screen buttons, Viber survey answer texts, memory field names, MemoryName, and TargetKey do not pass through the template renderer.
JavaScript in Nodes
In text or JSON templates, JavaScript is written between {{ and }}:
Hello, {{ truncate(#member.name, 20) }}!
{
"customer": {{ JSON.stringify(#member.name) }},
"is_success": {{ #node.12.http.isSuccess }}
}
Before execution, #var values are converted into JS values:
true/falsebecome booleans;- a number in invariant format becomes a number;
- other text becomes a safe JS string literal;
- a missing key becomes
null.
For JSON, it is better to use JSON.stringify(...) when the value is inserted outside already opened quotes. A simple construction like "name": "#member.name" can create invalid JSON if the value itself contains quotes or special characters.
Conditions
Condition.Expression accepts a raw JS expression or an expression wrapped in one outer {{ ... }} pair:
#node.12.http.statusCode == 200 && #node.12.http.isSuccess
parseJson(#node.12.http.rawBody).items.length > 0
The result is converted to boolean. Empty string, 0, false, no, null, undefined, and NaN mean false. A non-zero number, true, yes, and any other non-empty string mean true. Objects and arrays are not converted directly to boolean - compare a specific property or length.
Available Helper Functions
| Function | Purpose | Example |
|---|---|---|
truncate(value, length) |
Cuts text and adds ... |
{{ truncate(#member.name, 10) }} |
parseJson(json) |
Converts a JSON string into a JS object | {{ parseJson(#node.12.http.rawBody).order.id }} |
parseBase64Json(base64) |
Decodes base64 JSON and returns an object | {{ parseBase64Json(#node.5.payload).status }} |
Standard JavaScript expression features, including field access, arrays, .map(...), .join(...), and global JSON, are executed by the Jint engine.
JS Limits and Errors
Condition.Expressionrejects expressions with;as disallowed statements. In a regular{{ JS }}template, an expression with;is not executed and silently produces an empty fragment.- One expression has a 100 ms timeout, a maximum of 50 statements, and recursion depth 5.
- In a regular template, a JS error stops the node. Exception: an undefined identifier produces an empty fragment.
- In
Condition, a missing#varbecomesnulland usually leads to the false branch without an error. - A syntax or runtime error in
Conditionadds an execution error and stops the scenario. It is not an automatic transition to the false branch. - HTML entities inside an expression are decoded, so
>saved by the editor is executed as>.
Nodes Available in AI Tool
A synchronous AI tool cannot wait for a new human message or show a messenger screen. The practically supported skeleton is:
Agent trigger -> HTTP request / JSON processor / Condition -> JSON output in every branch
| Node | In AI tool | Reason |
|---|---|---|
Agent trigger |
Yes | Entry point and argument validation |
HTTP request |
Yes | Synchronous external API call |
JSON processor |
Yes | Synchronous variable formation |
Condition |
Yes | Synchronous branching |
JSON output |
Yes | Required terminal result |
Screen, Keyboard Screen, Carousel screen, Share phone screen, Input, Viber survey |
No | Wait for user interaction |
Chat |
No | Terminal handoff without JSON |
Set user tag, Get user tag, User has tag, Remove user tag |
No | No member context/post-processing tool flow |
Set memory, Get memory |
No | Memory dispatcher requires member UserId |
Switch |
No | Not part of the verified AI tool skeleton |
HTTP webhook |
Not recommended | External entry point, not a tool processing step |
Other Event nodes |
Not recommended | A tool should start through the single Agent trigger |
Processor |
No | Reserved enum value without node implementation |