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

# Workflow Conditions and Variables

> The expression language behind workflow branching: cases, comparison operators, arithmetic, logical combinators, and the variable namespaces they read.

## Cases

Every branching node routes through an ordered list of cases. Each case pairs a condition (`when`) with a destination and optional effects (`then`):

```json theme={"system"}
"cases": [
  {
    "when": { "cmp": "==", "left": { "var": "call.status" }, "right": { "const": "completed" } },
    "then": {
      "to": "n_extract",
      "effects": [ { "set_value": { "state.attempted": { "const": true } } } ]
    }
  }
]
```

Cases are evaluated **in order and the first match wins**. When nothing matches, the execution moves to the node's `on_no_match`, or the definition-wide `on_no_match` if the node doesn't declare one — so an execution always has somewhere to go. Point the definition-wide fallback at a dedicated `end` node (an `unhandled` ending) and it doubles as your safety net.

***

## Operands

Conditions compare **operands**, each one of three forms:

| Form    | Example                            | Meaning                                                                                                    |
| ------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `var`   | `{"var": "extraction.call_score"}` | Reads a variable from the execution context                                                                |
| `const` | `{"const": 80}`                    | A literal — string, number, boolean, null, or (only as the right side of `in`) a list of up to 100 scalars |
| `op`    | `{"op": "+", "args": [ ... ]}`     | Arithmetic over other operands                                                                             |

Arithmetic supports `+`, `-`, `*`, `/`. Addition and multiplication take any number of `args`; subtraction and division take exactly two:

```json theme={"system"}
{ "op": "+", "args": [ { "var": "extraction.call_score" }, { "var": "extraction.engagement_intent" } ] }
```

***

## Comparisons

```json theme={"system"}
{ "cmp": "in", "left": { "var": "call.status" }, "right": { "const": ["busy", "no_answer"] } }
```

| Operator             | Meaning                                                                                         |
| -------------------- | ----------------------------------------------------------------------------------------------- |
| `==`, `!=`           | Equality. String comparison is case-insensitive by default; add `"cs": true` for case-sensitive |
| `>`, `>=`, `<`, `<=` | Numeric ordering — both sides must resolve to numbers                                           |
| `in`                 | Left value is one of the right-side list's values                                               |
| `contains`           | Left string contains the right substring                                                        |

***

## Combinators

Combine conditions with `all` (AND), `any` (OR) and `not`, nested up to 32 levels:

```json theme={"system"}
{
  "all": [
    { "cmp": "==", "left": { "var": "response.status" }, "right": { "const": 200 } },
    { "any": [
      { "cmp": ">=", "left": { "var": "entry.loan_amount" }, "right": { "const": 50000 } },
      { "exists": { "var": "entry.priority_flag" } }
    ] }
  ]
}
```

Two more forms round out the language: `{"exists": {"var": "..."}}` is true when the variable is present, and `{"always": true}` matches unconditionally — the standard last case or single-exit route.

***

## Effects

A matching case can write to durable state before moving on:

```json theme={"system"}
"then": {
  "to": "n_api",
  "effects": [
    { "set_value": { "state.promised": { "var": "extraction.promised_date" } } }
  ]
}
```

`set_value` targets are always `state.<name>` (one level deep). `state.*` is the execution's scratchpad — it survives retries, later calls and waits, and is never reset.

***

## Variable namespaces

| Namespace      | Written by                   | Reset                                 | Contents                                                                                                             |
| -------------- | ---------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `entry.*`      | contact ingress              | never                                 | The contact's fields — system fields plus everything the start node declares. `entry.reference_id` is always present |
| `call.*`       | each `agent` node            | overwritten per agent node            | `call.status`, `call.duration_s`, `call.error`, plus post-call insights                                              |
| `extraction.*` | `extraction` nodes           | cleared on entering any agent node    | The selected extracted fields from the latest call                                                                   |
| `response.*`   | each `api` node              | cleared on entering any api node      | `response.status`, `response.error`, plus every `response_map` name                                                  |
| `whatsapp.*`   | each `aisensy_whatsapp` node | cleared on entering any WhatsApp node | `whatsapp.status`, `whatsapp.message_id`, `whatsapp.error`                                                           |
| `state.*`      | `set_value` effects          | never                                 | Your own durable values                                                                                              |
| `node.<id>.*`  | every node                   | never                                 | Per-node history — read an earlier node's outputs even after the live namespace was overwritten                      |

<Note>
  `call.*`, `response.*` and `whatsapp.*` hold the **latest** node's values of that kind. When a workflow has two agent nodes and you need the first call's status after the second call ran, read it from `node.<first_node_id>.*` instead.
</Note>

***

## Variables in node configs

Node configs (agent prompt variables, API URLs/bodies, WhatsApp templates) don't embed expressions directly. They use `{placeholder}` references resolved by the node's `config.variables` map:

```json theme={"system"}
"config": {
  "url": "https://api.example.com/lookup",
  "body": { "phone": "{phone}" },
  "variables": {
    "phone": { "value": { "var": "entry.mobile_number" }, "required": true }
  }
}
```

Each variable spec takes a `value` operand, an optional `type` (one of `string`, `number`, `boolean`, `timestamp`, `phone`, `email`, `url`, `json` — the value is coerced, and the execution treats a failed coercion as a missing value), and `required`. A missing required variable stops the execution with `termination_reason` `required_variable_missing`; a missing optional one resolves empty and the execution continues with a `warning` event on its timeline.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Nodes" icon="circle-nodes" href="/docs/guides/workflows/nodes">
    What each node writes and branches on
  </Card>

  <Card title="Quickstart" icon="rocket" href="/docs/guides/workflows/quickstart">
    See conditions in a complete working definition
  </Card>
</CardGroup>
