> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Computed Values

> Define formula-based fields that are evaluated per customer at decision time.

## Overview

Computed values let you define formulas on offer categories that are evaluated dynamically for each customer during a Decision Flow. This enables personalization like custom pricing, dynamic discounts, and tailored messaging.

## How It Works

1. **Define computed fields** on a category with a formula and output type
2. **Configure enrichment** in a Decision Flow to load customer data from schema tables
3. **Add a compute stage** to evaluate formulas per candidate offer
4. **Access results** in the Recommend API response under the `personalization` field
5. **Verify in the studio** — the [Recommendation Preview](/decisioning/decision-flows#preview) on the decision-flow detail view now renders the computed `personalization` values inline under each offer card, so authors can confirm a formula produces the expected value before any API client is wired up

## Formula Syntax

The formula engine supports the following features. Each example is shown in a code block so it copies cleanly into the editor.

**Arithmetic**

```
base_rate * 1.05
```

**Comparison**

```
amount > 1000
```

**Ternary**

```
tier == "gold" ? 0.15 : 0.10
```

**Functions** — pick the smaller or larger of two values.

```
min(rate, 0.25)
max(amount, 100)
```

**Rounding** — round a number to N decimal places.

```
round(price, 2)
```

**Null handling** — return the first non-null argument.

```
coalesce(custom_rate, default_rate)
```

**String concatenation** — join string fragments.

```
concat(first_name, " ", last_name)
```

## Variable Namespaces

| Prefix         | Source                                                                                             | Example                           |
| -------------- | -------------------------------------------------------------------------------------------------- | --------------------------------- |
| *(none)*       | Other custom fields on the offer                                                                   | `base_rate`                       |
| `customer.*`   | The base `customer` schema row (loaded automatically)                                              | `customer.loan_amount`            |
| `<entity>.*`   | Auto-enriched [Schema Joins](/api-reference/schema-joins), rolled up via the join's `aggregations` | `accounts.balance_sum`            |
| `behavior.*`   | [Behavioral Metric](/studio/behavioral-metrics) values, keyed by slugified metric name             | `behavior.converts_30d`           |
| `journey.*`    | Active [Journey](/studio/journeys) enrollment state                                                | `journey.current`, `journey.step` |
| `attributes.*` | Request-time attributes from Recommend API                                                         | `attributes.tier`                 |

<Note>
  The `customer.*`, `<entity>.*`, `behavior.*`, and `journey.*` namespaces come from the [canonical decision context](/decisioning/decision-flows#the-decision-context-auto-assembled), which the engine assembles automatically on every Recommend call — no Enrich node is required. An Enrich node only *overrides or extends* the assembled context.
</Note>

<Tip>
  The formula engine uses a tokenizer and recursive-descent parser -- it does not use dynamic code execution. All formulas are safely interpreted from an AST.
</Tip>

## Example

A "Personal Loan" category with a computed field:

```
Field: personalized_rate
Formula: base_rate * (1 - customer.loyalty_score * 0.01)
Output Type: number
```

When the Recommend API runs, KaireonAI calculates each loan offer's `personalized_rate` using the customer's enriched `loyalty_score` and the offer's `base_rate`.

## Personalization patterns

The compute node covers a broad set of personalization use cases. Each pattern below is a copy-pasteable formula plus the inputs it expects and the output it produces. All formulas in this section have been verified against the live formula engine — see `platform/scripts/test-compute-personalization.mts` for the executable proof.

### Greetings and templated copy

```
concat("Hi ", coalesce(attributes.first_name, "there"), ", welcome back!")
```

Inputs: `attributes.first_name` (optional). Output (string): `"Hi Anuraag, welcome back!"` — falls back to `"Hi there, welcome back!"` when the attribute is missing. `coalesce` chains as many fallbacks as you need.

```
concat(attributes.first_name, " — ", customer.tier, " member")
```

Mixes a request attribute with an enriched field — useful when the channel template needs a personalized salutation that includes the segment.

### Tier-based numeric output (credit limit, discount)

```
customer.tier == "Platinum" ? base_rate * 5 : base_rate * 2
```

Inputs: `customer.tier`, `base_rate` (custom field on the offer). For a Platinum customer with `base_rate = 5000`, returns `25000`. For a Gold customer with the same `base_rate`, returns `10000`.

### Multi-band ladder (credit score → limit)

```
customer.credit_score >= 800 ? 50000
  : customer.credit_score >= 740 ? 30000
  : customer.credit_score >= 670 ? 15000
  : 5000
```

Nested ternaries form a clean if/else-if/else ladder. With a score of 820 the customer gets `50000`; at 620 the safe-default `5000`.

### Risk-adjusted APR

```
round(base_apr + (850 - customer.credit_score) * 0.02, 2)
```

For `base_apr = 5.5` and a score of 820, the personalized APR is `6.10`. At 650 it becomes `9.50`. `round(x, n)` is the safe way to format money values — never returns more than `n` decimal places.

### Ceiling clamp (program-cap underwriting)

```
min(customer.income * 0.3, 100000)
```

Computes 30% of income, capped at the program ceiling of $100,000. A customer earning $500,000 gets exactly $100,000; one earning $250,000 gets `75000`.

### Conditional CTA / region-specific disclosure

```
customer.tier == "Platinum" ? "Apply with priority underwriting →" : "Apply now →"
```

Returns one of two CTA strings depending on tier. Useful for personalizing channel templates without authoring duplicate creatives.

```
attributes.region == "CA" ? "California disclosure §1234"
  : attributes.region == "EU" ? "GDPR — your data, your rights"
  : "Standard terms apply"
```

Compliance copy that switches on the request's region attribute. The same Compute node can emit `disclosure_text` alongside the numeric output.

### Cross-field arithmetic on the offer

```
round(customer.balance * (current_rate - new_rate) / 100, 0)
```

For `customer.balance = 8500`, `current_rate = 24.99`, `new_rate = 12.99`, returns `1020` — the estimated annual interest savings the response can show under each card offer.

### Loyalty waiver

```
customer.years_with_us >= 5 ? "WAIVED" : annual_fee
```

Loyal customers (≥ 5 years) see the string `"WAIVED"`; newer customers see the raw `annual_fee` value. The output type can be `text` even though the else-branch returns a number — the Recommend response carries the value through unchanged.

## Null and error handling

The engine is null-safe and crash-free:

* **Missing variable** → result is `null`. `customer.balance * 0.05` with no `customer.balance` returns `null`, not `NaN`.
* **Divide by zero** → result is `null`. `100 / 0` returns `null`, not `Infinity`.
* **Write-time validation** → the `/api/v1/categories` endpoint checks, via a Zod `superRefine`, that every computed field has a non-empty `formula` and an `outputType` of `number` or `text`, rejecting with a `400` before persisting. A formula that is present but syntactically invalid is not rejected at write time — it evaluates to `null` at decision time, so use the **Validate** button in the Category editor to catch syntax errors early.

The engine is also injection-safe — `Function(...)`, `eval(...)`, and `process.env` are not recognized identifiers, so any such expression evaluates to `null` and is logged as a parse error.

## Next Steps

<CardGroup cols={3}>
  <Card title="Formula Reference" icon="function" href="/tutorials/formula-reference">
    Complete list of operators, functions, and variable namespaces.
  </Card>

  <Card title="Decision Flows" icon="sitemap" href="/decisioning/decision-flows">
    See how computed values are evaluated in the Compute stage.
  </Card>

  <Card title="Scoring Strategies" icon="bullseye" href="/decisioning/scoring-strategies">
    How the same candidates produce different rankings under each scoring method.
  </Card>
</CardGroup>
