Skip to main content

Overview

This guide shows you battle-tested patterns for solving common business logic problems with Rules. Each pattern includes complete, copy-paste ready code and explains when to use it.
Copy and adapt: These patterns are designed to be copied and modified for your specific use case. Change the fact names, values, and logic to match your needs.

Tiered Calculations

Apply different values based on thresholds - perfect for pricing, discounts, shipping rates, or service levels.

Pattern: Volume Discount

Apply progressively larger discounts based on order size.
{
  "orderTotal.value": 250
}
Key principle: Order conditions from most specific (highest threshold) to least specific. Using between with INCLUSIVE_LEFT ensures exact values like $100 or $200 get the correct tier without ambiguity.
Use this pattern for:
  • Volume discounts
  • Shipping rates by weight/distance
  • Service level pricing (Basic/Pro/Enterprise)
  • Progressive tax rates
  • Priority levels based on value

Pattern: Customer Tier Benefits

Map customer tiers to different benefit levels.
{
  "tierDiscount.value": {
    "operator": "map",
    "input": [
      "@fact:customerTier.value",
      {
        "bronze": 0.05,
        "silver": 0.10,
        "gold": 0.15,
        "platinum": 0.20
      },
      0
    ]
  },
  "freeShipping.value": {
    "operator": "inArray",
    "input": [
      "@fact:customerTier.value",
      ["gold", "platinum"]
    ]
  },
  "prioritySupport.value": {
    "operator": "=",
    "input": ["@fact:customerTier.value", "platinum"]
  }
}
Use this pattern for:
  • Membership benefits
  • Access levels
  • Feature flags by plan
  • Support priority

Validation Rules

Check if data meets business requirements and provide clear feedback.

Pattern: Required Field Validation

Ensure critical fields are completed.
{
  "hasEmail.value": {
    "operator": "notEmpty",
    "input": ["@fact:email.value"]
  },
  "hasPhone.value": {
    "operator": "notEmpty",
    "input": ["@fact:phone.value"]
  },
  "hasAddress.value": {
    "operator": "and",
    "input": [
      {"operator": "notEmpty", "input": ["@fact:street.value"]},
      {"operator": "notEmpty", "input": ["@fact:city.value"]},
      {"operator": "notEmpty", "input": ["@fact:zipCode.value"]}
    ]
  },
  "isValid.value": {
    "operator": "and",
    "input": [
      "@fact:hasEmail.value",
      "@fact:hasPhone.value",
      "@fact:hasAddress.value"
    ]
  }
}
Use this pattern for:
  • Form validation
  • Data quality checks
  • Required fields enforcement
  • Pre-submission verification

Pattern: Range Validation

Check if values fall within acceptable ranges.
{
  "quantityValid.value": {
    "operator": "between",
    "input": ["@fact:quantity.value", 1, 100]
  },
  "priceValid.value": {
    "operator": "and",
    "input": [
      {"operator": ">", "input": ["@fact:price.value", 0]},
      {"operator": "<=", "input": ["@fact:price.value", 10000]}
    ]
  },
  "ageValid.value": {
    "operator": "between",
    "input": ["@fact:age.value", 18, 120]
  },
  "allValid.value": {
    "operator": "and",
    "input": [
      "@fact:quantityValid.value",
      "@fact:priceValid.value",
      "@fact:ageValid.value"
    ]
  }
}
Use this pattern for:
  • Numeric range validation
  • Age verification
  • Date range checks
  • Inventory limits

Pattern: Validation with Error Messages

Provide specific error messages for failed validations.
{
  "emailValid.value": {
    "operator": "stringContains",
    "input": ["@fact:email.value", "@"]
  },
  "passwordValid.value": {
    "operator": ">=",
    "input": [
      {"operator": "stringLength", "input": ["@fact:password.value"]},
      8
    ]
  },
  "errors.value": {
    "operator": "generateArray",
    "input": [
      [
        {"operator": "not", "input": ["@fact:emailValid.value"]},
        "Email must contain @"
      ],
      [
        {"operator": "not", "input": ["@fact:passwordValid.value"]},
        "Password must be at least 8 characters"
      ]
    ]
  },
  "isValid.value": {
    "operator": "=",
    "input": [
      {"operator": "arrayLength", "input": ["@fact:errors.value"]},
      0
    ]
  }
}
Use this pattern for:
  • User-friendly validation feedback
  • Multi-field validation
  • Form error messages
  • API request validation

