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

# Conditions

> Use conditions to branch your automation pipeline based on call outcomes, contact data, or any field in the context. Route different results down different paths — send alerts for failures, escalate low ratings, or skip steps when data is missing.

## What is a Condition?

A Condition step evaluates a field in the pipeline context and branches the automation into two paths:

* **Then** — steps that run when the condition is true
* **Otherwise** — steps that run when the condition is false (optional)

If a branch has no steps, it is skipped. The pipeline continues after the condition with any remaining steps.

```text theme={null}
... previous steps ...
  |
  v
Condition: call.status = "completed"
  |
  |-- Then:
  |     Step A: Sync to CRM
  |     Step B: Email to contact
  |
  |-- Otherwise:
  |     Step C: SMS to team ("Call failed")
  |
  v
... next steps (always run) ...
```

***

## Configuration

Every condition has three fields:

| Field        | Description                                                            |
| ------------ | ---------------------------------------------------------------------- |
| **Field**    | The context path to evaluate. Use dot-notation to reach nested values. |
| **Operator** | How to compare the field value against the target value.               |
| **Value**    | The target value to compare against.                                   |

### Field

The field path references any value in the pipeline context. Common paths:

| Path                           | When available                                  | Example values                                                                                            |
| ------------------------------ | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `call.status`                  | After call completes                            | `completed`, `failed`, `voicemail`, `rang-out`, `hang-up`, `dropout`, `User unavailable`, `User rejected` |
| `call.end_reason`              | After call completes                            | `user hangup`, `ai hangup`, `voicemail`, `failed`                                                         |
| `call.duration`                | After call completes                            | `45`, `120`, `0`                                                                                          |
| `call.structured_data.{field}` | After call completes                            | Depends on your Script's data collection schema                                                           |
| `call.success_evaluation`      | After call completes                            | `successful`, `partially_successful`, `unsuccessful`                                                      |
| `contact.email`                | After Upsert Contact                            | `john@example.com` or empty                                                                               |
| `contact.phone_number`         | After Upsert Contact                            | `+61400111222`                                                                                            |
| `trigger.{field}`              | Always                                          | Depends on trigger payload                                                                                |
| `source.{field}`               | After Source step                               | Depends on API response                                                                                   |
| `mapped.{field}`               | After Transform step                            | Depends on your mappings                                                                                  |
| `objects.{type}.{field}`       | After Upsert Object or hydrated from call event | Depends on object data                                                                                    |

### Operators

| Operator | Label                 | What it checks                                                     |
| -------- | --------------------- | ------------------------------------------------------------------ |
| `eq`     | = (equals)            | Field value exactly matches the target value                       |
| `neq`    | != (not equal)        | Field value does not match the target value                        |
| `gt`     | > (greater than)      | Field value is greater than the target (numeric comparison)        |
| `lt`     | \< (less than)        | Field value is less than the target (numeric comparison)           |
| `gte`    | >= (greater or equal) | Field value is greater than or equal to the target                 |
| `lte`    | \<= (less or equal)   | Field value is less than or equal to the target                    |
| `in`     | in (list)             | Field value is one of several target values (provide a JSON array) |
| `exists` | exists                | Field has any value (is not null, undefined, or empty string)      |

### Value

The value you compare against. How you enter it depends on the operator:

| Operator                 | Value format               | Example                      |
| ------------------------ | -------------------------- | ---------------------------- |
| `eq`, `neq`              | Text or number             | `completed`, `3`, `true`     |
| `gt`, `lt`, `gte`, `lte` | Number                     | `5`, `60`, `2.5`             |
| `in`                     | JSON array                 | `["completed", "voicemail"]` |
| `exists`                 | Not required (leave empty) |                              |

The value field automatically parses JSON. If you type `3`, it's treated as the number 3. If you type `true`, it's treated as boolean true. If you need the literal string `"true"`, wrap it in quotes: `"true"`.

***

## Branching

### Then (on true)

Steps added to the **Then** branch run only when the condition evaluates to true. You can add any step type inside a branch — Transform, Destination, Upsert Contact, or even another Condition.

