Skip to main content

Understanding Facts

Facts are the input data for your rules - a flat key-value object where keys are unique identifiers and values are the data to evaluate.

Fact Structure

{
  "factKey": "value or variable mapping expression"
}

Static Facts

Hard-coded values that don’t change

Dynamic Facts

Values pulled from previous steps using variable mapping

Static Facts

Static facts have hard-coded values:
{
  "minAge.value": 18,
  "shippingThreshold.value": 50,
  "defaultTier.value": "bronze",
  "isActive.value": true
}

Dynamic Facts with Variable Mapping

Most facts in real flows pull data from previous steps using variable mapping:
{
  "orderTotal.value": "$.NODE_ID.checkout.total", // from previous step
  "customerEmail.value": "$.trigger.email" // from trigger event
}
When the Rules step executes, all variable mapping expressions are resolved first, converting your facts into actual values before any rules are evaluated. Learn more about variable mapping

Fact Naming Conventions

Fact keys can be any valid JSON key, but we recommend using descriptive names with a property suffix:
{
  "orderTotal.value": 150,
  "orderTotal.formatted": "$150.00",
  "orderTotal.withTax": 165,
  "customer.firstName": "John",
  "customer.lastName": "Smith"
}
Why use property suffixes? Using consistent suffixes like .value makes your rules more readable and allows you to create multiple related calculations from the same base concept.

Referencing Facts in Rules

Reference facts in your rules using the @fact: prefix followed by the exact fact key:
{
  "discount.value": {
    "operator": "*",
    "input": ["@fact:orderTotal.value", 0.10]
  }
}

Understanding Rules

Rules define the logic for calculating outcomes based on your facts. Rules are structured as key-value pairs where the key is the rule name and the value defines how to calculate it.

Simple Rule Format

Use simple format for direct calculations without conditions:
{
  "ruleName.property": {
    "operator": "operatorName",
    "input": [param1, param2, ...]
  }
}
Example - Calculate total:
{
  "total.value": {
    "operator": "+",
    "input": ["@fact:subtotal.value", "@fact:tax.value"]
  }
}

Conditional Rule Format

Use conditional format when the outcome depends on conditions - an array of condition/outcome pairs evaluated top to bottom:
{
  "ruleName.property": [
    {
      "condition": {
        "operator": "operatorName",
        "input": [...]
      },
      "outcome": "value if condition is true"
    },
    {
      "condition": {
        "operator": "operatorName",
        "input": [...]
      },
      "outcome": "value if condition is true"
    },
    {
      "outcome": "default value"
    }
  ]
}
Example - Tiered discount:
{
  "discount.value": [
    {
      "condition": {
        "operator": ">=",
        "input": ["@fact:orderTotal.value", 200]
      },
      "outcome": 0.15
    },
    {
      "condition": {
        "operator": "between",
        "input": ["@fact:orderTotal.value", 100, 199]
      },
      "outcome": 0.10
    },
    {
      "outcome": 0
    }
  ]
}
Conditions are evaluated top to bottom: The first matching condition wins and its outcome is returned. Always put more specific conditions before general ones, and include a default outcome without a condition at the end.

Nested Operations

You can nest operations within the input array to create complex calculations:
{
  "finalPrice.value": {
    "operator": "-",
    "input": [
      "@fact:orderTotal.value",
      {
        "operator": "*",
        "input": [
          "@fact:orderTotal.value",
          "@fact:discountRate.value"
        ]
      }
    ]
  }
}
This calculates: orderTotal - (orderTotal * discountRate)

Rules Referencing Rules

Rules can reference the outcomes of other rules using @fact:ruleName:
{
  "subtotal.value": {
    "operator": "+",
    "input": [
        "@fact:item1.value",
        "@fact:item2.value"
    ]
  },
  "tax.value": {
    "operator": "*",
    "input": ["@fact:subtotal.value", 0.08]
  },
  "total.value": {
    "operator": "+",
    "input": ["@fact:subtotal.value", "@fact:tax.value"]
  }
}
Rule order doesn’t matter! The Rules engine automatically determines the correct evaluation order based on dependencies. You can define rules in any sequence.

Operators

Operators are the functions that manipulate your data. The Rules engine includes operators for math, comparisons, logic, strings, arrays, dates, and more.

Operator Categories

