# Automation Code Steps

{% hint style="success" %}
**Audience:** Developers

**Purpose:** Explains how Automation Code Steps work in <code class="expression">space.vars.Kizen\_company\_name</code> and provides guidance for writing, executing, and managing custom JavaScript within automations.
{% endhint %}

## Overview

Code steps provide powerful, secure, and flexible scripting to <code class="expression">space.vars.Kizen\_company\_name</code> Automations using Python. Code Steps natively integrate with automation variables and field values from your custom object entities. All code runs in an isolated container.

### Available Runtimes <a href="#available-runtimes" id="available-runtimes"></a>

* Python 3.12
* Python 3.13

In addition to packages included in the Python Standard Library, the following packages come pre-installed:

* awslambdaric
* bcrypt
* fpdf2
* lxml
* msgpack
* numpy
* paramiko
* pyjwt
* pypdf
* pytz
* requests
* tzdata

{% hint style="info" %}
**Note:** If you have a library you would like for us to consider adding, send us a note at <support@kizen.com>.
{% endhint %}

### Limits <a href="#limits" id="limits"></a>

* 1 GB RAM
* 30 sec execution time

For more information see, [Log Message Limits](#log-message-limits).

***

## Using Inputs and Generating Outputs <a href="#using-inputs-and-generating-outputs" id="using-inputs-and-generating-outputs"></a>

Your python code will access input data in an object named `inputs` and write to an object named `outputs`. The names of the attributes are set when you select inputs and outputs in your <code class="expression">space.vars.Kizen\_company\_name</code> Automation.

This example assumes an input called “name” and an output called “greeting”

```python
outputs.greeting = "hello, " + inputs.name + "!"
```

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2Fb36Xr0oSCJgwSoza36f4%2FScreenshot-2025-06-26-at-3.23.58%E2%80%AFPM.png?alt=media&#x26;token=b3e6d35f-4106-4304-9b63-aa830feda2a1" alt=""><figcaption></figcaption></figure></div>

***

## Logging <a href="#logging" id="logging"></a>

You may write logs using the provided `outputs.log()` function.

Example:

```python
from datetime import datetime
outputs.log(f"Started at: {datetime.now()}")
```

To view these logs:

1\. Open the Automation History, for example by navigating to entity record you’ve run this automation on, and clicking the “Automation Name” for an execution in the list.

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2FbYvj7dmfPnvFeedBGepP%2FScreenshot-2025-06-26-at-3.36.26%E2%80%AFPM.png?alt=media&#x26;token=eb117ceb-0cf3-42e5-a2dc-26f720e03e6a" alt=""><figcaption></figcaption></figure></div>

2. Then — in the Automation History view — click the Execution Status in Code Step Action (the word “Completed” in the screenshot):

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2FnmAYSyijNmFsVUkS13sk%2FScreenshot-2025-06-26-at-3.31.51%E2%80%AFPM.png?alt=media&#x26;token=606a629d-b641-4ce4-903c-a8cc612ed777" alt=""><figcaption></figcaption></figure></div>

3. You will see your Execution details, including any logs you’ve written:

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2Fnb0i6P3Wa6bxIDSzDRbz%2FScreenshot-2025-06-26-at-3.31.59%E2%80%AFPM.png?alt=media&#x26;token=37f33700-cedc-4d08-b2e3-c8c1d4a354a2" alt=""><figcaption></figcaption></figure></div>

### Log Message Limits

Each call to `output.logs()` supports a maximum message size of **8 KB**. Messages that exceed this limit are truncated.

In addition, the **combined size of all log messages** generated during a single code step execution is limited to **100 KB**. Once this limit is reached, any additional log messages are discarded.

To avoid losing diagnostic information:

* Keep log messages short and focused
* Avoid logging large data structures or verbose output, especially inside loops
* For larger content, write values to fields or upload files, which support larger data sizes

***

## Validating Inputs and Raising Errors <a href="#validating-inputs-and-raising-errors" id="validating-inputs-and-raising-errors"></a>

You can [raise an Exception](https://docs.python.org/3/library/exceptions.html) to immediately stop execution of your Python code due to invalid data or other unexpected cases.

```python
outputs.log("Checking for Aristotle...")

if inputs.first_name == 'Aristotle':
    raise ValueError("Unexpected Mathematician")
else:
    outputs.greeting = f"Hello, {inputs.first_name}!"
```

This error will be visible in the Execution details:

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2Foey9JTaC7Uy778BwJByw%2FScreenshot-2025-06-26-at-4.18.00%E2%80%AFPM.png?alt=media&#x26;token=bbc1f73a-526d-4513-904f-af6e6ac063de" alt=""><figcaption></figcaption></figure></div>

A successful execution will show the inputs, outputs, and logs (more detail on the encoding of inputs and outputs later in this document):

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2FWRqvGwpl2TIHefbvQHDl%2FScreenshot-2025-06-26-at-4.20.22%E2%80%AFPM.png?alt=media&#x26;token=4af91647-bda7-44dc-8e9b-ab11972e418b" alt=""><figcaption></figcaption></figure></div>

***

## Making HTTP Requests <a href="#making-http-requests" id="making-http-requests"></a>

The ability to send HTTP requests enables powerful, flexible integrations.

```python
import requests

resp = requests.post(
  "https://httpbin.org/anything",
  json={"greeting": "Hello, world!"}
)
outputs.log(f"Got {len(resp.content)} bytes")
```

### Integration Secrets <a href="#integration-secrets" id="integration-secrets"></a>

You may also configure your Code Step with access to use Integration Secrets.

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2F8fgoXDts95NaWOqdlcOY%2FScreenshot-2025-06-26-at-4.39%E2%80%AFPM.png?alt=media&#x26;token=0d4ce5d7-ed08-4c53-ad09-a5fcf655c3b6" alt=""><figcaption></figcaption></figure></div>

```python
import requests

my_secret = secrets["magicword"]

resp = requests.get(
    "https://httpbin.org/anything",
    headers={"Authorization": f"Bearer {my_secret}"}
)
outputs.log(resp.text)
```

### HTTP Request Logs <a href="#http-request-logs" id="http-request-logs"></a>

In addition to messages you log directly in your code, HTTP requests are logged automatically.

In your HTTP request logs you’ll find:

* Total number of HTTP requests sent
* Detailed logs of the first 100 requests sent:
  * HTTP Method
  * URL
  * Request and Response Headers
  * Request Body (truncated to the first 1 kB)
* Number of requests sent without capturing detailed logs (due to exceeding the 100-request threshold)

This info will appear in the Execution Details:

<div data-with-frame="true"><figure><img src="https://3898351136-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQd8ufpN7wkdnx7JtgoeZ%2Fuploads%2Fh48OH4VFzEOsYlfTAWLN%2FScreenshot-2025-06-26-at-3.56.47%E2%80%AFPM.png?alt=media&#x26;token=139fd0ff-28c8-4155-bec7-25533f33e807" alt=""><figcaption></figcaption></figure></div>

***

## Kizen Data Types and Data Encoding <a href="#kizen-data-types-and-data-encoding" id="kizen-data-types-and-data-encoding"></a>

When you view the Automation History for a Code Step, or use the Immediate/sync API for CodeRunner you will see your <code class="expression">space.vars.Kizen\_company\_name</code> values encoded as JSON using the following scheme:

<table data-header-hidden><thead><tr><th>Data Type</th><th>Type Code</th><th>Example</th></tr></thead><tbody><tr><td>Boolean</td><td>b</td><td><pre class="language-json"><code class="lang-json">{"t": "b", "v": "false"}
</code></pre></td></tr><tr><td>Date</td><td>d</td><td><pre class="language-json"><code class="lang-json">{"t": "d", "v": "2024-12-25"}
</code></pre></td></tr><tr><td>DateTime</td><td>dt</td><td><pre class="language-json"><code class="lang-json">{"t": "dt", "v": "2024-03-14T01:59:26.535897+00:00"}
</code></pre></td></tr><tr><td>Number</td><td>n</td><td><pre class="language-json"><code class="lang-json">{"t": "n", "v": "3.14"}
</code></pre></td></tr><tr><td>Phone Number</td><td>p</td><td><pre class="language-json"><code class="lang-json">{"t": "p", "v": "+15125551212"}
</code></pre></td></tr><tr><td>String</td><td>s</td><td><pre class="language-json"><code class="lang-json">{"t": "s", "v": "Hello, World!"}
</code></pre></td></tr><tr><td>UUID</td><td>u</td><td><pre class="language-json"><code class="lang-json">{"t": "u", "v": "c6f9fe22-9d2c-4dca-9380-ab9733c85303"}
</code></pre></td></tr><tr><td>Entity Record</td><td>e&#x3C;uuid></td><td><p>The UUID in the type code indicates which Custom Object the entity is part of.<br></p><pre class="language-json"><code class="lang-json">{
  "t": "e&#x3C;06e86916-cc8e-4622-af2f-8e9c08e9225b>",
  "v": "643eb36c-744c-4928-8e21-077acb65eaef"
}
</code></pre></td></tr><tr><td>Field Option</td><td>o&#x3C;uuid,uuid></td><td><p>The first UUID in the type code is the Custom Object id, the second UUID is the Field id.<br></p><pre class="language-json"><code class="lang-json">{
  "t": "o&#x3C;f87c4d49-9de2-4701-a7d1-73eda1783e25,28ca3e62-592e-4036-a7a9-0e2fd500d8f5>",
  "v": "24fb871d-f1df-42a9-8dac-1adb24bb03f6"
}
</code></pre></td></tr><tr><td>Array (typed)</td><td>a[...]</td><td><pre class="language-json"><code class="lang-json">{
  "t": "a[s]",
  "v": ["Einstein", "Newton", "Pythagoras"]
}
</code></pre></td></tr><tr><td>List (untyped)</td><td>l</td><td><p><strong>Note:</strong> Values are individually encoded, may be an empty list, and may be <code>null</code>.<br></p><pre class="language-json"><code class="lang-json">{
  "t": "l",
  "v": [
    {"t": "b", "v": "false"},
    {"t": "d", "v": "2024-12-25"}
  ]
}
</code></pre></td></tr><tr><td>File</td><td>f</td><td><p><strong>Note:</strong> The value will be a valid file ID.</p><pre class="language-json"><code class="lang-json">{"t": "f","v": "c6f9fe22-9d2c-4dca-9380-ab9733c85303"}
</code></pre></td></tr></tbody></table>

