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

# Actions Reference

> Complete reference guide for all automation actions with configuration details, conditions, and walkthrough examples

This reference covers every action available in the Elementum automation builder. Each section explains what the action does, how to configure it, and walks through a realistic scenario so you can see how it works in practice.

<Info>
  New to automations? Start with the [Automation System](/workflows/automation-system) guide to learn how triggers, conditions, and actions fit together.
</Info>

## Inspect Trigger and Action Outputs While Building

As you build an automation, every trigger and action lists the variables it produces in an **Outputs** section at the bottom of its configuration pull-out. Each entry shows the variable name (for example, `textResult`, `result.project_name`, `create_record.id`) and its data type (Text, Decimal, Date, and so on), with a checkbox next to each one.

Use this section to:

* **Confirm available variables** — Verify the exact name and type of every output before referencing it in a later step.
* **Select which outputs to expose** — Toggle the checkbox next to each variable to control whether it's surfaced to downstream actions.
* **Catch missing values early** — If a variable you expect isn't listed, the step isn't producing it yet (a script may need to be re-executed so its output schema picks up the new property, an action may need to be re-tested, and so on).

Checking the Outputs section as you configure each step is the fastest way to confirm that variable names match what you expect — without having to publish and run a full automation trace.

## Logic Actions

Logic actions control which path your automation takes. They let you branch based on data values, check multiple criteria, and loop through collections of records.

### If / Otherwise If / Otherwise

The **If** action creates a decision point. You define a condition, and the actions nested beneath it only run when that condition is true. **Otherwise If** adds additional branches, and **Otherwise** catches everything that didn't match a previous branch.

#### How Conditions Work

Each condition compares a value from your automation (a field on the trigger record, an output from a previous action, or a variable) against a target value using an operator.

A single condition has three parts:

| Part         | What it means                                                                         | Example                                                            |
| ------------ | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| **Value**    | The data you want to check — select from trigger fields, action outputs, or variables | `trigger.priority`                                                 |
| **Operator** | How to compare the value                                                              | `equals`, `does not equal`, `greater than`, `contains`, `is empty` |
| **Target**   | What you're comparing against — a static value, another field, or a variable          | `"Critical"`                                                       |

#### Combining Multiple Conditions

When a single comparison isn't enough, add more conditions to the same If block. You connect them with **AND** or **OR**:

* **AND** — Every condition must be true. Use this when you need all criteria met.
* **OR** — At least one condition must be true. Use this when any one criterion is enough.

**Example**: Route only high-value enterprise tickets to the priority queue:

| Condition       | Operator     | Target       | Connector |
| --------------- | ------------ | ------------ | --------- |
| `customer_tier` | equals       | `Enterprise` | AND       |
| `order_amount`  | greater than | `10000`      | —         |

Both must be true for the actions beneath this If to run.

#### Condition Groups

When your logic mixes AND with OR, use **condition groups** to control evaluation order — similar to how parentheses work in math.

Without groups, the automation evaluates conditions strictly top to bottom, which can produce unexpected results. Groups let you say "evaluate these conditions together first, then combine the result with the rest."

**Scenario**: You want to escalate a support ticket when the customer is Enterprise tier AND the issue is either Critical priority OR has been open for more than 48 hours.

Without condition groups, you'd have no way to express "Critical OR open 48+ hours" as a unit. With groups:

| Group       | Condition       | Operator     | Target       | Connector |
| ----------- | --------------- | ------------ | ------------ | --------- |
| —           | `customer_tier` | equals       | `Enterprise` | AND       |
| **Group 1** | `priority`      | equals       | `Critical`   | OR        |
| **Group 1** | `hours_open`    | greater than | `48`         | —         |

This reads as: customer is Enterprise **AND** (priority is Critical **OR** hours open is greater than 48).

To create a condition group in the automation builder, click **Add Condition Group** in the If action's configuration panel. Drag conditions into or out of groups to restructure your logic.

#### Building Multi-Branch Decisions

Use **Otherwise If** and **Otherwise** to handle different outcomes in a single automation instead of building separate automations for each scenario.

<Tabs>
  <Tab title="Scenario">
    An order comes in and needs different approval paths depending on the amount:

    1. **If** `order_amount` is greater than `10,000` — route to CFO for approval
    2. **Otherwise If** `order_amount` is greater than `1,000` — route to the department manager
    3. **Otherwise** (all remaining orders) — mark as auto-approved
  </Tab>

  <Tab title="How it evaluates">
    Elementum checks branches top to bottom and runs the **first one that matches**:

    * A \$15,000 order matches the first If, so it goes to the CFO. The remaining branches are skipped.
    * A \$3,000 order fails the first If (not greater than 10,000), matches the Otherwise If, and goes to the department manager.
    * A \$500 order fails both conditions, so it falls through to Otherwise and is auto-approved.
  </Tab>
</Tabs>

**Variables**: Each If and Otherwise If outputs a boolean (`true` or `false`) that downstream actions can reference to check which branch ran.

### Repeat for Each

Loops through a collection of records or data items and runs the same set of actions on each one. The collection typically comes from a **Search Records** or **Find Related Records** action earlier in the automation.

**Configuration**:

| Field          | Description                                                                                   |
| -------------- | --------------------------------------------------------------------------------------------- |
| **Collection** | The list to iterate over — select from outputs of previous actions that return multiple items |
| **Actions**    | Drag actions inside the Repeat for Each block to run them on every item                       |

**Variables**: Inside the loop, you have access to:

| Variable | Description                                                                                                     |
| -------- | --------------------------------------------------------------------------------------------------------------- |
| `item`   | The current record or data item in the loop, with all its fields accessible (e.g., `item.email`, `item.status`) |
| `index`  | The current iteration number (starting from 0)                                                                  |

