Build a Transaction Rule Engine with AND/OR Chains and Nested Parentheses

Read the full interview experience this question came from →

Quick Overview

Multi-part coding exercise: build a rule engine that accepts or denies payment transactions by evaluating text conditions over their attributes. The parts add single comparisons, then AND/OR chains evaluated strictly left to right, then nested parentheses. It tests parser design, modular code, and directing an AI coding assistant.

Build a Transaction Rule Engine with AND/OR Chains and Nested Parentheses

Company: Stripe

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: hard

Interview Round: Technical Screen

Build a rule engine that decides whether each payment transaction is accepted or denied. - **Transactions:** a list of records, each a set of named attributes, for example `{"id": "t1", "amount": 1500, "currency": "USD", "country": "US", "card_type": "prepaid"}`. These attribute names are illustrative. - **Rules:** a list of rules, each pairing a condition over a transaction's attributes with an action, `ACCEPT` or `DENY`. - **Output:** one decision per transaction, in input order. Assume a condition arrives as text, such as `amount > 1000`. A comparison is a field name, an operator (`==`, `!=`, `>`, `>=`, `<`, `<=`) and a literal value, which is a number or a double-quoted string. The task grows in parts, each extending what a condition can express. Three parts are given below. The round continues with further parts that add more kinds of conditions, and finishing all of them is not expected, so structure the code so that each new part is a small, local change. An AI coding assistant is available during the round. Use it as a tool you direct: you decide the modules and their interfaces, hand it well-scoped pieces, and check what it produces, rather than letting it produce one monolithic solution. ### Clarifying Questions - When several rules match one transaction, which one decides: the first matching rule in list order, any matching `DENY`, or something else? What is the decision when no rule matches? - Do rules arrive as text that must be parsed, or as already-structured objects? - What should a comparison return when the transaction lacks the field it tests, or when the types do not match, as in `country > 5`? - Should a malformed rule be rejected when the rules are loaded, or skipped when transactions are evaluated? - Are amounts integers in the smallest currency unit, or decimals? ### Part 1 — Single-condition rules Each rule's condition is a single comparison. Parse the rules and return a decision for every transaction. For example, the condition `amount > 1000` matches a transaction whose `amount` is 1500 but not one whose `amount` is exactly 1000. ```hint Separate the jobs Even with one comparison there are distinct jobs: reading the rule text, representing a condition, evaluating it against a transaction, and turning matches into a decision. Decide which of these will have to change in later parts. ``` #### What This Part Should Cover - A condition representation that is parsed once and evaluated many times - Correct comparison semantics for numbers and strings, including the boundary of strict operators - A decision step kept separate from condition evaluation - Tests for matching, non-matching and malformed rules ### Part 2 — AND and OR without precedence A condition may now chain comparisons with `AND` and `OR`. The two operators have no precedence over each other: evaluate the chain strictly from left to right. So `A OR B AND C` means `(A OR B) AND C`, not the usual `A OR (B AND C)`. For the transaction `{"country": "US", "amount": 50, "card_type": "credit"}`, the condition `country == "US" OR amount > 1000 AND card_type == "prepaid"` is false, because `(true OR false) AND false` is false. ```hint Fold as you go Think about how an already-evaluated left side combines with the next comparison, and whether splitting the text on spaces or keywords will survive the next part. ``` #### Clarifying Questions for this Part - Are `AND` and `OR` always uppercase? - May a string literal contain the word `AND` or `OR`, or spaces? #### What This Part Should Cover - Tokenizing that does not break on spacing or on keywords inside string literals - Left-to-right combination that matches the stated semantics, verified by a test where the usual precedence would give a different answer - An extension of Part 1's structures rather than a rewrite ### Part 3 — Nested conditions with parentheses Conditions may now group sub-conditions with parentheses, nested to any depth, for example `(amount > 1000 AND country != "US") OR (card_type == "prepaid" AND amount > 200)`. A parenthesized group is evaluated as a unit before it is combined with its neighbors. For the transaction `{"amount": 300, "country": "US", "card_type": "prepaid"}`, that condition is true, because the second group is true. ```hint Recursion in the input A parenthesized group contains a whole condition, which may itself contain groups. Consider which structure in your code can mirror that. ``` #### Clarifying Questions for this Part - Outside parentheses, does left-to-right evaluation still hold, or should `AND` now bind more tightly than `OR`? - Is there a maximum nesting depth or rule length? #### What This Part Should Cover - Parsing of arbitrary nesting, with clear errors for unbalanced or misplaced parentheses - A tree representation whose evaluation follows the grouping exactly - Tests for nested groups and for malformed input - A change confined to parsing, with evaluation and the decision step untouched ### What a Strong Answer Covers - A modular design (tokenizing, parsing into a tree, evaluating, deciding) chosen by the candidate before the assistant writes code - The policies the prompt leaves open (how rules combine, missing fields, malformed rules) raised, decided explicitly, and easy to change - Incremental progress: each part working and tested before the next one starts - Effective direction of the AI assistant: scoped requests, reviewed output, and bugs caught by tests - Readable code with clear names and error messages that point at the offending rule and position ### Follow-up Questions - How would you add `NOT` and an `IN` operator, as in `country IN ("US", "CA")`, and which modules would change? - How would you report which rule decided each transaction, and why it matched? - A new rule needs state across transactions, such as the number of transactions on the same card in the last hour. What changes in your design? - With thousands of rules and a high transaction rate, where does the time go, and how would you reduce it?