Lookup Tables & Mappings

Map keys to values using lookup objects - perfect for state taxes, shipping zones, or category mappings.

Pattern: State Tax Lookup

Map states to their tax rates with a default fallback.
{
  "taxRate.value": {
    "operator": "map",
    "input": [
      "@fact:state.value",
      {
        "CA": 0.0725,
        "NY": 0.08,
        "TX": 0.0625,
        "FL": 0.06,
        "WA": 0.065,
        "IL": 0.0625
      },
      0.05
    ]
  },
  "taxAmount.value": {
    "operator": "*",
    "input": ["@fact:subtotal.value", "@fact:taxRate.value"]
  },
  "total.value": {
    "operator": "+",
    "input": ["@fact:subtotal.value", "@fact:taxAmount.value"]
  }
}
Use this pattern for:
  • Tax rates by location
  • Shipping costs by zone
  • Commission rates by region
  • Currency conversion rates

Pattern: Category-Based Rules

Apply different rules based on product category.
{
  "shippingCost.value": {
    "operator": "map",
    "input": [
      "@fact:category.value",
      {
        "electronics": 15.99,
        "clothing": 7.99,
        "books": 4.99,
        "furniture": 49.99
      },
      9.99
    ]
  },
  "returnWindow.value": {
    "operator": "map",
    "input": [
      "@fact:category.value",
      {
        "electronics": 30,
        "clothing": 60,
        "books": 30,
        "furniture": 14
      },
      30
    ]
  },
  "requiresSignature.value": {
    "operator": "inArray",
    "input": [
      "@fact:category.value",
      ["electronics", "jewelry", "furniture"]
    ]
  }
}
Use this pattern for:
  • Category-specific policies
  • Product type rules
  • Department-specific logic
  • Industry-specific calculations

Array Processing

Process lists of items with aggregations, filtering, and transformations using JSONPath queries.

Pattern: Cart Total Calculation

