HTTP
Nodes in the HTTP section are used to integrate a scenario with external services. HTTP Request performs an outbound HTTP request during scenario execution, while HTTP Webhook starts a new scenario from an external HTTP POST.
1. HTTP Request
HTTP Request (HttpRequest) sends an outbound HTTP request to a CRM, ERP, your own backend, or another API, waits for the response, and converts it into variables for subsequent nodes.
Use HTTP Request when you need to:
- retrieve data from an external API;
- send data to a CRM, ERP, or your own backend;
- pass scenario variables through headers or a JSON body;
- check the HTTP result in a following
Condition; - use the API response in subsequent nodes or return it through
JSON output.
Settings
| Field | Meaning |
|---|---|
Url |
Full endpoint URL; supports #var and {{ JS }} |
Method |
Get=0, Post=1, Put=2, Patch=3, Delete=4 |
Headers |
Header dictionary; values support #var and {{ JS }} |
BodyTemplate |
UTF-8 application/json body; supports #var and {{ JS }} |
TimeoutMs |
Response timeout in milliseconds. Not set, 0, or negative uses the backend default of 100 s. Maximum 30 minutes. Applies to both sync and async modes |
AsyncRequest |
Runs the request in the background without waiting for the response; default false |
AsyncResponseAction |
Where the scenario continues after the background request completes; used only with AsyncRequest=true |
NextAction |
The single output |
The library default for Method is Post, but if the field is omitted from the API DTO, the C# enum default is Get. For that reason, it is better to always set the method explicitly.
Headers should also be sent at least as an empty object {}: null may cause a runtime error.
Connections
- Input: one standard connector.
- Output: one
NextAction. GETdoes not send a body.- For other methods, the backend sends the body as
application/json. - HTTP
4xx/5xxdoes not stop the node with an exception:isSuccess=false, then the flow continues throughNextAction. - A transport, DNS, or network exception is typically returned as status
-1,isSuccess=false, with the error text inreasonPhrase.
Output variables
After an HTTP response is received, or a transport error is handled, the node creates:
#node.{id}.http.rawBody
#node.{id}.http.statusCode
#node.{id}.http.reasonPhrase
#node.{id}.http.isSuccess
In async mode, the main branch also gets:
#node.{id}.http.queued
In sync mode, http.queued is absent or empty.
Top-level primitive fields from the JSON response and response headers also become outputs.
For example, this response:
{
"orderId": 501,
"status": "created"
}
for node ID 12 creates:
#node.12.orderId
#node.12.status
If a body field and a header use the same key, the header added later overwrites that value in the shared variables dictionary.
statusCode and isSuccess are stored as strings, but inside JS they are automatically converted to number/boolean values.
Variables and templates
Url, Headers values, and BodyTemplate support #var and {{ JS }}.
For example:
Url: https://api.example.com/cards?phone=#member.phone
Method: Post
Headers:
Authorization: Bearer #node.3.api_token
X-Member: #member.external_id
BodyTemplate:
{
"name": {{ JSON.stringify(#member.name) }},
"amount": {{ #node.8.amount }}
}
Async mode
When AsyncRequest is on, the node does not wait for the response. The request goes to a background worker and the scenario continues immediately. Only #node.{id}.http.queued = "True" is available right away; other http.* outputs are empty, and the following nodes cannot read the response of this node.
If AsyncResponseAction is set, the backend resumes the scenario from this action in the context of the same member after the background request completes: success, failure, or timeout. The response becomes available as the usual #node.{id}.http.* values and JSON fields, and the resulting screen is sent to the user.
If AsyncResponseAction is empty, the request is fire-and-forget: the response is only logged.
Example:
HTTP request (async, AsyncResponseAction -> node:31)
-> node:31
-> Condition "#node.12.http.isSuccess"
Test send
The editor can send a test request from an HTTP Request node without running the scenario. The result shows the response statusCode, reasonPhrase, headers, body, and the isSuccess flag.
If the URL, headers, or body template contains #var variables or {{ JS }} expressions, you can provide test values for them before sending. The editor suggests the variables available at this node; the values are substituted exactly like at runtime. Without test values, a missing variable is replaced with an empty string, the same rule as in regular templates.
Important details:
- A test request is a real HTTP call to the configured endpoint, not a sandbox. Requests that create or change data in the external system have a real effect.
- A test request does not start the scenario: no following nodes run, and no
#node.*output variables are created.
Example
HTTP Request
-> Condition "#node.12.http.isSuccess"
| true -> JSON processor / Screen / JSON output
| false -> fallback Screen / error JSON output
Important details
- An invalid or empty URL can fail before the internal transport-exception handling and end the execution as a node failure.
- There is no separate response-body size limit.
- JSON arrays are not expanded into individual outputs. Use
#node.{id}.http.rawBodyandparseJson(...)to work with them. - Header names containing hyphens may exist in the context, but
#varsyntax cannot read the full key. - Do not read
#node.{id}.http.*of an async node in the main branch. Use theAsyncResponseActionbranch instead. - Do not use untrusted user input as a URL: the current backend has no separate SSRF allowlist.
- Secrets in headers are stored inside the schema JSON and returned in the node DTO; this is not a secret vault.
HTTP Requestcan be used in a synchronous AI tool.
2. HTTP Webhook Soon
HTTP Webhook (HttpWebhook) starts a scenario from an external HTTP POST. It is intended for callbacks from a CRM, payment system, form, integration service, or another backend.
HTTP Webhookalready has a backend creation API and a runtime endpoint, but the current backend does not have anHttpWebhookNodeMapper. Because of this, the node is not returned in the common schema DTO response and is not yet fully available in the standard editor UI.
Settings
| Field | Meaning |
|---|---|
Slug |
Part of the webhook URL and also the node action; the backend stores the trimmed slug without a webhook: prefix |
Title |
Canvas title; if empty, the backend generates Webhook {slug} |
NextAction |
The single output |
Connections
HTTP Webhookis an entry point and has no normal input connector.- Output: one
NextAction. - After parsing the request body, the node continues execution through
NextAction.
Invocation
The backend supports two routes:
POST /webhook/{schemaId}/{slug}/{memberId}
POST /webhook/{schemaId}/{slug}
The route:
POST /webhook/{schemaId}/{slug}
has [AllowAnonymous].
The route with {memberId} inherits the BaseController authorization requirement and is not a public webhook endpoint.
The public route looks up a member by the top-level string field Phone in the JSON body. The field name is case-insensitive. Numeric, nested, or non-JSON values are not used as a phone number.
If a member is found, the scenario receives member variables and can display the next Screen to that member.
Output variables
The JSON body is stored as:
#webhook.body
Primitive body fields are also expanded into node variables.
For this body:
{
"orderId": 105,
"status": "paid"
}
node ID 7 creates:
#node.7.orderId
#node.7.status
The webhook always returns a simple response without a configurable response body. A business result must be sent through a following Screen or to an external system.
Example
HTTP Webhook "payment"
-> Condition status == paid
-> Screen / HTTP Request
Important details
- The public phone-based webhook does not verify a signature from the external system. If authenticity is required, it must be enforced at the gateway level or through additional integration logic.
- If
Phoneis missing, invalid, or no member is found, the phone route returns200 OKwithout starting a useful member flow. - The route with
{memberId}starts the chain with a syntheticUserContext(UserId="webhook"), so real member variables are not passed into the flow. - After a successful lookup, the phone route starts the chain with a real member context, stores the new screen state, and supports Telegram/Viber delivery.
- Changing
Slugfor an existingNodeIdmay leave the old action in the serialized chain because replacement is performed by action key. - Reusing the same slug may replace the node that already occupies that action.
- In many invalid or incomplete cases, the current controller returns
200 OKso the external system does not perform endless retries. - Arrays and some nested JSON structures have the same extractor limitations as
JSON processor. HTTP Webhookis an external entry point, so it is not recommended as a processing step inside a synchronous AI tool.