### Otherwise (on false)

Steps added to the **Otherwise** branch run only when the condition evaluates to false. This branch is optional. If you leave it empty, the pipeline simply skips it and continues.

### After the condition

Any steps placed after the condition step in the main pipeline run regardless of which branch was taken. Use this for steps that should always execute.

***

## Nesting Conditions

You can place a Condition inside another Condition's branch to create multi-level logic. Nesting is limited to **2 levels deep**.

```text theme={null}
Condition: call.status = "completed"
  |
  |-- Then:
  |     Condition: call.structured_data.rating < 3      (nested, level 2)
  |       |-- Then: SMS to team ("Low rating alert")
  |       |-- Otherwise: Email to contact ("Thanks!")
  |
  |-- Otherwise:
  |     SMS to team ("Call did not complete")
```

This example:

1. First checks if the call completed
2. If yes, checks whether the rating was low
3. Sends different notifications depending on the outcome

***

## Common Patterns

### Route by call status

Branch on whether the call was successful:

* **Field:** `call.status`
* **Operator:** `eq`
* **Value:** `completed`
* **Then:** Sync results to CRM, send follow-up email
* **Otherwise:** Alert the team to retry or follow up manually

### Route by call outcome

Use structured data fields from your Script to route based on what happened during the call:

* **Field:** `call.structured_data.appointment_booked`
* **Operator:** `eq`
* **Value:** `true`
* **Then:** Send confirmation email, update CRM status to "Booked"
* **Otherwise:** Send nurture email, update CRM status to "Follow up"

### Flag low ratings

Alert your team when a customer gives a low satisfaction score:

* **Field:** `call.structured_data.rating`
* **Operator:** `lte`
* **Value:** `2`
* **Then:** SMS to team with call summary, email to customer success manager
* **Otherwise:** (skip)

### Check for missing data

Only proceed if a required field exists:

* **Field:** `contact.email`
* **Operator:** `exists`
* **Then:** Send follow-up email to contact
* **Otherwise:** (skip — no email available)

### Route by end reason

Branch based on how the call ended — useful for distinguishing voicemail from hangups:

* **Field:** `call.end_reason`
* **Operator:** `eq`
* **Value:** `voicemail`
* **Then:** Sync to CRM as "Left voicemail", schedule retry
* **Otherwise:** (skip)

### Route by multiple values

Check if the call ended in one of several statuses:

* **Field:** `call.status`
* **Operator:** `in`
* **Value:** `["User unavailable", "rang-out", "failed"]`
* **Then:** Schedule a retry call via webhook
* **Otherwise:** (skip — call was answered)

### Escalate based on a threshold

If the call lasted less than 30 seconds, it likely didn't go well:

* **Field:** `call.duration`
* **Operator:** `lt`
* **Value:** `30`
* **Then:** SMS to team — "Very short call with \{\{contact.full\_name}} (\{\{call.duration}}s). May need manual follow-up."
* **Otherwise:** (skip)

### Branch by trigger data

Route differently based on data from the incoming webhook:

* **Field:** `trigger.priority`
* **Operator:** `eq`
* **Value:** `high`
* **Then:** Create Call immediately using priority Script
* **Otherwise:** Create Call using standard Script

***

## Tips

* **Keep conditions simple.** One condition checking one field is easier to debug than nested logic. If you find yourself nesting 2 levels deep, consider whether two separate automations would be clearer.
* **Check the Execution Log.** When a condition branch is not taken, the log shows that branch as "Skipped" in grey. This makes it easy to verify your conditions are evaluating as expected.
* **Use `exists` before accessing optional data.** If a field might not be present (e.g., `contact.email` for contacts without an email), use an `exists` condition before steps that depend on it.
* **Numeric comparisons require numeric values.** If your structured data field contains a string like `"4"`, the comparison still works — but make sure the Value field is also entered as a number (`4`, not `"4"`).
* **The `in` operator expects a JSON array.** Enter the value as `["option1", "option2"]` with square brackets and quotes around strings.
