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

# Author JEXL expressions

> Write and validate expressions in company configuration.

JEXL expressions read configured field values and return a value for a specific configuration setting. The [JEXL reference](/api-reference/configuration/jexl-reference) lists every registered macro, its arguments, and the expression locations that accept it. In the app, open **Configuration > Data Model > JEXL Reference** to search the same catalog.

## Choose the expression location

The setting determines which fields and named roots an expression can read, which macros it can call, and what happens if it returns null or fails. The [expression locations table](/api-reference/configuration/jexl-reference#expression-locations) lists every supported setting. The main groups are:

| Setting | Typical purpose | Result |
| - | - | - |
| `fields[].calculatedValue` and `objects[].subFields[].calculatedValue` | Compute a Live or Stamped field. | A value compatible with the field type. |
| `entityInvariants[].condition` | Require a rule to hold on each entity write. | Exactly `true` to pass. |
| `fieldLocations[].requiredCondition`, `fieldLocations[].displayCondition`, and `cards[].displayCondition` | Control form requiredness and visibility. | A Boolean condition. |
| `fieldLocations[].autoSetCalculation` and `fieldLocations[].autoSetConfirmation` | Suggest a value and decide whether to confirm it. | A field value or a Boolean. |
| `formLogicRules[].addCondition` | Add a form to a quote when its condition holds. | A Boolean condition. |
| `conversionRules[].expression` | Map a source Quote or Policy value to a destination. | A destination-compatible value. |
| `smartTags[].expression`, `listColumns[].expression`, and `exportSurfaces[].expression` | Produce display or export output. | The output value. |
| `ratingWorkflows[]` expression settings and `financials.payeeDefaults.expression` | Check rating, project inputs, or select a default. | Depends on the setting. |

For most entity expressions, use bare field reference IDs such as `annualRevenue`. Calculated values also offer `me`, `parent`, and `root` according to the containing object. Conversion rules use `source.<field>` and `transaction.<field>`. Policy entity invariants can read `transaction` and `policyVersions`; other entity invariants cannot. Smart tags offer those version roots only for Quote form types. Policy-row exports offer them; other exports do not. The setting's own entry in the reference lists its available roots.

## Write conditions and calculations

Use `=`, `==`, or `!=` for equality; `>`, `>=`, `<`, and `<=` for ordered comparisons. Arithmetic uses `+`, `-`, `*`, `/`, and `%`. Text and list comparisons are case-sensitive. Parentheses group expressions. `!` negates a Boolean.

The type checker rejects equality comparisons on Boolean fields and whole lists. Use a Boolean field directly, such as `isActive` or `!isActive`. For lists, use membership, a bracket filter, or `COUNT`. Ordered comparisons require Numbers; use a date function such as `DAYS_BETWEEN` before comparing dates numerically.

```text theme={null}
(status = 'Active' || status = 'Pending') && annualRevenue > 1000000
```

`&&` binds more tightly than `||`, and both short-circuit. The expression `a || b && c` means `a || (b && c)`. A ternary selects only its chosen branch:

```text theme={null}
(IS_PRESENT(nickname)) ? nickname : legalName
```

Wrap a function-call condition in parentheses before `?`. `??` selects the right value when the left is null or undefined, but its right operand still evaluates. Do not put a sequence allocator on its right side. Use a ternary when the fallback has side effects:

```text theme={null}
(IS_PRESENT(referenceNumber)) ? referenceNumber : NEXT_SEQUENCE_NUMBER('reference-number')
```

This example assumes a configured `reference-number` sequence and a Stamped field that accepts sequence allocation. Check the macro's accepted locations before using it.

Use `IS_PRESENT(value)` for an unset value. It returns false for null, undefined, empty text, and whitespace-only text. Zero and `false` are present. `CLEAR()` produces an explicit null, which is useful when a conversion must clear a destination. Do not use a bare `null` value in an expression; this JEXL grammar does not offer a general null literal. The record-presence comparison `transaction.before == null` is a narrow supported exception.

`CONTAINS` reads left to right. `tags CONTAINS 'urgent'` tests list membership; `name CONTAINS 'Corp'` tests a text substring. `IN` tests a scalar element in a list, such as `'urgent' IN tags`. The engine also has string-to-string `IN` behavior, but the configuration type checker requires a list on the right. Use `CONTAINS` for text.

Use `items[.active]` or `items[.state = 'CA']` to filter a list. Use `items|map('state')` to extract one property from each item. `map` is the registered pipe transform; `filter` is not. List indexing uses `items[0]`. Test for presence before depending on an optional element.

Group a membership test before negating it. `!` binds more tightly than `IN` or `CONTAINS`, so `!('GL' IN coverageTypes)` means the list lacks `GL`, and `!(name CONTAINS 'Corp')` means the name lacks that substring. To write "if A, then B," use `!(A) || (B)`.

Date fields store `{date: 'YYYY-MM-DD', timezone}`. Use `YEAR(date)`, `MONTH(date)`, and `DAY(date)` to read parts of a date, and `ADD_DAYS`, `ADD_MONTHS`, or `ADD_YEARS` for arithmetic. Wrap a negative literal passed to a function, as in `ADD_DAYS(effectiveDate, (-1))`. When a Date field needs a Date object from an ISO string, use `DATE_VALUE(effectiveDateText, 'America/New_York')`; in a conversion, read the source value as `source.effectiveDateText`. Use `FORMAT_DATE` only for display text. `TODAY()` is temporal and is accepted only in the locations listed in the reference.

## Author an entity invariant

An invariant is one row of `entityInvariants`. This example requires a nonempty Policy number:

```json theme={null}
{
  "entity": "Policy",
  "condition": "IS_PRESENT(policyNumber)",
  "errorMessage": "A policy number is required."
}
```

This row is part of the complete configuration document, not a complete import body. On an entity write, only a strict Boolean `true` passes. `false` or null refuses the write with the configured `errorMessage`. An evaluation error also refuses the write and reports that the named invariant could not be checked. The write does not persist a partially valid entity. Each invariant sees the fields of its declared entity; Policy invariants can additionally inspect the transaction and policy version grid. Bind dry runs apply the same fail-closed rule before Bind.

An entity invariant runs once for the entity. It does not automatically run once per item in an ObjectList. To require at least one matching row, use `COUNT(rows[.active]) > 0`. To require every row to pass a condition, count violations: `COUNT(rows[!.active]) = 0`. A form placement's display or required condition changes that placement in the browser; use an entity invariant for a rule that must hold on every write, including API writes.

Policy version roots can be absent when a write has no transaction in view, including a candidate data validation run. Guard a rule that depends on the prior policy with `transaction.before == null || <condition>`. That comparison is the supported record-presence use of `null`; it does not make `null` a general value literal.

## Validate before importing

Configuration validation first checks JSON shape, expression syntax, supported roots and macros, and references and result types where the setting has enough type information. A reported syntax error means the expression did not compile. A rejected macro means its tag is unavailable at that expression location. A reference or type finding names the affected setting or rule. Some display, list, and rating expressions report type findings as warnings; entity invariants, conversions, and calculated values use errors for invalid types. Treat warnings as work to inspect, not proof that the expression will return the intended value.

Macro availability is checked in every branch. A short-circuit condition or ternary does not make an otherwise forbidden macro valid.

A valid configuration can still disagree with existing records. A [data validation run](/api-reference/configuration/overview#checking-configuration-against-stored-data) scans stored records against a candidate configuration. Runtime writes evaluate the active expressions using current entity data. A missing value, a database read, or a calculation can still fail there even after static validation succeeds. The result follows the expression location's [null and error behavior](/api-reference/configuration/jexl-reference#expression-locations).

An external write refused by the example invariant returns HTTP `400` with the normal error envelope. The `message` includes the data field, `userMessages` contains the configured message, and `details` identifies the same field:

```json theme={null}
{
  "error": {
    "code": "TenantInvariantViolation",
    "message": "fieldModelV1Data: A policy number is required.",
    "userMessages": ["A policy number is required."],
    "details": [
      { "field": "fieldModelV1Data", "message": "A policy number is required." }
    ]
  }
}
```

Search the exported `entityInvariants` rows for the text in `userMessages`, then inspect the matching row's `entity` and `condition`. If the message says the invariant could not be checked, inspect its roots, macro availability, and values at evaluation time. The [Policy API overview](/api-reference/policies/overview) describes the Check Bind Conditions response, which identifies invariant findings before a bind.

## Change configuration safely

1. [Export the complete configuration](/api-reference/configuration/overview) and keep a copy of the current body.
2. Edit the relevant expression. Check its location, roots, macros, and destination type against the [JEXL reference](/api-reference/configuration/jexl-reference).
3. [Validate the candidate](/api-reference/configuration/overview). Correct syntax, forbidden macros, wrong references, and type findings.
4. [Compare the candidate](/api-reference/configuration/overview) with the current configuration to review its scope.
5. Start a [data validation run](/api-reference/configuration/overview#checking-configuration-against-stored-data) for the candidate when stored records could be affected. Poll the run and read its findings.
6. Exercise the expression on representative data in a test environment, including missing values and both condition branches. Then import the complete configuration.

Keep framework-required rows and their fixed expressions intact. A configuration import applies the full body, so omitting an unrelated section can remove it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.