Sum prices and quantities across cart items using jPath to query literal arrays.
{
  "cartItems.value": [
    { "name": "Widget", "price": 29.99, "quantity": 2 },
    { "name": "Gadget", "price": 49.99, "quantity": 1 },
    { "name": "Tool", "price": 19.99, "quantity": 3 }
  ]
}
Working with arrays: Use the jPath operator to extract values from literal array objects. The $[*].propertyName syntax extracts that property from each array element. When both inputs are arrays of the same length, math operators process them element-by-element.
Alternative syntax: Rules also support a wildcard syntax (@fact:items/*/property) for flattened key-value structures, but most users will work with literal JSON arrays as shown in this example.
Use this pattern for:
  • Shopping cart totals
  • Invoice line items
  • Batch processing
  • Aggregate calculations

Pattern: Array Filtering and Selection

Filter arrays based on conditions.
{
  "inStock.value": {
    "operator": "jPath",
    "input": ["@fact:items.value", "$[*].inStock"]
  },
  "quantities.value": {
    "operator": "jPath",
    "input": ["@fact:items.value", "$[*].quantity"]
  },
  "hasQuantity.value": {
    "operator": ">=",
    "input": ["@fact:quantities.value", 1]
  },
  "filterMask.value": {
    "operator": "and",
    "input": ["@fact:hasQuantity.value", "@fact:inStock.value"]
  },
  "eligibleItems.value": {
    "operator": "arrayFilter",
    "input": ["@fact:items.value", "@fact:filterMask.value"]
  },
  "eligiblePrices.value": {
    "operator": "jPath",
    "input": ["@fact:eligibleItems.value", "$[*].price"]
  },
  "eligibleTotal.value": {
    "operator": "+",
    "input": "@fact:eligiblePrices.value"
  }
}
Use this pattern for:
  • Filtering by criteria
  • Available items only
  • Conditional selections
  • Qualified subset processing

Pattern: Array Aggregations

Calculate statistics from arrays.
{
  "orderAmounts.value": {
    "operator": "jPath",
    "input": ["@fact:orders.value", "$[*].amount"]
  },
  "totalRevenue.value": {
    "operator": "+",
    "input": "@fact:orderAmounts.value"
  },
  "orderCount.value": {
    "operator": "jPath",
    "input": ["@fact:orders.value", "$[*]"]
  },
  "averageOrderValue.value": {
    "operator": "/",
    "input": [
      "@fact:totalRevenue.value",
      {
        "operator": "arrayLength",
        "input": ["@fact:orderCount.value"]
      }
    ]
  },
  "maxOrder.value": {
    "operator": "max",
    "input": "@fact:orderAmounts.value"
  },
  "minOrder.value": {
    "operator": "min",
    "input": "@fact:orderAmounts.value"
  }
}
Use this pattern for:
  • Analytics calculations
  • Summary statistics
  • Dashboard metrics
  • Report generation

Multi-Condition Logic

Combine multiple conditions to make complex decisions.

Pattern: Eligibility Checks

Determine if someone qualifies based on multiple criteria.
{
  "meetsAge.value": {
    "operator": ">=",
    "input": ["@fact:age.value", 18]
  },
  "meetsIncome.value": {
    "operator": ">=",
    "input": ["@fact:annualIncome.value", 30000]
  },
  "hasCreditHistory.value": {
    "operator": ">=",
    "input": ["@fact:creditScore.value", 600]
  },
  "isEligible.value": {
    "operator": "and",
    "input": [
      "@fact:meetsAge.value",
      "@fact:meetsIncome.value",
      "@fact:hasCreditHistory.value"
    ]
  },
  "eligibilityReasons.value": {
    "operator": "generateArray",
    "input": [
      [
        {"operator": "not", "input": ["@fact:meetsAge.value"]},
        "Must be 18 or older"
      ],
      [
        {"operator": "not", "input": ["@fact:meetsIncome.value"]},
        "Minimum income requirement not met"
      ],
      [
        {"operator": "not", "input": ["@fact:hasCreditHistory.value"]},
        "Credit score below minimum"
      ]
    ]
  }
}
Use this pattern for:
  • Loan qualification
  • Program eligibility
  • Access control
  • Application approval

Pattern: Priority Scoring

Calculate priority scores based on multiple weighted factors.
{
  "urgencyScore.value": {
    "operator": "map",
    "input": [
      "@fact:urgency.value",
      {"low": 1, "medium": 3, "high": 5, "critical": 10},
      1
    ]
  },
  "impactScore.value": {
    "operator": "map",
    "input": [
      "@fact:impact.value",
      {"individual": 1, "team": 3, "department": 5, "company": 10},
      1
    ]
  },
  "customerTierScore.value": {
    "operator": "map",
    "input": [
      "@fact:customerTier.value",
      {"bronze": 1, "silver": 2, "gold": 3, "platinum": 5},
      1
    ]
  },
  "totalScore.value": {
    "operator": "+",
    "input": [
      {"operator": "*", "input": ["@fact:urgencyScore.value", 2]},
      {"operator": "*", "input": ["@fact:impactScore.value", 1.5]},
      "@fact:customerTierScore.value"
    ]
  },
  "priority.value": [
    {
      "condition": {"operator": ">=", "input": ["@fact:totalScore.value", 30]},
      "outcome": "P1"
    },
    {
      "condition": {
        "operator": "between",
        "input": ["@fact:totalScore.value", 20, 30, "INCLUSIVE_LEFT"]
      },
      "outcome": "P2"
    },
    {
      "condition": {
        "operator": "between",
        "input": ["@fact:totalScore.value", 10, 20, "INCLUSIVE_LEFT"]
      },
      "outcome": "P3"
    },
    {
      "outcome": "P4"
    }
  ]
}
Use this pattern for:
  • Ticket prioritization
  • Lead scoring
  • Risk assessment
  • Resource allocation

String Formatting & Templates

Format data for display or generate dynamic messages.

Pattern: Dynamic Message Generation

Create personalized messages with data substitution.
{
  "welcomeMessage.value": {
    "operator": "stringTemplate",
    "input": [
      "Welcome back, {{1}}! You have {{2}} new messages and {{3}} pending tasks.",
      "@fact:firstName.value",
      "@fact:messageCount.value",
      "@fact:taskCount.value"
    ]
  },
  "orderConfirmation.value": {
    "operator": "stringTemplate",
    "input": [
      "Order #{{1}} confirmed! {{2}} items totaling {{3}} will ship to {{4}}.",
      "@fact:orderNumber.value",
      "@fact:itemCount.value",
      {"operator": "numberFormat", "input": ["@fact:total.value", 2]},
      "@fact:shippingCity.value"
    ]
  }
}
Use this pattern for:
  • Email templates
  • Notification messages
  • Dynamic content
  • User communications

Pattern: Name Formatting

Combine name parts in various formats.
{
  "fullName.value": {
    "operator": "concat",
    "input": ["@fact:firstName.value", " ", "@fact:lastName.value"]
  },
  "formalName.value": {
    "operator": "concat",
    "input": ["@fact:lastName.value", ", ", "@fact:firstName.value"]
  },
  "displayName.value": {
    "operator": "concat",
    "input": [
      "@fact:firstName.value",
      " ",
      {"operator": "substring", "input": ["@fact:lastName.value", 0, 1]},
      "."
    ]
  },
  "initials.value": {
    "operator": "concat",
    "input": [
      {"operator": "substring", "input": ["@fact:firstName.value", 0, 1]},
      {"operator": "substring", "input": ["@fact:lastName.value", 0, 1]}
    ]
  }
}
Use this pattern for:
  • Name display variations
  • User profiles
  • Report headers
  • Contact lists

Date & Time Calculations

Work with dates for deadlines, aging, and scheduling.

Pattern: Due Date Calculation

Calculate deadlines based on creation date and urgency.
{
  "daysToComplete.value": {
    "operator": "map",
    "input": [
      "@fact:priority.value",
      {"critical": 1, "high": 3, "medium": 7, "low": 14},
      7
    ]
  },
  "dueDate.value": {
    "operator": "addDate",
    "input": [
      "@fact:createdDate.value",
      "@fact:daysToComplete.value",
      "days"
    ]
  },
  "formattedDueDate.value": {
    "operator": "dateFormat",
    "input": ["@fact:dueDate.value", "YYYY-MM-DD"]
  }
}
Use this pattern for:
  • SLA calculations
  • Payment terms
  • Project deadlines
  • Expiration dates

Pattern: Age & Overdue Calculations

Determine how old something is or if it’s overdue.
{
  "ageInDays.value": {
    "operator": "dateDiff",
    "input": [
      {"operator": "now", "input": []},
      "@fact:createdDate.value",
      "days"
    ]
  },
  "isOverdue.value": {
    "operator": ">",
    "input": [
      {"operator": "now", "input": []},
      "@fact:dueDate.value"
    ]
  },
  "daysOverdue.value": [
    {
      "condition": "@fact:isOverdue.value",
      "outcome": {
        "operator": "dateDiff",
        "input": [
          {"operator": "now", "input": []},
          "@fact:dueDate.value",
          "days"
        ]
      }
    },
    {
      "outcome": 0
    }
  ]
}
Use this pattern for:
  • Overdue tracking
  • Aging reports
  • Time-based alerts
  • Compliance monitoring

Conditional Calculations

Perform different calculations based on conditions.

Pattern: Conditional Fees

Apply fees only when certain conditions are met.
{
  "rushFee.value": [
    {
      "condition": {
        "operator": "=",
        "input": ["@fact:isRush.value", true]
      },
      "outcome": 25
    },
    {
      "outcome": 0
    }
  ],
  "oversizeFee.value": [
    {
      "condition": {
        "operator": ">",
        "input": ["@fact:weight.value", 50]
      },
      "outcome": {
        "operator": "*",
        "input": [
          {"operator": "-", "input": ["@fact:weight.value", 50]},
          2
        ]
      }
    },
    {
      "outcome": 0
    }
  ],
  "totalFees.value": {
    "operator": "+",
    "input": [
      "@fact:baseFee.value",
      "@fact:rushFee.value",
      "@fact:oversizeFee.value"
    ]
  }
}
Use this pattern for:
  • Conditional charges
  • Dynamic pricing
  • Fee calculations
  • Surcharge logic

Best Practices

Keep It Simple

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

Use Descriptive Names

Name rules clearly so their purpose is obvious: qualifiesForFreeShipping not rule1

Provide Defaults

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

Test Incrementally

Add one rule at a time and test it before adding the next

Document Complex Logic

For complex rules, add comments or use descriptive intermediate rule names

Reuse Calculations

Calculate values once and reference them multiple times rather than recalculating

What’s Next?

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