Basic: +, -, *, /, ^, %
Rounding: round, ceil, floor, trunc, toFixed
Advanced: min, max, log, baseLog, numberFormat
Big Numbers: addBig, subtractBig, multiplyBig, divideBig
Equality: = (equal), != (notEqual)
Magnitude: >, >=, <, <=
Range: between, notBetween
Boolean: and, or, not
Existence: empty, notEmpty
Manipulation: concat, join, substring, split
Formatting: stringTemplate, numberFormat
Searching: startsWith, endsWith, stringContains, stringNotContains
Creation: generateArray, concatArray
Searching: arrayContains, arrayNotContains, inArray, notInArray
Transformation: sort, sortString, arrayFilter
Processing: Use wildcards like @fact:items.value/*/price
Current: today, now, timeNow
Calculation: addDate, subtractDate, dateDiff
Formatting: dateFormat, toISO
Key-Value: map / lookup
Membership: inOptions / options-in, in, notIn
Sets: isSubset, isNotSubset, setUnion, setIntersection, setDifference
Parsing: jsonParse, jsonStringify
Querying: jPath for JSONPath queries like $.items[0].name

Full Operations Reference

See the complete operations reference with syntax, parameters, and examples for every operator

Array Processing with JSONPath

The Rules engine supports processing arrays using JSONPath queries via the jPath operator.

Learn more about JSONPath

Learn about variable mapping with JSONPath and other data transformations using jPath references and queries

JSONPath Syntax

Use jPath to extract values from literal array objects:
{
  "operator": "jPath",
  "input": [arrayData, jsonPathQuery]
}

Example: Extract Array Values

Extract prices from a cart items array:
{
  "cartItems.value": [
    { "name": "Widget", "price": 29.99, "quantity": 2 },
    { "name": "Gadget", "price": 49.99, "quantity": 1 }
  ]
}
Rules:
{
  "prices.value": {
    "operator": "jPath",
    "input": ["@fact:cartItems.value", "$[*].price"]
  },
  "totalPrice.value": {
    "operator": "+",
    "input": "@fact:prices.value"
  }
}
Output:
{
  "prices.value": [29.99, 49.99],
  "totalPrice.value": 79.98
}

Example: Element-by-Element Operations

Calculate line totals by multiplying price × quantity for each item:
{
  "prices.value": {
    "operator": "jPath",
    "input": ["@fact:cartItems.value", "$[*].price"]
  },
  "quantities.value": {
    "operator": "jPath",
    "input": ["@fact:cartItems.value", "$[*].quantity"]
  },
  "lineTotals.value": {
    "operator": "*",
    "input": ["@fact:prices.value", "@fact:quantities.value"]
  }
}
Output:
{
  "prices.value": [29.99, 49.99],
  "quantities.value": [2, 1],
  "lineTotals.value": [59.98, 49.99]
}
When both inputs to a math operator are arrays of the same length, they’re processed element-by-element: prices[0] * quantities[0], prices[1] * quantities[1], etc.

Common JSONPath Patterns

PatternDescriptionExample
$[*]All array elementsGet entire array
$[*].propertyNameProperty from all elements$[*].price
$.0 or $[0]First elementGet first item
$[-1]Last elementGet last item
$[0:3]Array sliceFirst 3 items

Alternative: Wildcard Syntax

Rules also support a wildcard syntax (@fact:items/*/property) for working with flattened key-value structures. This is an advanced feature most users won’t need.Flattened structure:
{
  "cartItems": "Widget,Gadget,Tool",
  "cartItems/Widget/price": 29.99,
  "cartItems/Widget/quantity": 2,
  "cartItems/Gadget/price": 49.99,
  "cartItems/Gadget/quantity": 1
}
Using wildcard:
{
  "totalQuantity.value": {
    "operator": "+",
    "input": "@fact:cartItems/*/quantity"
  }
}
Most users should use literal arrays with jPath queries instead, as shown in the primary examples above.

Data Flow & Evaluation

Understanding how the Rules engine processes your facts and rules:
1

Variable Mapping Resolution

All facts with variable mapping expressions are resolved first, pulling data from previous steps in your flow
2

Dependency Analysis

The engine analyzes which rules depend on which facts and other rules
3

Evaluation Order

Rules are evaluated in dependency order - a rule that references another rule’s outcome waits for that rule to complete first
4

Condition Evaluation

For conditional rules, conditions are checked top to bottom, and the first matching condition’s outcome is returned
5

Output Generation

All rule outcomes are collected into a flat object matching your rule names

Example Flow

// Facts (after variable mapping resolution)
{
  "price.value": 100,
  "quantity.value": 3
}

// Rules
{
  "subtotal.value": {
    "operator": "*",
    "input": ["@fact:price.value", "@fact:quantity.value"]
  },
  "tax.value": {
    "operator": "*",
    "input": ["@fact:subtotal.value", 0.08]
  },
  "total.value": {
    "operator": "+",
    "input": ["@fact:subtotal.value", "@fact:tax.value"]
  }
}

// Evaluation order (automatic)
// 1. subtotal.value = 100 * 3 = 300
// 2. tax.value = 300 * 0.08 = 24
// 3. total.value = 300 + 24 = 324

// Output
{
  "subtotal.value": 300,
  "tax.value": 24,
  "total.value": 324
}

Best Practices

Use Descriptive Names

Name facts and rules clearly: customerAge.value not ca

Be Consistent

Use the same property suffixes throughout: always .value, not mixing .value and .val

Keep Rules Simple

Break complex logic into multiple small rules rather than one giant rule

Add Comments

Use descriptive rule names as self-documentation: qualifiesForPremiumDiscount explains itself

Test Incrementally

Add rules one at a time and test each in the Flow Debugger

Provide Defaults

Always include a default outcome in conditional rules to handle unexpected cases

What’s Next?

Need Help? Visit our Help Center or join the Community for support.