# 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"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developer.kizen.com/docs/concepts/automations/automation-code-steps.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
