Skip to main content

Condition Step

The Condition step adds branching logic to your flows by evaluating conditions using the rules engine. Based on the conditions you define, the flow routes to different next steps—or terminates with success or error.
How Conditions Work: The Condition step uses the same rules engine as the Rules step, but instead of calculating values, it routes the flow based on which condition matches first. Conditions are checked top-to-bottom until one matches.

How It Works

The Condition step evaluates conditions in sequence and routes to the outcome of the first matching condition:
Previous Step

Condition: Is amount > 1000?
↓ (true)           ↓ (false)
High Value Step    Standard Step

Configuration

Facts

Just like the Rules step, you define facts that will be evaluated by the conditions. Facts are populated using variable mapping from previous steps:
{
  "orderTotal": "$.checkout_step.total",
  "customerTier": "$.customer_lookup.tier",
  "agentDecision": "$.support_agent.output.decision",
  "confidence": "$.support_agent.output.confidence"
}
Fact keys don’t need the .value suffix in the Condition step—the system handles this automatically.

Conditions Array

Conditions are evaluated top-to-bottom. The first matching condition’s outcome is used:
{
  "conditions": [
    {
      "condition": {
        "operator": "and",
        "input": [
          {"operator": ">", "input": ["@fact:orderTotal", 10000]},
          {"operator": "=", "input": ["@fact:customerTier", "enterprise"]}
        ]
      },
      "outcome": "enterprise_handler_step_id"
    },
    {
      "condition": {
        "operator": ">",
        "input": ["@fact:orderTotal", 1000]
      },
      "outcome": "business_handler_step_id"
    },
    {
      "outcome": "standard_handler_step_id"
    }
  ]
}
Order matters! Place most specific conditions first, more general conditions last. The first matching condition wins.

Special Outcomes

Instead of routing to another step, you can terminate the flow:
  • "RESOLVE_SUCCESS" - End the flow successfully
  • "RESOLVE_ERROR" - End the flow with an error
{
  "conditions": [
    {
      "condition": {
        "operator": "=",
        "input": ["@fact:validationStatus", "valid"]
      },
      "outcome": "processing_step_id"
    },
    {
      "outcome": "RESOLVE_ERROR"
    }
  ]
}

Condition Syntax

Conditions use the same operator-based syntax as the Rules step. See the Rules Operations Reference for all available operators.

Basic Comparisons

// Equality
{
  "operator": "=",
  "input": ["@fact:status", "approved"]
}

// Inequality
{
  "operator": "!=",
  "input": ["@fact:status", "pending"]
}

// Greater than
{
  "operator": ">",
  "input": ["@fact:amount", 1000]
}

// Less than or equal
{
  "operator": "<=",
  "input": ["@fact:score", 100]
}

Logical Operators

// AND - All conditions must be true
{
  "operator": "and",
  "input": [
    {"operator": ">", "input": ["@fact:amount", 1000]},
    {"operator": "=", "input": ["@fact:tier", "gold"]}
  ]
}

// OR - At least one condition must be true
{
  "operator": "or",
  "input": [
    {"operator": "=", "input": ["@fact:status", "urgent"]},
    {"operator": "=", "input": ["@fact:priority", "high"]}
  ]
}

// NOT - Invert condition
{
  "operator": "not",
  "input": [
    {"operator": "=", "input": ["@fact:approved", true]}
  ]
}

Null Checks

// Check if value exists
{
  "operator": "notEmpty",
  "input": ["@fact:email"]
}

// Check if value is empty/null
{
  "operator": "isEmpty",
  "input": ["@fact:optionalField"]
}

String Operations

// Contains substring
{
  "operator": "includes",
  "input": ["@fact:message", "refund"]
}

// Starts with
{
  "operator": "startsWith",
  "input": ["@fact:email", "admin@"]
}

// Ends with
{
  "operator": "endsWith",
  "input": ["@fact:filename", ".pdf"]
}

// Case-insensitive comparison
{
  "operator": "=",
  "input": [
    {"operator": "toLower", "input": ["@fact:category"]},
    "support"
  ]
}

Array Operations

// Check if array contains value
{
  "operator": "in",
  "input": ["@fact:selectedTag", "@fact:availableTags"]
}

// Check array length
{
  "operator": ">",
  "input": [
    {"operator": "size", "input": ["@fact:items"]},
    0
  ]
}

Common Patterns