Overview: Multi-part coding exercise: build a rule engine that accepts or denies payment transactions by evaluating text conditions over their attributes. The parts add single comparisons, then AND/OR chains evaluated strictly left to right, then nested parentheses. It tests parser design, modular code, and directing an AI coding assistant.

Read the full Stripe Software Engineer interview experience this question came from

|Home/Software Engineering Fundamentals/Stripe
Stripe logo
Stripe
Aug 30, 2026
hardSoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
2
0

Build a rule engine that decides whether each payment transaction is accepted or denied.

  • Transactions: a list of records, each a set of named attributes, for example {"id": "t1", "amount": 1500, "currency": "USD", "country": "US", "card_type": "prepaid"} . These attribute names are illustrative.
  • Rules: a list of rules, each pairing a condition over a transaction's attributes with an action, ACCEPT or DENY .
  • Output: one decision per transaction, in input order.

Assume a condition arrives as text, such as amount > 1000. A comparison is a field name, an operator (==, !=, >, >=, <, <=) and a literal value, which is a number or a double-quoted string.

The task grows in parts, each extending what a condition can express. Three parts are given below. The round continues with further parts that add more kinds of conditions, and finishing all of them is not expected, so structure the code so that each new part is a small, local change.

An AI coding assistant is available during the round. Use it as a tool you direct: you decide the modules and their interfaces, hand it well-scoped pieces, and check what it produces, rather than letting it produce one monolithic solution.

Clarifying Questions Guidance

  • When several rules match one transaction, which one decides: the first matching rule in list order, any matching DENY , or something else? What is the decision when no rule matches?
  • Do rules arrive as text that must be parsed, or as already-structured objects?
  • What should a comparison return when the transaction lacks the field it tests, or when the types do not match, as in country > 5 ?
  • Should a malformed rule be rejected when the rules are loaded, or skipped when transactions are evaluated?
  • Are amounts integers in the smallest currency unit, or decimals?

Part 1 — Single-condition rules

Each rule's condition is a single comparison. Parse the rules and return a decision for every transaction. For example, the condition amount > 1000 matches a transaction whose amount is 1500 but not one whose amount is exactly 1000.

What This Part Should Cover Guidance

  • A condition representation that is parsed once and evaluated many times
  • Correct comparison semantics for numbers and strings, including the boundary of strict operators
  • A decision step kept separate from condition evaluation
  • Tests for matching, non-matching and malformed rules

Part 2 — AND and OR without precedence

A condition may now chain comparisons with AND and OR. The two operators have no precedence over each other: evaluate the chain strictly from left to right. So A OR B AND C means (A OR B) AND C, not the usual A OR (B AND C).

For the transaction {"country": "US", "amount": 50, "card_type": "credit"}, the condition country == "US" OR amount > 1000 AND card_type == "prepaid" is false, because (true OR false) AND false is false.

Clarifying Questions for this Part Guidance

  • Are AND and OR always uppercase?
  • May a string literal contain the word AND or OR , or spaces?

What This Part Should Cover Guidance

  • Tokenizing that does not break on spacing or on keywords inside string literals
  • Left-to-right combination that matches the stated semantics, verified by a test where the usual precedence would give a different answer
  • An extension of Part 1's structures rather than a rewrite

Part 3 — Nested conditions with parentheses

Conditions may now group sub-conditions with parentheses, nested to any depth, for example (amount > 1000 AND country != "US") OR (card_type == "prepaid" AND amount > 200). A parenthesized group is evaluated as a unit before it is combined with its neighbors. For the transaction {"amount": 300, "country": "US", "card_type": "prepaid"}, that condition is true, because the second group is true.

Clarifying Questions for this Part Guidance

  • Outside parentheses, does left-to-right evaluation still hold, or should AND now bind more tightly than OR ?
  • Is there a maximum nesting depth or rule length?

What This Part Should Cover Guidance

  • Parsing of arbitrary nesting, with clear errors for unbalanced or misplaced parentheses
  • A tree representation whose evaluation follows the grouping exactly
  • Tests for nested groups and for malformed input
  • A change confined to parsing, with evaluation and the decision step untouched

What a Strong Answer Covers Guidance

  • A modular design (tokenizing, parsing into a tree, evaluating, deciding) chosen by the candidate before the assistant writes code
  • The policies the prompt leaves open (how rules combine, missing fields, malformed rules) raised, decided explicitly, and easy to change
  • Incremental progress: each part working and tested before the next one starts
  • Effective direction of the AI assistant: scoped requests, reviewed output, and bugs caught by tests
  • Readable code with clear names and error messages that point at the offending rule and position

Follow-up Questions Guidance

  • How would you add NOT and an IN operator, as in country IN ("US", "CA") , and which modules would change?
  • How would you report which rule decided each transaction, and why it matched?
  • A new rule needs state across transactions, such as the number of transactions on the same card in the last hour. What changes in your design?
  • With thousands of rules and a high transaction rate, where does the time go, and how would you reduce it?
Loading comments...