<Tabs>
  <Tab title="Scenario">
    An automation runs at the end of each day to send shipping confirmations for all orders placed that day.

    1. **Search Records** finds all orders with `status = "Ready to Ship"` and `created_date = today`
    2. **Repeat for Each** iterates over the search results
    3. Inside the loop, for each order: **Run Calculation** computes the shipping cost, **Update Record Fields** sets the shipping amount and changes status to "Shipped", and **Send Email Notification** sends a confirmation to the customer
  </Tab>

  <Tab title="Performance tip">
    Each iteration adds execution time, especially if the loop body includes API calls or AI actions. Filter your collection as tightly as possible before entering the loop — use specific Search Records conditions rather than searching broadly and filtering inside the loop.
  </Tab>
</Tabs>

***

## Record Actions

Record actions create, update, search, and manage records and their relationships.

<AccordionGroup>
  <Accordion title="Create Record" icon="plus">
    Creates a new record in a specified element or table, populating fields from trigger data, action outputs, or static values.

    **Configuration**:

    | Field              | Description                                                                                                             |
    | ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
    | **Action Name**    | A descriptive name for this action                                                                                      |
    | **Element/Table**  | Which element or table to create the record in                                                                          |
    | **Field Mappings** | Map fields on the new record to values — select from trigger variables, previous action outputs, or enter static values |

    **Variables**: Outputs the new record ID and all field values, accessible as `create_record.id`, `create_record.{field_name}`, etc.

    <Tabs>
      <Tab title="Scenario">
        When a customer sends an email to your support address, automatically create a support ticket:

        1. **Email Received** trigger fires
        2. **Search Records** finds the customer by `trigger.sender_email`
        3. **Create Record** creates a new Support Ticket with:
           * Subject → `trigger.subject`
           * Customer → `search_records.customer`
           * Description → `trigger.body`
           * Status → `"New"`
           * Source → `"Email"`
      </Tab>

      <Tab title="Tip">
        Set all field values in the Create Record action itself rather than creating the record and then immediately updating it with a separate Update Record Fields action. This saves an extra round-trip and makes the automation faster.
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Update Record Fields" icon="pencil">
    Modifies one or more field values on an existing record.

    **Configuration**:

    | Field              | Description                                                                              |
    | ------------------ | ---------------------------------------------------------------------------------------- |
    | **Action Name**    | A descriptive name for this action                                                       |
    | **Record**         | Which record to update — typically the trigger record or a record from a previous action |
    | **Field Mappings** | Map fields to new values from trigger data, action outputs, or static values             |

    **Variables**: Outputs the updated record with its new field values.

    <Tabs>
      <Tab title="Scenario">
        After AI classifies a support ticket, update the ticket with the classification results:

        1. **AI Classification** analyzes the ticket description and returns `category` and `confidence`
        2. **Update Record Fields** sets:
           * Category → `ai_classification.category`
           * Priority → `ai_classification.confidence > 0.8 ? "High" : "Normal"` (via a preceding Run Calculation)
           * Classification Confidence → `ai_classification.confidence`
      </Tab>

      <Tab title="Tip">
        Consolidate multiple field updates into a single Update Record Fields action instead of using several in a row. Each action that touches the record adds latency.
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Relate Records" icon="link">
    Establishes a relationship link between two records, enabling cross-record data access in views and subsequent automation steps.

    **Configuration**:

    | Field             | Description                        |
    | ----------------- | ---------------------------------- |
    | **Action Name**   | A descriptive name for this action |
    | **Source Record** | The record to relate from          |
    | **Target Record** | The record to relate to            |
    | **Relationship**  | The relationship type to create    |

    **Variables**: Outputs relationship details and connected record information.

    **When to use**: After creating a new record that needs to be linked to an existing one — for example, linking a newly created project record to the customer who requested it.
  </Accordion>

  <Accordion title="Search Records" icon="filter">
    Queries a table and returns records matching your criteria, making them available as variables for downstream actions.

    **Configuration**:

    | Field             | Description                                                                                  |
    | ----------------- | -------------------------------------------------------------------------------------------- |
    | **Action Name**   | A descriptive name for this action                                                           |
    | **Element/Table** | Which element or table to search                                                             |
    | **Conditions**    | Filter criteria using the same condition builder as If actions — value, operator, and target |

    Conditions in Search Records work the same way as [If conditions](#how-conditions-work): pick a field, choose an operator, and set a target value. You can add multiple conditions with AND/OR connectors and use condition groups for complex queries.

    **Variables**: Outputs matching records as a collection. Use `search_records.{field_name}` to access the first result, or feed the collection into a **Repeat for Each** to process multiple matches.

    <Tabs>
      <Tab title="Scenario">
        When processing an incoming email, find the customer record to link with the new ticket:

        1. **Search Records** on the Customers element
        2. Condition: `email` equals `trigger.sender_email`
        3. If a match is found, use `search_records.customer` in the Create Record action to link the ticket to the customer
      </Tab>

      <Tab title="Search Records vs. AI Data Search">
        Use **Search Records** when you're looking up records by exact field values — email addresses, IDs, status values.

        Use **AI Data Search** when the input is natural language or free-form text — a ticket description, a customer question — and you want semantically similar results rather than exact matches.
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Start Approval Process" icon="check">
    Initiates a configured approval workflow for a record, sending notifications to designated approvers.

    **Configuration**:

    | Field                | Description                                               |
    | -------------------- | --------------------------------------------------------- |
    | **Action Name**      | A descriptive name for this action                        |
    | **Approval Process** | Select an existing approval process configured in the app |
    | **Record**           | The record to submit for approval                         |

    The approval process itself (approvers, stages, escalation rules) is configured separately under the app's [Approval Processes](/workflows/approval-processes) settings. This action starts that process for a specific record.

    **Variables**: Outputs the approval process ID and current status.
  </Accordion>

  <Accordion title="Update Approval Status" icon="repeat">
    Changes the status of an active approval process, advancing or halting the workflow.

    **Configuration**:

    | Field           | Description                                            |
    | --------------- | ------------------------------------------------------ |
    | **Action Name** | A descriptive name for this action                     |
    | **Status**      | The new status to set — Approved, Rejected, or Pending |

    **Variables**: Outputs the new approval status and workflow state.
  </Accordion>

  <Accordion title="Add Watcher" icon="eye">
    Subscribes one or more users to a record so they receive in-platform notifications when the record changes.

    **Configuration**:

    | Field           | Description                                                                                             |
    | --------------- | ------------------------------------------------------------------------------------------------------- |
    | **Action Name** | A descriptive name for this action                                                                      |
    | **Record**      | The record to add watchers to                                                                           |
    | **Users**       | Which users to subscribe — from a previous Search Users action, a static user, or a field on the record |

    **When to use**: When someone needs visibility into a record's progress without being the assignee — for example, adding a department manager as a watcher on all high-priority issues.
  </Accordion>

  <Accordion title="Record Field Locking" icon="lock">
    Prevents changes to specified fields on a record, protecting data integrity after a process completes.

    **Configuration**:

    | Field           | Description                        |
    | --------------- | ---------------------------------- |
    | **Action Name** | A descriptive name for this action |
    | **Record**      | The record to lock fields on       |
    | **Fields**      | Which fields to lock               |

    **When to use**: After an approval process completes, lock the approved values (price, terms, quantities) so they can't be changed without going through the approval process again.
  </Accordion>

  <Accordion title="Make Assignment" icon="user-plus">
    Assigns a record to a specific user or team.

    **Configuration**:

    | Field           | Description                                                                       |
    | --------------- | --------------------------------------------------------------------------------- |
    | **Action Name** | A descriptive name for this action                                                |
    | **Record**      | The record to assign                                                              |
    | **Assignee**    | A user or team — from a Search Users result, a static value, or a field reference |

    **When to use**: After classification or routing logic determines who should handle a record. Often paired with an If action or AI Classification to route to the right team based on the record's content.

    <Tabs>
      <Tab title="Scenario">
        Route support tickets to the right team based on AI classification:

        1. **AI Classification** categorizes the ticket as Technical, Billing, or General
        2. **If** `ai_classification.category` equals `"Technical"` → **Make Assignment** to Technical Support team
        3. **Otherwise If** `ai_classification.category` equals `"Billing"` → **Make Assignment** to Billing team
        4. **Otherwise** → **Make Assignment** to General Support queue
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Find Related Records" icon="sitemap">
    Returns all records related to a given record, making them available for downstream actions.

    **Configuration**:

    | Field            | Description                          |
    | ---------------- | ------------------------------------ |
    | **Action Name**  | A descriptive name for this action   |
    | **Record**       | The record to find relationships for |
    | **Relationship** | Which relationship type to follow    |

    **Variables**: Outputs a collection of related records. Feed into a **Repeat for Each** to process each one, or access the collection's count to make decisions.

    **When to use**: When you need context from linked records before making a decision — for example, pulling a customer's order history before classifying a support ticket's priority.
  </Accordion>

  <Accordion title="Generate Report" icon="chart-bar">
    Compiles data into a formatted Excel or PDF [report](/data/reports) file that subsequent actions can reference.

    <Warning>
      Generate Report creates the file but does not save it to a record. Use **Save Attachment** after this action to persist the file, or include it in a **Send Email Notification** as an attachment.
    </Warning>

    **Configuration**:

    | Field           | Description                                     |
    | --------------- | ----------------------------------------------- |
    | **Action Name** | A descriptive name for this action              |
    | **Report**      | Select an existing report configured in the app |

    **Variables**:

    | Variable           | Type | Description                                                                                            |
    | ------------------ | ---- | ------------------------------------------------------------------------------------------------------ |
    | `generated_report` | File | The report file (Excel or PDF) for use in Save Attachment, Send Email, or other file-accepting actions |

    <Tabs>
      <Tab title="Scenario">
        Generate and distribute a monthly performance report:

        1. **Time-Based** trigger fires on the first of each month
        2. **Generate Report** creates the Sales Performance Summary
        3. **Save Attachment** attaches the report to the monthly reporting record
        4. **Send Email Notification** sends the report to stakeholders with the file attached
      </Tab>
    </Tabs>
  </Accordion>
</AccordionGroup>

***

## Elementum Intelligence Actions

Intelligence actions use AI to analyze, classify, summarize, transform, and search your data. They accept unstructured input and return structured output that subsequent actions can use.

<AccordionGroup>
  <Accordion title="Run Agent Task" icon="robot">
    Passes a task to a configured AI agent, which works autonomously and returns structured or text output. This is the most flexible intelligence action — use it when the other specialized actions (Classification, Summarization, etc.) don't cover your needs.

    **Configuration**:

    | Field               | Description                                                                                               |
    | ------------------- | --------------------------------------------------------------------------------------------------------- |
    | **Action Name**     | Descriptive name for the agent task                                                                       |
    | **AI Agent**        | Select an existing agent or create a new one                                                              |
    | **Task Definition** | What the agent should accomplish — supports `{{value_references}}` from trigger data and previous actions |
    | **Output Type**     | **Text** (free-form response) or **Structured** (specific fields you define)                              |
    | **Output Fields**   | (Structured mode only) The fields the agent should return, with names and types                           |

    **Variables**:

    | Variable                         | Description                                  |
    | -------------------------------- | -------------------------------------------- |
    | `run_agent_task.success`         | Boolean — whether the task completed         |
    | `run_agent_task.error_message`   | Error details if the task failed             |
    | `run_agent_task.{custom_fields}` | Your defined output fields (Structured mode) |

    The agent runs in a headless environment with no user interaction, so the task definition must include all necessary context. Built-in retry logic (up to 3 attempts) handles cases where the agent doesn't return output in the expected format.

    <Info>
      For a detailed guide on using this action, see the [Agent Task Automation Guide](/workflows/agent-task-automation).
    </Info>
  </Accordion>

  <Accordion title="AI File Analysis" icon="brain">
    Reads an uploaded document and extracts structured data into fields you define, without manual parsing.

    **Configuration**:

    | Field             | Description                                                                      |
    | ----------------- | -------------------------------------------------------------------------------- |
    | **Action Name**   | Descriptive name for this action                                                 |
    | **File**          | The file to analyze — from a trigger attachment, Read File output, or file field |
    | **Output Fields** | The specific data points to extract, with field names and types                  |

    **Variables**: Outputs each extracted field as an individual variable.

    <Tabs>
      <Tab title="Scenario">
        Automatically process uploaded invoices:

        1. **Attachment is Added** trigger fires when a PDF is uploaded to a vendor record
        2. **AI File Analysis** extracts: vendor name, invoice number, line items, total amount, due date
        3. **Create Record** creates an Invoice record with the extracted values
        4. **If** `total_amount` is greater than `5000` → **Start Approval Process**
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Transform Data with AI" icon="wand-magic-sparkles">
    Cleans, normalizes, and reformats input data into a consistent format.

    **Configuration**:

    | Field                           | Description                                                               |
    | ------------------------------- | ------------------------------------------------------------------------- |
    | **Action Name**                 | Descriptive name for this action                                          |
    | **Input**                       | The data to transform — from trigger fields, action outputs, or variables |
    | **Transformation Instructions** | What transformation to apply                                              |

    **Variables**: Outputs the transformed data in the specified format.

    **When to use**: When incoming data is inconsistent — addresses in different formats, phone numbers with or without country codes, company names with varying abbreviations — and you need it standardized before writing to records or sending to external systems.
  </Accordion>

  <Accordion title="AI Classification" icon="tags">
    Assigns a category or label to input content based on meaning and context, returning the result with a confidence score.

    **Configuration**:

    | Field           | Description                                                                 |
    | --------------- | --------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                            |
    | **Input**       | The content to classify — from trigger fields, action outputs, or variables |
    | **Categories**  | The set of categories the AI should choose from                             |

    **Variables**: Outputs the selected `category` and a `confidence` score (0–1). Use the confidence score in a downstream If action to handle low-confidence classifications differently — for example, routing to a human reviewer when confidence is below 0.7.

    <Tabs>
      <Tab title="Scenario">
        Classify incoming support emails and route them:

        1. **Email Received** trigger fires
        2. **AI Classification** analyzes `trigger.body` against categories: Bug Report, Feature Request, Billing Question, General Inquiry
        3. **If** `category` equals `"Bug Report"` AND `confidence` is greater than `0.8` → **Make Assignment** to Engineering
        4. **Otherwise If** `category` equals `"Billing Question"` → **Make Assignment** to Finance
        5. **Otherwise** → **Make Assignment** to General Support
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="AI Summarization" icon="compress">
    Distills lengthy input into a concise summary.

    **Configuration**:

    | Field           | Description                                                                  |
    | --------------- | ---------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                             |
    | **Input**       | The content to summarize — from trigger fields, action outputs, or variables |

    **Variables**: Outputs the `summary` text.

    **When to use**: When a downstream action needs a brief version of long-form content — for example, generating a one-line ticket description from a multi-paragraph customer email, or creating an executive summary from a detailed report before sending it via Teams.
  </Accordion>

  <Accordion title="AI Data Search" icon="magnifying-glass">
    Runs a semantic search against an AI Search table and returns contextually relevant results. Unlike Search Records (which matches exact field values), AI Data Search finds results by meaning.

    **Configuration**:

    | Field               | Description                                                                                        |
    | ------------------- | -------------------------------------------------------------------------------------------------- |
    | **AI Search Table** | Select a configured AI Search table (Element or Table)                                             |
    | **Query**           | The search query — supports `{{value_references}}` for dynamic queries based on the current record |

    **Variables**: Outputs the search results for use in subsequent actions.

    **When to use**: When the search input is natural language — a customer's question, a ticket description, or any free-form text — and you want the most relevant matches by meaning rather than exact field values.
  </Accordion>
</AccordionGroup>

***

## Communication Actions

Communication actions send notifications, messages, and updates to users inside and outside of Elementum.

<AccordionGroup>
  <Accordion title="Send Record Update" icon="bell">
    Sends an in-platform notification about a record to specified users. No external email is sent — notifications appear within Elementum.

    **Configuration**:

    | Field           | Description                                                                     |
    | --------------- | ------------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                                |
    | **Record**      | The record to notify about                                                      |
    | **Recipients**  | Users to notify — from a Search Users result, static users, or field references |

    **When to use**: For internal status updates that don't warrant an email — for example, notifying a team that a record is ready for review.
  </Accordion>

  <Accordion title="Send Email Notification" icon="envelope">
    Sends a formatted email with dynamic content from automation variables. Supports up to 25 recipients and multiple attachment sources.

    **Configuration**:

    | Field                 | Description                                                                                                                                                                  |
    | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **Action Name**       | Descriptive name for this action                                                                                                                                             |
    | **From Display Name** | The sender name that appears to recipients                                                                                                                                   |
    | **Sending Domain**    | The verified email domain to send from. Use the selector to choose between any domain configured for your organization so a single org can send mail from multiple entities. |
    | **From**              | The email address prefix (before the selected sending domain, for example `support` for `support@yourdomain.com`)                                                            |
    | **Bcc**               | Blind carbon copy recipients (up to 25 total)                                                                                                                                |
    | **Subject**           | Email subject line — supports `{{value_references}}`                                                                                                                         |
    | **Notification Body** | Email content with HTML formatting — supports `{{value_references}}`                                                                                                         |
    | **Email Attachments** | Optional files to include                                                                                                                                                    |

    **Email Attachments** can come from three sources:

    | Source          | Description                                                                         |
    | --------------- | ----------------------------------------------------------------------------------- |
    | **Record**      | Files from specific file fields on the trigger record                               |
    | **Attachments** | All files from the attachments block on the trigger record                          |
    | **File**        | Files from the workflow context — such as a generated report from an earlier action |

    You can combine multiple attachment sources in a single email.

    <Warning>
      Total attachment size is limited to 25MB. If attachments exceed this limit, the email will fail to send.
    </Warning>

    <Tip>
      For transactional emails only. Marketing use may result in restrictions or loss of access.
    </Tip>
  </Accordion>

  <Accordion title="Post Comment" icon="comment">
    Adds a timestamped comment to a record, creating a visible log of what the automation did.

    **Configuration**:

    | Field           | Description                                        |
    | --------------- | -------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                   |
    | **Record**      | The record to comment on                           |
    | **Comment**     | The comment text — supports `{{value_references}}` |

    **Variables**: Outputs the comment ID and timestamp.

    **When to use**: To create an audit trail on the record itself. Especially useful for logging AI decisions — for example, posting "AI classified as Bug Report with 92% confidence" so users can see why the ticket was routed a certain way.
  </Accordion>

  <Accordion title="Send Message to Teams" icon="microsoft">
    Posts a message to a Microsoft Teams channel.

    **Configuration**:

    | Field           | Description                                       |
    | --------------- | ------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                  |
    | **Channel**     | The Teams channel to post to                      |
    | **Message**     | Message content — supports `{{value_references}}` |

    **Variables**: Outputs message delivery status and channel information.

    **When to use**: For real-time team notifications — critical issue alerts, escalation notices, or workflow completion updates that need immediate visibility in your team's collaboration space.
  </Accordion>

  <Accordion title="Initiate Call" icon="phone">
    Triggers an outbound phone call from a configured AI agent. The call runs asynchronously — the workflow continues immediately without waiting for the call to complete.

    **Configuration**:

    | Field                  | Description                                                          |
    | ---------------------- | -------------------------------------------------------------------- |
    | **Action Name**        | Descriptive name for this action                                     |
    | **AI Agent**           | Which agent will conduct the call                                    |
    | **Phone Service**      | Phone service provider                                               |
    | **Phone Number**       | Number to call — from a record field, action output, or static value |
    | **Related Record**     | (Optional) Record this call relates to, for context                  |
    | **Additional Context** | (Optional) Extra information for the AI agent                        |
    | **Default Language**   | Language for the conversation                                        |

    **Variables**: Outputs call initiation status and call ID.

    <Info>
      The workflow does not pause for the call to complete. Use the **Agent Conversation Ended** trigger in a separate automation to process call outcomes like transcripts, sentiment analysis, or follow-up actions.
    </Info>
  </Accordion>

  <Accordion title="Initiate Email Conversation" icon="envelope-open">
    Kicks off an agent-led email conversation from inside an automation so you can collect data, deliver information, or follow up with recipients without blocking the workflow. The agent handles replies asynchronously while the rest of the automation continues.

    **Prerequisites**:

    * Add the ability to respond over email to the assigned agent's instructions so it knows how to handle the conversation.

    **Configuration**:

    | Field                       | Description                                                                                                                                                                                               |
    | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **Action Name**             | Descriptive name for this action                                                                                                                                                                          |
    | **Agent**                   | Which agent will own the conversation                                                                                                                                                                     |
    | **Trigger Record**          | Record the conversation is about — typically the record from the automation trigger                                                                                                                       |
    | **Email Participants**      | Recipients of the conversation (users, groups, or value references)                                                                                                                                       |
    | **First Message**           | The opening message the agent sends. Choose to author it directly or have the agent generate it from instructions. Supports `{{value_references}}` so you can pull dynamic values from the trigger record |
    | **Additional Instructions** | Extra guidance for the agent during the conversation. Supports `{{value_references}}`                                                                                                                     |
    | **Conversation Timeout**    | How long the agent waits for replies before ending the conversation (1–4 days)                                                                                                                            |
    | **Follow-Up Behavior**      | (Optional) What the agent should do if a recipient hasn't replied by a specific date and time                                                                                                             |

    **Variables**: Outputs conversation status and the conversation ID for downstream actions.

    **Behavior notes**:

    * The workflow does not pause while the email conversation is in flight — subsequent actions run immediately.
    * The agent can still run its configured tools while handling email responses, so it can look up records, take actions, or pull in additional context as the conversation progresses.
    * Use the **Agent Conversation Ended** trigger in a separate automation to react to the conversation outcome (for example, update the trigger record, post a comment, or kick off a follow-up workflow).
  </Accordion>
</AccordionGroup>

***

## File Actions

File actions process documents, extract text content, and manage file storage on records.

<Info>
  **File Size Limits**: Elementum supports file uploads up to **250MB** per file. Email attachments have a lower limit of 25MB due to email provider restrictions.
</Info>

<AccordionGroup>
  <Accordion title="Read File" icon="file">
    Extracts the text content of an uploaded file, making it available as a variable for downstream actions. Supports PDF, DOC, DOCX, TXT, CSV, and Excel formats.

    **Configuration**:

    | Field           | Description                                                                         |
    | --------------- | ----------------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                                    |
    | **File**        | The file to read — from a trigger attachment, file field, or previous action output |

    **Variables**: Outputs the file content as text and file metadata.

    **When to use**: When you need the text content of a file for AI analysis, script processing, or conditional logic — for example, reading a contract PDF before passing its content to AI File Analysis or an Execute Script action.
  </Accordion>

  <Accordion title="Read Bulk File" icon="files">
    Extracts text from multiple files simultaneously, returning their contents as an array without needing a Repeat for Each loop.

    **Configuration**:

    | Field           | Description                                                                                            |
    | --------------- | ------------------------------------------------------------------------------------------------------ |
    | **Action Name** | Descriptive name for this action                                                                       |
    | **Files**       | The files to read — from a trigger's attachment collection or a file field that accepts multiple files |

    **Variables**: Outputs an array of file contents and processing results.
  </Accordion>

  <Accordion title="Save Attachment" icon="paperclip">
    Saves a file to the attachments block on a specified record. Files generated or received during an automation are not persisted automatically — this action is required to keep them.

    <Info>
      Use this action after **Generate Report** to attach the generated file to a record. Without this step, the report exists only as a temporary reference within the automation.
    </Info>

    <Warning>
      This action processes one file at a time. When an email includes multiple attachments, use a **Repeat for Each** action to save each one individually.
    </Warning>

    **Configuration**:

    | Field           | Description                                                                                 |
    | --------------- | ------------------------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                                            |
    | **File**        | The file to save — from a generated report, email attachment, API response, or other source |
    | **Record**      | Which record to attach the file to                                                          |
  </Accordion>

  <Accordion title="Unzip File" icon="folder-open">
    Extracts files from a ZIP archive and makes the individual files available for subsequent actions.

    **Configuration**:

    | Field           | Description                      |
    | --------------- | -------------------------------- |
    | **Action Name** | Descriptive name for this action |
    | **File**        | The ZIP file to extract          |

    **Variables**: Outputs a list of extracted files.
  </Accordion>
</AccordionGroup>

***

## Data Actions

Data actions perform calculations, run scripts, set variables, and invoke other automations.

<AccordionGroup>
  <Accordion title="Execute Script" icon="code">
    Executes custom JavaScript in a secure, sandboxed environment. Your code receives named input values and returns a result object that subsequent actions can reference.

    **Configuration**:

    | Field           | Description                                                                              |
    | --------------- | ---------------------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                                         |
    | **Inputs**      | Named values from triggers, previous actions, or static values                           |
    | **Code**        | JavaScript that processes inputs and returns a result object. Click **Execute** to test. |

    When you add an Execute Script action, the code editor starts with a template:

    ```javascript theme={null}
    /**
     * Access your input values from the `input.parameters` object
     * Example:
     *
    const {
      recordType,
      id,
      title
    } = input.parameters;
    **/

    return {};
    ```

    <Tip>
      As you add input parameters in the sidebar, they are automatically added to the example destructuring statement, showing you which variables are available.
    </Tip>

    **Accessing Inputs**:

    All inputs are available exclusively through the `input.parameters` object. They are not injected as standalone variables into the script scope — referencing a parameter name directly (without `input.parameters.`) returns `undefined`.

    ```javascript theme={null}
    // Correct — access via input.parameters
    const myValue = input.parameters.myParameterName;

    // Incorrect — standalone variables are not injected
    // myParameterName → undefined
    // inputs → undefined
    ```

    **Working with Record Inputs and Field Mappings**:

    When an input parameter contains records (from a Search Records or Find All action), any field mapping aliases you configure in the Inputs panel become properties on each record object — they are not injected as top-level variables.

    ```javascript theme={null}
    const records = input.parameters.allFoundRecords;

    // Each record has field mapping aliases as properties
    const total = records.reduce((sum, record) => sum + record.amount, 0);

    return { total: String(total) };
    ```

    In this example, `allFoundRecords` is the parameter name and `amount` is the field mapping alias for the Amount field. Access the parameter through `input.parameters.allFoundRecords`, then access mapped fields as properties on each record (`record.amount`).

    **Execution Environment**:

    * Server-side, isolated sandbox — consistent behavior between testing and production
    * No access to file system, network, or external resources
    * Execution timeout: 10 seconds
    * Statement limit: 50,000 JavaScript statements
    * Console output captured (maximum 20 KB)

    **Built-in Utilities**:

    <Tabs>
      <Tab title="Base64">
        Encode and decode Base64 strings directly in your scripts.

        ```javascript theme={null}
        const encoded = btoa("Hello, World!");
        const decoded = atob("SGVsbG8sIFdvcmxkIQ==");

        return { encoded, decoded };
        ```

        Useful for preparing data for APIs that expect Base64-encoded payloads, or decoding Base64 content from external systems.
      </Tab>

      <Tab title="CSV Parsing">
        Parse CSV strings into structured data using the built-in `csvParse` utility.

        ```javascript theme={null}
        const csvContent = input.parameters.fileContent;
        const rows = csvParse(csvContent);

        return {
          totalRows: rows.length,
          firstRow: rows[0],
          columnNames: Object.keys(rows[0])
        };
        ```

        Useful for processing CSV content from the Read File action before creating or updating records.
      </Tab>
    </Tabs>

    **Variables**:

    | Variable     | Type | Description                                 |
    | ------------ | ---- | ------------------------------------------- |
    | `result`     | JSON | The object returned by your JavaScript code |
    | `textResult` | Text | JSON string representation of the result    |

    <Warning>
      The script must return a JavaScript object. Arrays, null, undefined, and primitive values are not valid return values. Wrap arrays in an object property if needed.
    </Warning>

    **Output Schema**:

    The Output Schema is generated automatically from the object your script returns. After you click **Execute**, the **Outputs** panel reads the result and lists each top-level property — along with its type — so downstream actions can reference those properties by name. You don't need to define properties manually.

    To refresh the schema after changing the script, click **Execute** again. The schema updates to match the new return value.

    <Tip>
      If a property you expect isn't appearing in downstream actions, run **Execute** once more — the schema rebuilds from the latest result. There's typically no reason to edit the schema by hand.
    </Tip>

    <Warning>
      If **Execute** fails with an error like `The field at path '/testJavaScriptExecution/outputSchema/properties[N]/...' was declared as a non null type...` (where `[N]` is the index of the offending property), your script returned `null` (or a property of the returned object was `null`) for the test inputs you provided. The schema generator can't infer a type from a null value. Fix it one of two ways:

      * **Add null handling to the script** — provide default values or guard clauses so every property in the returned object always has a non-null value. For example, `return { items: rows ?? [], count: rows?.length ?? 0 }`.
      * **Provide test values for every input** — open the **Inputs** panel and supply a representative test value for each parameter so the script's happy path runs and returns real data.

      You can't save the action while the Output Schema has errors — any schema mismatch (including the null-type error above) blocks the **Save** button until it's resolved.
    </Warning>

    **Using an output in a downstream action**: The Output Schema is generated automatically, but its inferred types are broad (string, number, object, array). Downstream inputs that require a specifically-typed value — a list of recipients, for example — often won't accept a raw script property from the value picker. When you hit that, return the payload as JSON from your script, add a **Read File** action configured with a [JSON File Reader](/workflows/json-file-reader) after Execute Script, and map the reader's typed variables into the downstream field.

    <Tabs>
      <Tab title="Scenario: Discount calculation">
        Calculate tiered discounts for an order:

        ```javascript theme={null}
        const orders = input.parameters.orderData;
        const discountTier = input.parameters.customerTier;

        const discountRates = {
          "Enterprise": 0.20,
          "Professional": 0.10,
          "Standard": 0.05
        };

        const discount = discountRates[discountTier] || 0;
        const subtotal = orders.reduce((sum, order) => sum + order.amount, 0);
        const discountAmount = subtotal * discount;

        return {
          subtotal: subtotal,
          discountPercent: discount * 100,
          discountAmount: discountAmount,
          total: subtotal - discountAmount,
          orderCount: orders.length
        };
        ```
      </Tab>

      <Tab title="Scenario: Ticket analysis">
        Analyze open tickets and compute statistics:

        ```javascript theme={null}
        const tickets = input.parameters.openTickets;

        const summary = tickets.map(ticket => ({
          id: ticket.id,
          priority: ticket.priority,
          age: Math.floor(
            (Date.now() - new Date(ticket.createdAt).getTime()) / 86400000
          )
        }));

        return {
          tickets: summary,
          totalOpen: tickets.length,
          criticalCount: summary.filter(t => t.priority === "Critical").length
        };
        ```
      </Tab>

      <Tab title="Scenario: Sum field-mapped records">
        Aggregate a field across records returned by a Search Records action. The input parameter `lineItems` contains the found records, and the field mapping alias `amount` maps to the Amount field:

        ```javascript theme={null}
        const records = input.parameters.lineItems;

        const total = records.reduce((sum, record) => sum + (record.amount || 0), 0);

        return {
          total: String(total),
          count: records.length
        };
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Run Calculation" icon="calculator">
    Evaluates a mathematical or logical expression using values from triggers or previous actions. The expression language is the same one used in [Calculations](/data/calculations) — all functions on that page (for example, `DATEDIF`, `DATE`, `CONCAT`, `IF`, `ISBLANK`) are available here.

    **Configuration**:

    | Field           | Description                                                                         |
    | --------------- | ----------------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                                    |
    | **Expression**  | The calculation to evaluate — supports standard math operators and value references |

    <Info>
      **Referencing values in the Expression field**: Type `$` to open the variable value picker and select a value from the trigger or a previous action. The picker inserts a value reference (for example, `$specialistManager`). Do **not** use the `ELEMENT."FieldName"` syntax here — that form is only valid in [table calculated columns](/data/calculations), where the calculation runs against a record. Inside the Run Calculation action, references come from the workflow's variables, so `DATEDIF($specialistManager, NOW(), 'D')` is correct while `DATEDIF(YourElement."Specialist Manager", NOW(), 'D')` is not.
    </Info>

    **Variables**: Outputs the calculated value.

    **When to use**: For straightforward math — totaling order amounts, computing tax, determining percentages. For anything more complex (conditionals, loops, string operations), use **Execute Script** instead.
  </Accordion>

  <Accordion title="Set Variable" icon="bookmark">
    Stores a value under a named variable that any subsequent action can reference.

    **Configuration**:

    | Field             | Description                                                               |
    | ----------------- | ------------------------------------------------------------------------- |
    | **Action Name**   | Descriptive name for this action                                          |
    | **Variable Name** | The name to store the value under                                         |
    | **Value**         | The value to store — from trigger data, action outputs, or a static value |

    **When to use**: When you need to reference the same computed value in multiple downstream actions, or when you want to give a descriptive name to a value for readability. For example, storing the result of a calculation as `total_with_tax` so it's clear what the value represents when used later.
  </Accordion>

  <Accordion title="Run Automation" icon="play">
    Invokes a separate automation as a step in the current workflow, enabling reuse of shared logic.

    **Configuration**:

    | Field           | Description                      |
    | --------------- | -------------------------------- |
    | **Action Name** | Descriptive name for this action |
    | **Automation**  | Select the automation to invoke  |

    **Variables**: Outputs the invoked automation's execution status.

    **When to use**: When the same sequence of actions is needed in multiple automations — for example, a "Notify Stakeholders" automation that sends Teams messages and emails. Instead of duplicating those steps everywhere, build it once and call it with Run Automation.
  </Accordion>
</AccordionGroup>

***

## User Actions

User actions find users and user groups for assignments and notifications.

<AccordionGroup>
  <Accordion title="Search Users" icon="users">
    Queries the user directory and returns matching users.

    **Configuration**:

    | Field           | Description                                                               |
    | --------------- | ------------------------------------------------------------------------- |
    | **Action Name** | Descriptive name for this action                                          |
    | **Conditions**  | Filter criteria — department, role, name, email, or other user attributes |

    **Variables**:

    | Variable | Type         | Description                                                  |
    | -------- | ------------ | ------------------------------------------------------------ |
    | `users`  | User (array) | All users matching the criteria                              |
    | `user`   | User         | The first matching user (convenient for single-user lookups) |
    | `count`  | Number       | Total matching users                                         |

    Each user has sub-properties: `user.id`, `user.name`, `user.email`.

    <Info>
      To process multiple users from the `users` array, use a **Repeat for Each** action. Inside the loop, each `item` has `item.id`, `item.name`, and `item.email`.
    </Info>
  </Accordion>

  <Accordion title="Search User Groups" icon="users-rectangle">
    Queries the user group directory and returns matching groups.

    **Configuration**:

    | Field           | Description                                |
    | --------------- | ------------------------------------------ |
    | **Action Name** | Descriptive name for this action           |
    | **Conditions**  | Filter criteria — group name or attributes |

    **Variables**: Outputs matching user groups and their member details.

    **When to use**: When you need to assign a record to a team rather than a specific person, or when routing decisions depend on group membership.
  </Accordion>
</AccordionGroup>

***

## External Actions

External actions connect your automations to third-party systems.

<AccordionGroup>
  <Accordion title="Send API Request" icon="code">
    Sends an HTTP request to any REST API and returns the response for downstream actions.

    **Configuration**:

    | Field                        | Description                                                                                                                                                                                                   |
    | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **Action Name**              | Descriptive name for this action                                                                                                                                                                              |
    | **URL**                      | The API endpoint — supports `{{value_references}}`                                                                                                                                                            |
    | **Request Method**           | GET, POST, PUT, or DELETE                                                                                                                                                                                     |
    | **Authorization Type**       | Authentication method — see *Authorization options* below                                                                                                                                                     |
    | **Request Headers**          | HTTP headers as key-value pairs — add entries with **+ Request Header**                                                                                                                                       |
    | **Request Data**             | Format of the request payload (shown for methods that send a body). Options: **JSON Input**, **Form Data URL Encoded**, **Multipart Form Data**, or **Custom Request Body** — see *Request Data types* below. |
    | **Response Type**            | Format used to parse the response — **JSON** or **FILE**                                                                                                                                                      |
    | **Continue on Error Status** | When enabled, the automation continues even if the response status indicates an error (4xx or 5xx). Pair with a follow-up Execute Script that inspects `statusCode` and `response` to extract error details.  |

    **Request Data types**:

    | Type                      | Body fields shown                                                                                                                                                                                                                                                                                                                 |
    | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **JSON Input**            | A single **JSON Input** editor that accepts a JSON-formatted string. Includes a `{}` formatting button and an expand control. Use this for JSON request bodies — see the warning below for how to pass an Execute Script output safely.                                                                                           |
    | **Form Data URL Encoded** | A list of **Key** / **Value** text pairs. Add more with **+ Form Value**. Submitted with `Content-Type: application/x-www-form-urlencoded`.                                                                                                                                                                                       |
    | **Multipart Form Data**   | A list of **Form Value** entries. Each entry has a **Key** field with a text/file toggle (the paperclip icon switches the value to a file reference; the **Tt** icon switches it back to text) and a **Value** input. Add more with **+ Form Value**. Submitted with `Content-Type: multipart/form-data` — used for file uploads. |
    | **Custom Request Body**   | A **Content Type** input plus a **Custom Request Body** text area for the raw payload. Use this when you need full control over the Content-Type header and body shape.                                                                                                                                                           |

    All payload fields support `{{value_references}}`. Type `$` inside any of these fields to open the value picker.

    **Authorization options**:

    | Type             | Description                                                                                                               |
    | ---------------- | ------------------------------------------------------------------------------------------------------------------------- |
    | **No Auth**      | No authorization header                                                                                                   |
    | **Basic Auth**   | Username and password, sent as Base64-encoded Authorization header. Credentials encrypted at rest.                        |
    | **Bearer Token** | Static token (encrypted at rest) or dynamic reference from a previous action output                                       |
    | **OAuth**        | Client Credentials flow — provide OAuth URL, Client ID, and Client Secret. Tokens are cached and refreshed automatically. |

    **OAuth Configuration**:

    | Field              | Description                                                                                         |
    | ------------------ | --------------------------------------------------------------------------------------------------- |
    | **OAuth URL**      | The token endpoint URL                                                                              |
    | **Client ID**      | Your OAuth client identifier (encrypted at rest)                                                    |
    | **Client Secret**  | Your OAuth client secret (encrypted at rest)                                                        |
    | **Request Type**   | How credentials are sent — *HTTP Basic* (Authorization header) or *Form URL Encoded* (request body) |
    | **Custom Headers** | Additional headers for the token request (optional)                                                 |

    **Variables**:

    | Variable       | Type    | Description                                  |
    | -------------- | ------- | -------------------------------------------- |
    | `response`     | JSON    | Parsed JSON response body                    |
    | `success`      | Boolean | Whether the request succeeded                |
    | `textResponse` | Text    | Raw text response body                       |
    | `statusCode`   | Number  | HTTP status code (200, 404, 500, etc.)       |
    | `file`         | File    | Downloaded file (when response type is FILE) |

    <Warning>
      When **JSON Input** is selected as the Request Data type, the editor expects a plain string containing valid JSON — not a structured JSON object. Mapping an object output directly to it — for example, the `result` output from an Execute Script action — causes the request to fail with `failed to convert input data to params`.
    </Warning>

    To send a dynamic JSON payload, stringify the object inside the Execute Script action and reference the resulting string in the **JSON Input** editor:

    ```javascript theme={null}
    const payload = {
      order_id: order.id,
      total: order.total
    };

    return { jsonPayload: JSON.stringify(payload) };
    ```

    Then map `jsonPayload` into the **JSON Input** editor. The script's `textResult` output is not a reliable substitute — it isn't a clean JSON string the receiving API can consume, and most endpoints will reject it as an invalid request body.

    <Tabs>
      <Tab title="Scenario">
        Check inventory before processing an order:

        1. **Record is Created** trigger fires for a new order
        2. **Send API Request** sends a GET to the inventory system with the product IDs from the order
        3. **If** `send_api_request.success` equals `true` AND `response.in_stock` equals `true` → continue processing
        4. **Otherwise** → **Update Record Fields** sets status to "Backordered" and **Send Email Notification** alerts the customer
      </Tab>

      <Tab title="Error handling">
        Enable **Continue on Error Status** on the Send API Request action, then add an Execute Script immediately after it. Pass the status code and response into the script to determine whether the call succeeded and extract useful error details. This prevents a single failed API call from stopping the entire automation.
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Run Function" icon="function">
    Invokes a pre-built custom function with input parameters for specialized processing.

    **Configuration**:

    | Field           | Description                          |
    | --------------- | ------------------------------------ |
    | **Action Name** | Descriptive name for this action     |
    | **Function**    | Select the custom function to invoke |
    | **Inputs**      | Input parameters for the function    |

    **Variables**: Outputs the function result and any computed values.

    **When to use**: For specialized business logic or integrations that aren't covered by built-in actions — custom pricing algorithms, proprietary system integrations, or reusable processing routines.
  </Accordion>
</AccordionGroup>

***

<Info>
  For design principles, performance strategies, and proven patterns, see [Automation Best Practices](/workflows/automation-best-practices). For trigger configuration and use cases, see the [Automation Triggers Reference](/workflows/automation-triggers-reference).
</Info>