***

## Working with Typed Python Objects

Certain field values are automatically converted to strongly-typed Python objects with convenient properties. These objects extend UUID, so they still work anywhere a UUID is expected (comparisons, `str()`, etc.) while providing direct access to metadata.

### KizenFile

File field values are converted to `KizenFile` objects with the following properties:

| Property       | Type  | Description                                                     |
| -------------- | ----- | --------------------------------------------------------------- |
| `url`          | `str` | Presigned S3 URL for downloading the file, valid for 10 minutes |
| `name`         | `str` | Original filename                                               |
| `size`         | `int` | File size in bytes                                              |
| `content_type` | `str` | MIME content type (e.g., "application/pdf")                     |

```python
# Accessing a file field
contract = inputs.contract_file

outputs.log(f"File: {contract.name} ({contract.size} bytes)")

# Download the file content
import requests
response = requests.get(contract.url)
content = response.content
```

### FieldOption

Values from dropdown, radio, checkboxes, tags, and yesnomaybe fields are converted to `FieldOption` objects:

| Property | Type  | Description                |
| -------- | ----- | -------------------------- |
| `name`   | `str` | Display name of the option |
| `order`  | `int` | Sort order                 |
| `code`   | `str` | Option code identifier     |

```python
# Accessing a dropdown field
status = inputs.lead_status

outputs.log(f"Status: {status.name}")  # "Qualified"
outputs.log(f"Code: {status.code}")    # "qualified"

# Still works as UUID for comparisons
outputs.log(str(status))  # "24fb871d-f1df-42a9-8dac-1adb24bb03f6"
```

#### Multi-Select Fields

For multi-select fields (checkboxes, tags), you receive a list of `FieldOption` objects:

```python
# Iterate over selected tags
for tag in inputs.interest_tags:
    outputs.log(f"{tag.name} (code: {tag.code})")
```

### Stage

Pipeline stage field values are converted to `Stage` objects with additional stage-specific properties:

| Property                     | Type  | Description                            |
| ---------------------------- | ----- | -------------------------------------- |
| `name`                       | `str` | Stage name                             |
| `order`                      | `int` | Sort order                             |
| `status`                     | `str` | Stage status: "open", "won", or "lost" |
| `percentage_chance_to_close` | `int` | Win probability (0-100)                |

```python
# Accessing a pipeline stage field
stage = inputs.deal_stage

outputs.log(f"Stage: {stage.name}")           # "Negotiation"
outputs.log(f"Win chance: {stage.percentage_chance_to_close}%")  # 60

# Check deal outcome
if stage.status == "won":
    outputs.result = "Deal closed!"
elif stage.status == "lost":
    outputs.result = "Schedule re-engagement"
```