Route based on agent’s structured output decisionFacts:
{
  "decision": "$.support_agent.output.decision",
  "confidence": "$.support_agent.output.confidence"
}
Conditions:
[
  {
    "condition": {
      "operator": "=",
      "input": ["@fact:decision", "approve"]
    },
    "outcome": "approval_flow_step"
  },
  {
    "condition": {
      "operator": "=",
      "input": ["@fact:decision", "reject"]
    },
    "outcome": "rejection_flow_step"
  },
  {
    "condition": {
      "operator": "=",
      "input": ["@fact:decision", "escalate"]
    },
    "outcome": "human_review_step"
  },
  {
    "outcome": "error_handler_step"
  }
]
Route based on numeric thresholdsFacts:
{
  "orderTotal": "$.order.total"
}
Conditions:
[
  {
    "condition": {
      "operator": ">=",
      "input": ["@fact:orderTotal", 10000]
    },
    "outcome": "enterprise_sales_step"
  },
  {
    "condition": {
      "operator": ">=",
      "input": ["@fact:orderTotal", 1000]
    },
    "outcome": "business_sales_step"
  },
  {
    "condition": {
      "operator": ">=",
      "input": ["@fact:orderTotal", 0]
    },
    "outcome": "self_service_step"
  },
  {
    "outcome": "RESOLVE_ERROR"
  }
]
Check multiple criteria before proceedingFacts:
{
  "email": "$.form.email",
  "age": "$.form.age",
  "termsAccepted": "$.form.terms_accepted"
}
Conditions:
[
  {
    "condition": {
      "operator": "and",
      "input": [
        {"operator": "notEmpty", "input": ["@fact:email"]},
        {"operator": "includes", "input": ["@fact:email", "@"]},
        {"operator": ">=", "input": ["@fact:age", 18]},
        {"operator": "=", "input": ["@fact:termsAccepted", true]}
      ]
    },
    "outcome": "validated_processing_step"
  },
  {
    "outcome": "validation_failed_step"
  }
]
Route based on status or categoryFacts:
{
  "customerStatus": "$.customer.status",
  "customerTier": "$.customer.tier"
}
Conditions:
[
  {
    "condition": {
      "operator": "=",
      "input": ["@fact:customerStatus", "new"]
    },
    "outcome": "new_customer_flow_step"
  },
  {
    "condition": {
      "operator": "=",
      "input": ["@fact:customerTier", "vip"]
    },
    "outcome": "vip_flow_step"
  },
  {
    "condition": {
      "operator": "=",
      "input": ["@fact:customerStatus", "returning"]
    },
    "outcome": "returning_customer_flow_step"
  },
  {
    "outcome": "standard_flow_step"
  }
]
Route based on AI confidence scoresFacts:
{
  "confidence": "$.agent.output.confidence",
  "decision": "$.agent.output.decision"
}
Conditions:
[
  {
    "condition": {
      "operator": ">=",
      "input": ["@fact:confidence", 0.9]
    },
    "outcome": "auto_approve_step"
  },
  {
    "condition": {
      "operator": ">=",
      "input": ["@fact:confidence", 0.6]
    },
    "outcome": "manager_review_step"
  },
  {
    "condition": {
      "operator": "<",
      "input": ["@fact:confidence", 0.6]
    },
    "outcome": "senior_review_step"
  },
  {
    "outcome": "RESOLVE_ERROR"
  }
]
Validate data and route errors appropriatelyFacts:
{
  "apiStatus": "$.http_request.status",
  "hasData": "$.http_request.data"
}
Conditions:
[
  {
    "condition": {
      "operator": "and",
      "input": [
        {"operator": "=", "input": ["@fact:apiStatus", 200]},
        {"operator": "notEmpty", "input": ["@fact:hasData"]}
      ]
    },
    "outcome": "success_processing_step"
  },
  {
    "condition": {
      "operator": "and",
      "input": [
        {"operator": ">=", "input": ["@fact:apiStatus", 400]},
        {"operator": "<", "input": ["@fact:apiStatus", 500]}
      ]
    },
    "outcome": "client_error_handler_step"
  },
  {
    "condition": {
      "operator": ">=",
      "input": ["@fact:apiStatus", 500]
    },
    "outcome": "server_error_handler_step"
  },
  {
    "outcome": "RESOLVE_ERROR"
  }
]
Verify required fields exist before processingFacts:
{
  "name": "$.form.name",
  "email": "$.form.email",
  "phone": "$.form.phone",
  "address": "$.form.address"
}
Conditions:
[
  {
    "condition": {
      "operator": "and",
      "input": [
        {"operator": "notEmpty", "input": ["@fact:name"]},
        {"operator": "notEmpty", "input": ["@fact:email"]},
        {"operator": "notEmpty", "input": ["@fact:phone"]},
        {"operator": "notEmpty", "input": ["@fact:address"]}
      ]
    },
    "outcome": "complete_data_processing_step"
  },
  {
    "outcome": "missing_fields_error_step"
  }
]

Best Practices

Always Have Default

Always include a final condition with no condition expression (just {"outcome": "..."}) to handle unexpected values.

Order Matters

