Skip to content

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.
  • GET does not send a body.
  • For other methods, the backend sends the body as application/json.
  • HTTP 4xx / 5xx does not stop the node with an exception: isSuccess=false, then the flow continues through NextAction.
  • A transport, DNS, or network exception is typically returned as status -1, isSuccess=false, with the error text in reasonPhrase.

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.rawBody and parseJson(...) to work with them.
  • Header names containing hyphens may exist in the context, but #var syntax cannot read the full key.
  • Do not read #node.{id}.http.* of an async node in the main branch. Use the AsyncResponseAction branch 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 Request can 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 Webhook already has a backend creation API and a runtime endpoint, but the current backend does not have an HttpWebhookNodeMapper. 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 Webhook is 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 Phone is missing, invalid, or no member is found, the phone route returns 200 OK without starting a useful member flow.
  • The route with {memberId} starts the chain with a synthetic UserContext (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 Slug for an existing NodeId may 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 OK so the external system does not perform endless retries.
  • Arrays and some nested JSON structures have the same extractor limitations as JSON processor.
  • HTTP Webhook is an external entry point, so it is not recommended as a processing step inside a synchronous AI tool.