Conditional Node
The Conditional node provides multi-branch routing logic for your webhook pipeline. Define named branches with filters, and events are routed to the first matching branch — with an else path for events that match no branch.
Overview
The Conditional node evaluates named branches in order against the incoming event payload. Each branch has its own set of filters and output targets. The first branch whose filters match wins — the event is routed to that branch's output nodes. If no branch matches, the event falls through to the else path.
elseWebhookIds / elseTransformIds).Configuration
| Field | Type | Default | Description |
|---|---|---|---|
| name | string | — | Friendly label for the conditional |
| branches | Branch[] | — | Array of named branches evaluated in order (first match wins) |
| elseWebhookIds | string[] | [] | Webhook IDs for the else path (when no branch matches) |
| elseTransformIds | string[] | [] | Transform IDs for the else path |
| inputNodes | { nodeType, nodeId }[] | [] | Upstream nodes that feed this one. nodeType is the node kind (webhook, scheduledWorkflow, filter, …) |
| loopBackDelaySec | number | 0 | Seconds to wait before looping back — only when the taken branch points to a node that already ran in this run (0–300). See Looping back. |
| isActive | boolean | true | Whether the conditional is enabled |
Branch Object
| Field | Type | Description |
|---|---|---|
| name | string | Human-readable label for this branch (e.g. "High value") |
| filters | PayloadFilter[] | Array of filter conditions to evaluate against the payload |
| filterMode | 'and' | 'or' | How to combine filters — all must match (and) or any (or) |
| outputNodes | string[] | Node IDs to route to when this branch matches |
| outputWebhookIds | string[] | Webhook IDs to route to when this branch matches |
| outputTransformIds | string[] | Transform IDs to route to when this branch matches |
Create a Conditional
Define branches with filters and output targets. The first branch whose filters match wins. Use elseWebhookIds and elseTransformIds for events that match no branch.
curl -X POST /api/conditionals \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "<your-workspace-id>",
"name": "Payment Amount Router",
"branches": [
{
"name": "High value",
"filters": [
{ "field": "data.object.amount", "operator": "gt", "value": "5000" }
],
"filterMode": "and",
"outputNodes": ["delay_6655aaa", "discord_6655bbb"],
"outputWebhookIds": [],
"outputTransformIds": []
},
{
"name": "Standard",
"filters": [
{ "field": "data.object.amount", "operator": "lte", "value": "5000" }
],
"filterMode": "and",
"outputNodes": [],
"outputWebhookIds": ["ep_standard_processing"],
"outputTransformIds": []
}
],
"elseWebhookIds": ["ep_fallback"],
"elseTransformIds": [],
"inputNodes": [{ "nodeType": "webhook", "nodeId": "6654a1b2c3d4e5f6a7b8c9d0" }],
"isActive": true
}'Response
{
"_id": "6655b8c9d0e1f2a3b4c5d6e7",
"name": "Payment Amount Router",
"branches": [
{
"name": "High value",
"filters": [
{ "field": "data.object.amount", "operator": "gt", "value": "5000" }
],
"filterMode": "and",
"outputNodes": ["delay_6655aaa", "discord_6655bbb"],
"outputWebhookIds": [],
"outputTransformIds": []
},
{
"name": "Standard",
"filters": [
{ "field": "data.object.amount", "operator": "lte", "value": "5000" }
],
"filterMode": "and",
"outputNodes": [],
"outputWebhookIds": ["ep_standard_processing"],
"outputTransformIds": []
}
],
"elseWebhookIds": ["ep_fallback"],
"elseTransformIds": [],
"inputNodes": [{ "nodeType": "webhook", "nodeId": "6654a1b2c3d4e5f6a7b8c9d0" }],
"isActive": true,
"ownerId": "org_abc123",
"createdAt": "2025-05-01T12:00:00.000Z",
"updatedAt": "2025-05-01T12:00:00.000Z"
}Update a Conditional
curl -X PATCH /api/conditionals/6655b8c9d0e1f2a3b4c5d6e7 \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"branches": [
{
"name": "VIP",
"filters": [
{ "field": "data.object.amount", "operator": "gt", "value": "50000" }
],
"filterMode": "and",
"outputNodes": ["delay_6655aaa", "discord_6655bbb"],
"outputWebhookIds": [],
"outputTransformIds": []
},
{
"name": "Standard",
"filters": [
{ "field": "data.object.amount", "operator": "lte", "value": "50000" }
],
"filterMode": "and",
"outputNodes": [],
"outputWebhookIds": ["ep_standard_processing"],
"outputTransformIds": []
}
],
"elseWebhookIds": ["ep_fallback"]
}'Looping back (polling)
A branch — or the else path — can point to a node that already ran earlier in the flow. When it does, the flow loops: that node runs again, its output comes back to the Conditional, and the branches are evaluated again. This is how you poll an external job until it finishes:
Start job → Check status → Loop Until Complete (Conditional)
▲ │ branch "Done": status is SUCCEEDED → Notify
└──── else ──────────┘Every pass of a node inside the loop shows up as its own step, in the Run Pipeline modal and in the run history, labeled iteration 2 · back from Loop Until Complete, iteration 3 · … and so on. There is no total — how many passes it takes depends on the external service.
Waiting between passes
A loop back runs immediately by default. A status check takes milliseconds, so without a wait the loop would spin through its whole budget in a couple of seconds while the job is still running. Two ways to wait, and they combine:
- Wait before looping back (
loopBackDelaySec) on the Conditional itself: how many seconds to wait before sending the flow back. It only applies when the taken branch points to a node that already ran — branches that continue forward never wait. Up to 5 minutes. - A Delay node inside the loop (else → Delay → Check status). Use it for waits longer than 5 minutes: a Delay is queued, so it survives a restart of the engine.
The cycle budget
A step can run at most 10 times in one event on Free, and 100 times on Starter, Pro and Enterprise. It is set by your plan and you can't change it; Settings → Workspaces shows yours. When a loop reaches it, that branch stops there and the run says why: the step shows up in Run History as "Stopped: a step ran 100 times in one event (Pro limit)", and in Run Pipeline the node turns red with the same message. The account owner also gets an email, at most once a day for each flow.
If you hit it, add a wait (see above) or check the branch rules — the loop only ends when a branch that continues forward matches.
until) is not waited for in Run Pipeline at all.Canvas Integration
On the canvas, the Conditional node renders with one outgoing edge per branch (labeled with the branch name) and an additional dashed edge labeled "else" for the fallback path. The canvas type is conditional with blue styling.
{
"id": "conditional-6655b8c9d0e1f2a3b4c5d6e7",
"type": "conditional",
"position": { "x": 400, "y": 200 },
"data": {
"label": "Payment Amount Router",
"conditionalId": "6655b8c9d0e1f2a3b4c5d6e7",
"branchCount": 2,
"hasElse": true,
"isActive": true
}
}Payload Examples
Branch 1 matches — high value
{
"type": "payment_intent.succeeded",
"data": {
"object": {
"amount": 25000,
"currency": "usd",
"customer": "cus_vip123"
}
}
}
// amount (25000) > 5000 -> matches "High value" branch
// -> routed to delay_6655aaa -> discord_6655bbbBranch 2 matches — standard
{
"type": "payment_intent.succeeded",
"data": {
"object": {
"amount": 3500,
"currency": "usd",
"customer": "cus_regular456"
}
}
}
// amount (3500) <= 5000 -> matches "Standard" branch
// -> routed to ep_standard_processingNo branch matches — else path
{
"type": "payment_intent.failed",
"data": {
"object": {
"error": "card_declined"
}
}
}
// no "amount" field -> no branch matches
// -> routed to elseWebhookIds (ep_fallback)Use Cases
- Amount thresholds — Route high-value transactions to a VIP processing pipeline and standard ones to the regular flow.
- Feature gating — Check for a feature flag field in the payload and route to different processing versions.
- Error handling — Check if the payload contains an error field; route errors to an error handler and successes to the main pipeline.
- A/B testing — Split events based on a user segment field to test different processing logic.
- Region-based routing — Route events to US or EU processing webhooks based on a region field.
API Reference
The Conditional node has its own API endpoints:
| Method | Webhook | Description |
|---|---|---|
| GET | /api/conditionals | List all conditionals |
| POST | /api/conditionals | Create a new conditional |
| GET | /api/conditionals/:id | Get a specific conditional |
| PATCH | /api/conditionals/:id | Update a conditional |
| DELETE | /api/conditionals/:id | Delete a conditional |
filterMode: "and" when all conditions in a branch must be true, or "or" when any single condition is enough to match.outputNodes for connecting to any node type (delays, Discord actions, etc.) in addition to outputWebhookIds and outputTransformIds for direct webhook/transform routing.