Conditions are evaluated top-to-bottom. Put most specific conditions first, most general last.

Use Agent Output Schemas

When routing based on agent decisions, use output schemas for clean, predictable conditions.

Test All Branches

Test each condition path with appropriate test data to ensure all outcomes work correctly.

Keep It Simple

For very complex logic, consider using a Rules step to calculate intermediate values, then use a Condition step for routing.

Document Branches

Use clear, descriptive names for outcome steps so the flow is easy to understand.

When to Use Conditions vs. Rules

Use Condition WhenUse Rules When
Need to route flow to different stepsNeed to calculate values
Binary or multi-way branchingComplex calculations or transformations
Flow termination neededData reshaping needed
Decision → Action mappingMultiple derived values needed
Example: Use Condition for: “If approved, go to approval step. If rejected, go to rejection step.” Use Rules for: “Calculate discount percentage based on order total, customer tier, and region.” Often you’ll use Rules step → Condition step together:
  1. Rules step calculates complex values
  2. Condition step routes based on those calculated values

Complete Example

Here’s a complete example showing Facts, Conditions, and routing: Scenario: Route customer support requests based on agent analysis Step Configuration:
{
  "facts": {
    "requestType": "$.support_agent.output.type",
    "priority": "$.support_agent.output.priority",
    "confidence": "$.support_agent.output.confidence",
    "requiresHuman": "$.support_agent.output.requires_human"
  },
  "conditions": [
    {
      "condition": {
        "operator": "=",
        "input": ["@fact:requiresHuman", true]
      },
      "outcome": "human_review_step_id"
    },
    {
      "condition": {
        "operator": "and",
        "input": [
          {"operator": "=", "input": ["@fact:requestType", "refund"]},
          {"operator": ">=", "input": ["@fact:confidence", 0.8]}
        ]
      },
      "outcome": "refund_processing_step_id"
    },
    {
      "condition": {
        "operator": "and",
        "input": [
          {"operator": "=", "input": ["@fact:requestType", "technical"]},
          {"operator": ">=", "input": ["@fact:confidence", 0.8]}
        ]
      },
      "outcome": "technical_support_step_id"
    },
    {
      "condition": {
        "operator": "=",
        "input": ["@fact:priority", "urgent"]
      },
      "outcome": "urgent_escalation_step_id"
    },
    {
      "condition": {
        "operator": "<",
        "input": ["@fact:confidence", 0.6]
      },
      "outcome": "low_confidence_review_step_id"
    },
    {
      "outcome": "standard_support_step_id"
    }
  ]
}
Flow Routing:
  1. If agent says human required → Human review
  2. If refund with high confidence → Auto-process refund
  3. If technical with high confidence → Technical support flow
  4. If marked urgent → Urgent escalation
  5. If low confidence → Manual review
  6. Default → Standard support queue

Troubleshooting

Possible causes:
  • No conditions matched and no default outcome
  • Fact reference is incorrect
  • Data type mismatch
  • Variable mapping failed
Solutions:
  • Always add a default condition with no condition expression
  • Verify fact keys match your facts object
  • Check data types (comparing string to number won’t match)
  • Verify previous step output contains expected data
  • Add logging steps before condition to inspect values
Possible causes:
  • Condition order wrong (earlier condition matched first)
  • Logical operator error (AND vs. OR)
  • Data type mismatch
  • Operator precedence unexpected
Solutions:
  • Reorder conditions (most specific first)
  • Verify logical operators are correct
  • Check data types match (use type conversion if needed)
  • Test each condition individually
  • Add logging to see which condition matched
Possible causes:
  • Fact doesn’t exist or is null
  • Variable mapping returned unexpected format
  • Case sensitivity issue
  • Whitespace in data
Solutions:
  • Check previous step output structure
  • Add null checks using notEmpty operator
  • Use toLower for case-insensitive comparison
  • Use trim operator to remove whitespace
  • Verify variable mapping path is correct
Possible causes:
  • Variable mapping didn’t extract nested value
  • Fact contains full object instead of specific property
Solutions:
  • Use JSONPath in variable mapping to extract specific property: $.step.output.nested.property
  • If fact contains object, use jPath operator in condition to access nested value
  • Consider using Map step before Condition to flatten data

Tips for Better Conditions

1

Map facts carefully

Use variable mapping to extract exactly the values you need. Make facts simple values when possible.
2

Start simple

Begin with basic conditions. Add complexity only when needed.
3

Use structured agent output

Define output schemas on agents for clean, predictable routing decisions.
4

Test all paths

Test each branch with appropriate test data to verify routing works correctly.
5

Handle null values

Always check for null/empty before comparing values using notEmpty or isEmpty.
6

Consider Rules + Condition

For complex logic, use Rules step to calculate, then Condition step to route based on results.

Next Steps