> ## 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.

# Code Step Examples

> Common Code Step patterns — validation, counters, JSON parsing, multi-condition routing — plus troubleshooting.

## Validation

Contact email is available:

```python theme={null}
def run():
    email = {{contact.email}}
    {{contact.email_verified}} = bool(email and "@" in email)
    return {{contact.email_verified}}
```

Contact phone is SMS capable:

```python theme={null}
def run():
    phone = {{contact.phone}}
    return str(phone or "").startswith("+614")
```

Email regex check:

```python theme={null}
def run():
    email = {{contact.email}}
    {{contact.email_verified}} = regex_match(r"^[^@\s]+@[^@\s]+\.[^@\s]+$", email)
    return {{contact.email_verified}}
```

Strict ISO date check:

```python theme={null}
def run():
    value = {{contact.date_of_birth}}
    return regex_match(r"^\d{4}-\d{2}-\d{2}$", value)
```

***

## JSON

Build and store a payload:

```python theme={null}
def run():
    payload = {
        "email": {{contact.email}},
        "first_name": {{contact.first_name}},
        "has_email": bool({{contact.email}})
    }
    {{webhook.response}} = json_dumps(payload)
    return True
```

Parse a webhook response and route on it:

```python theme={null}
def run():
    raw = {{webhook.response}}
    data = json_loads(raw or "{}")
    has_email = bool(data.get("email"))
    has_phone = bool(data.get("phone"))
    return has_email, has_phone
```

***

## Lists and Randomization

Build a numbered list in a random order with `range`, `enumerate`, `append`, and `random_shuffle`:

```python theme={null}
def run():
    options = random_shuffle(["sales", "support", "billing"])
    numbered = []
    for index, option in enumerate(options):
        numbered.append(str(index + 1) + ". " + option)
    {{surveys.temp_order_options}} = json_dumps(numbered)
    return True
```

Sum a range:

```python theme={null}
def run():
    total = 0
    for value in range(1, 5):
        total = total + value
    {{temp.number.num_1}} = total
    return total == 10
```

***

## Debugging With `print`

Write resolved values to the call's system notes while the step runs:

```python theme={null}
def run():
    email = {{contact.email}}
    phone = {{contact.phone}}
    print("contact:", email, phone)
    return bool(email), bool(phone)
```

Unquoted placeholders print the resolved value; quoted placeholders stay literal. Each `print(...)` becomes a system note before the final run success note.

***

## Routing With Multiple Conditions

A Code Step can return more than one boolean. Returned booleans map to the step's `conditions` array **by index**:

* Output index `0` → `conditions[0]`
* Output index `1` → `conditions[1]`
* Output index `2` → `conditions[2]`
* The final condition should be `"otherwise"` and acts as the fallback

If all returned booleans are false, the step routes to the final condition. If multiple are true, the **first true output index wins**.

### Counter example

This starts at `1` and increments each time the step runs:

```python theme={null}
def run():
    count = {{auth_check.matched_count}} or 0
    count = int(count) + 1
    {{auth_check.matched_count}} = count
    return bool(count == 1), bool(count == 2)
```

* First run → `(True, False)` → routes to `conditions[0]`
* Second run → `(False, True)` → routes to `conditions[1]`
* Third run → `(False, False)` → routes to the final `"otherwise"` condition

### Single-boolean tools

All tools use the same condition-array routing. For a single boolean output, `True` routes to the first condition and `False` routes to the final one. Return multiple booleans only when a step needs more than true/otherwise routing.

***

## Troubleshooting

### `Code Step must contain exactly one top-level def run():`

Missing `def run():`, extra top-level statements, or more than one function. Move setup inside `run()`:

```python theme={null}
def run():
    flag = True
    return flag
```

### `unindent does not match any outer indentation level`

Inconsistent indentation, or leading spaces before `def run():`. `def run():` must start at the first column.

### `name 'input_1' is not defined`

The code references `input_1`, but that input isn't mapped on the step. Map the additional input, or remove the reference.

### `Function 'x' is not allowed` / `Method 'x' is not allowed`

The code called something off the allow-list. Use an allowed equivalent:

```python theme={null}
# Invalid
def run():
    return isinstance({{contact.email}}, str)

# Valid
def run():
    return is_string({{contact.email}})
```

```python theme={null}
# Invalid
def run():
    return {{contact.phone}}.removeprefix("+")

# Valid
def run():
    value = str({{contact.phone}} or "")
    return value.replace("+", "").startswith("614")
```

See [Allowed Functions](/tools/code-step/functions) for the full list.

### `run() must return bool or list/tuple of bools`

The return value isn't a boolean or ordered booleans. Wrap results in `bool(...)`.

### Counter does not increment

Make sure the same variable placeholder is used for both the read and the write. If the read and write paths differ, the counter appears to reset.

### Branch goes to the wrong step

Multi-output routing uses condition-array indexes, not matching values. Condition `order` controls the sort before routing — verify the stored order matches the intended array order.

***

## Next Steps

* [Code Step overview](/tools/code-step/overview) — The `run()` contract and variables
* [Allowed Functions](/tools/code-step/functions) — The full deny-by-default allow-list
* [Tool Steps](/flows/steps-tool) — How tool steps and conditions work
