Flow Studio
Outbound Webhook Call
The WebhookCallNode — sending HTTP requests to external URLs, capturing response body/status/headers as node output.
Node Config
{
"nodeType": "WebhookCall",
"config": {
"url": "https://partner.example.com/api/notify",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"X-Api-Key": "$env.PARTNER_API_KEY"
},
"body": {
"orderId": "$output.createOrder.orderId",
"status": "confirmed",
"total": "$output.calculateTotal.total"
},
"timeoutSeconds": 30,
"followRedirects": true,
"validateStatusCodes": [200, 201, 202]
}
}
Node Output Shape
{
"statusCode": 200,
"statusText": "OK",
"body": { "accepted": true, "referenceId": "ref-xyz" },
"headers": {
"content-type": "application/json",
"x-request-id": "req-abc"
},
"elapsedMs": 145
}
Access in downstream expressions:
$output.notifyPartner.statusCode // → 200
$output.notifyPartner.body.referenceId // → "ref-xyz"
$output.notifyPartner.headers["x-request-id"] // → "req-abc"
Executor
[NodeCapability(CapabilityType.Webhook)]
public class WebhookCallExecutor : BaseNodeExecutor
{
private readonly IHttpClientFactory _httpFactory;
public override async Task<NodeExecutionResult> ExecuteAsync(NodeExecutionContext ctx)
{
var config = ctx.GetConfig<WebhookCallConfig>();
var url = ctx.EvaluateExpression<string>(config.Url);
var body = ctx.EvaluateExpression<object>(config.Body);
var headers = config.Headers.ToDictionary(
h => h.Key,
h => ctx.EvaluateExpression<string>(h.Value));
var client = _httpFactory.CreateClient("webhook");
var sw = Stopwatch.StartNew();
var response = await client.SendAsync(BuildRequest(url, config.Method, headers, body));
sw.Stop();
var responseBody = await response.Content.ReadFromJsonAsync<object>();
var output = new
{
statusCode = (int)response.StatusCode,
statusText = response.ReasonPhrase,
body = responseBody,
headers = response.Headers.ToDictionary(h => h.Key.ToLower(), h => h.Value.First()),
elapsedMs = (int)sw.ElapsedMilliseconds
};
if (config.ValidateStatusCodes?.Contains((int)response.StatusCode) == false)
return NodeExecutionResult.Success(output, portKey: "error");
return NodeExecutionResult.Success(output);
}
}
Status Code Routing
The validateStatusCodes config defines which status codes are treated as success. Any other status code routes to the error port (with the full response still available in output for inspection).