# Welcome to Rewst documentation

Explore our guides and recordings to start automating in Rewst today. Click through our recommended shortcuts below, or use the nav menu to the left, organized to match the left side menu in Rewst.

<table data-view="cards" data-full-width="false"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td align="center"><strong>Rewst Support</strong></td><td align="center">Contact and customer resources for help with using Rewst</td><td><a href="/pages/sA4fcjhqwlu92LDunc0u">/pages/sA4fcjhqwlu92LDunc0u</a></td><td><a href="/files/5mbLuYxJafEHq5ngA6WH">/files/5mbLuYxJafEHq5ngA6WH</a></td></tr><tr><td align="center"><strong>Rewst Open Mic</strong></td><td align="center">Recordings and invites to our recurring live community hangouts</td><td><a href="/pages/KDu7vPh8UKqjTLrNNK9a">/pages/KDu7vPh8UKqjTLrNNK9a</a></td><td><a href="/files/U6EielGqhQrEKgnAz0uu">/files/U6EielGqhQrEKgnAz0uu</a></td></tr><tr><td align="center"><strong>Cluck University</strong></td><td align="center">Sign up for training in Cluck University to learn how to use Rewst</td><td><a href="https://learn.rewst.io/">https://learn.rewst.io/</a></td><td><a href="/files/KRcqEWcLJSRFl0XjagIL">/files/KRcqEWcLJSRFl0XjagIL</a></td></tr></tbody></table>

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td align="center"><strong>Integrations</strong></td><td align="center">Setup and user instructions to integrate all your favorite tools with Rewst</td><td><a href="/pages/MyVtJy4FSLxxZuApmytJ">/pages/MyVtJy4FSLxxZuApmytJ</a></td><td><a href="/files/iOZFfHfsYoXjj9Q4Js0s">/files/iOZFfHfsYoXjj9Q4Js0s</a></td></tr><tr><td align="center"><strong>Crates</strong></td><td align="center">Browse available Crates in our collection of unpacking and user guides</td><td><a href="/pages/kZqn2LpBU4jhFDuWXgJS">/pages/kZqn2LpBU4jhFDuWXgJS</a></td><td><a href="/files/MtIT6XqBuocBA05kIVgQ">/files/MtIT6XqBuocBA05kIVgQ</a></td></tr><tr><td align="center"><strong>Agent Smith</strong></td><td align="center">Our open-source command executor that fits into your Rewst workflows</td><td><a href="/pages/fIpLMsRc6pvLNYaOvhWA">/pages/fIpLMsRc6pvLNYaOvhWA</a></td><td><a href="/files/o9XOhLMGvf8QvLeamvbx">/files/o9XOhLMGvf8QvLeamvbx</a></td></tr></tbody></table>

## Get started with Rewst

Not sure where to begin? We recommend these resources. Click on Cluck University links to launch that course in a new tab. Click on documentation links to take you directly to that page in this documentation site.

### Cluck University intro courses

<table data-view="cards"><thead><tr><th align="center"></th><th align="center"></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Rewst crash course</strong></td><td align="center">Get oriented, get confident, get automating</td><td><a href="/files/3F7e9pWxngNCaiNXzFr9">/files/3F7e9pWxngNCaiNXzFr9</a></td><td><a href="https://learn.rewst.io/rewst-crash-course">https://learn.rewst.io/rewst-crash-course</a></td></tr><tr><td align="center"><strong>Automation Fundamentals</strong></td><td align="center">For MSP strategists and builders: Plan smart, build right, prove ROI</td><td><a href="/files/ya5zXrgTHui2cDES9pXV">/files/ya5zXrgTHui2cDES9pXV</a></td><td><a href="https://learn.rewst.io/path/automation-fundamentals">https://learn.rewst.io/path/automation-fundamentals</a></td></tr><tr><td align="center"><strong>Cluck University catalog</strong></td><td align="center">View our total course catalog</td><td><a href="/files/9EtPioINXjSuYpJ6WLFh">/files/9EtPioINXjSuYpJ6WLFh</a></td><td><a href="https://learn.rewst.io/page/course-catalog">https://learn.rewst.io/page/course-catalog</a></td></tr></tbody></table>

### Documentation on Rewst platform basics

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f91d">🤝</span> <strong>What is an integration?</strong></td><td><a href="/pages/OSnkx0SEHcbueeC19adV">/pages/OSnkx0SEHcbueeC19adV</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f500">🔀</span> <strong>What is a workflow?</strong></td><td><a href="/pages/yoHf2AVYDQJZiCRERlY8">/pages/yoHf2AVYDQJZiCRERlY8</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span> <strong>What is an action?</strong></td><td><a href="/pages/IgLWPsIO9ptzH8SN9qYe">/pages/IgLWPsIO9ptzH8SN9qYe</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4c1">📁</span> <strong>What is an organization?</strong></td><td><a href="/pages/MJ3qhY7mNpNU1O94ZhwK">/pages/MJ3qhY7mNpNU1O94ZhwK</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4e6">📦</span> <strong>What is a Crate?</strong></td><td><a href="/pages/FLvdStgWDsLTcw5gA1vG">/pages/FLvdStgWDsLTcw5gA1vG</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4dd">📝</span> <strong>What is a form?</strong></td><td><a href="/pages/Bd04lN8ZJ5yY9uJkNDRD">/pages/Bd04lN8ZJ5yY9uJkNDRD</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f4c4">📄</span> <strong>What is a template?</strong></td><td><a href="/pages/Oo5ZGJt3Qt00dpcwtJ4V">/pages/Oo5ZGJt3Qt00dpcwtJ4V</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="2328">⌨️</span> <strong>What is Jinja?</strong></td><td><a href="/pages/h4161dV8T01nADfw2O4K">/pages/h4161dV8T01nADfw2O4K</a></td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f9d1-1f91d-1f9d1">🧑‍🤝‍🧑</span> <strong>What are users in Rewst?</strong></td><td><a href="/pages/gzxKSbCN6twFAlGzYgyr">/pages/gzxKSbCN6twFAlGzYgyr</a></td></tr></tbody></table>


# Coming soon to Rewst

{% hint style="info" %}
New Rewst features are currently in Beta with a planned general release for later in 2026. This documentation is regularly evolving to meet the needs of the changing product. We'll publish complete documentation for how to use the entire product upon general release. If you're one of our Beta users and want to submit feedback, please reach out via your dedicated Discord channel.

This page is intended to act as a quick-start guide that points out the differences between existing Rewst and our new features. It will not help you use the current release of Rewst. RoboRewsty will not pull its information into his search and knowledgebase.
{% endhint %}

## The Rewst Agent

Whereas RoboRewsty referenced Rewst documentation to provide answers and follow directions, the Rewst Agent operates off of *playbooks*, structured procedures the agent must load before authoring workflows, forms, or apps. Each one enforces required reads, required contracts, ordered steps, and verification.

Ask the Rewst Agent to build you anything that you could have built in Rewst before— only now, it will take the lead and do all the work for you. For anything the Rewst Agent builds, it will research, show a proposal with the exact nodes and field mappings, then ask once for approval. Nothing gets created, published, or run until you approve. If its proposal is off, just tell it what to change, and it will make adjustments and ask for approval again. Instead of having you manually build your automations to save time, new Rewst operates largely on you asking the Rewst Agent to build for you, for an even greater time savings.

<figure><img src="/files/9opJWbB8udEIOHKu67c9" alt=""><figcaption></figcaption></figure>

## App Builder

Like our previous App Builder, you can create sites in the new App Builder to suit your unique needs. But now, no coding knowledge is required to create and edit apps. Simply ask the Rewst Agent to make an app for you and let it create and refine the final product. For existing App Builder users, note that the new Builder has expanded components, offers full HTML editing capabilities without requiring you to add containers, and allows for greater thematic customization than its predecessor.

<figure><img src="/files/rmjrdsROy7yd4EaxoK3D" alt=""><figcaption><p>The apps list page</p></figcaption></figure>

<figure><img src="/files/y8nplYtyU6sYUoqA4Oam" alt=""><figcaption><p>An app being worked on in the App Builder</p></figcaption></figure>

## Form Builder

Our new Form Builder has more than 40 components, a 4x increase in options from our original forms. In addition to two default themes of light mode and dark mode, MSPs can create unlimited custom themes. The Form Builder comes with multi-page support built in, including named pages and next/previous navigation at the form's runtime.

Drag and drop components directly onto the Form Builder canvas for visually responsive form designing, no Jinja required. Or, ask the Rewst Agent to create a form for you, and watch as it picks the best components to achieve your desired goals.

<figure><img src="/files/i6w6fmbHofhwj3c5KUKW" alt=""><figcaption><p>The forms list page</p></figcaption></figure>

<figure><img src="/files/A274O8XJxK1BIRfFyfgR" alt=""><figcaption><p>A form being worked on in the Form Builder</p></figcaption></figure>

Forms are now subject to *workflow binding*, where a form is 'bound' to a single workflow, from inside the form. Trigger setup for forms has also been relocated to within the Form Builder— no more back-and-forth navigating between two tabs to set up your form triggers.

### Options Builder

Our new Options Builder replaces the original Options Generator and Options Filter features you're used to in Rewst and makes setting up forms to have options much easier. It supports hundreds of thousands of options

There are two ways to populate options:

* **Static** - for example, option A, option B, option C
* **Workflow-backed** - choose a workflow that generates options and Rewst auto-maps label and ID using a heuristic, with manual override available
  * Workflow-backed components are disabled on public forms to prevent accidental exposure of internal data

Filtering rules are built in to the Options Builder. Filter values populate from real data in the system, so MSPs select from actual identifiers instead of typing Jinja and risking typos.

### Access control

Forms have four options for access, which can be set in the Form Builder.

* **All suborganizations**, default: MSP owner and all suborganizations can authenticate at the runtime URL
* **Owner only**: MSP only
* **Selected suborganizations:** explicit allow-list
* **Public forms:** no login required

You can also create form-level exceptions per customer, without cloning the form. Add components that only exist for one organization, or hide specific components for select organizations.

## Workflow Builder

The Rewst Agent can build your workflows and any associated forms or scripts for you, all stemming from your query. Alternatively, you can build and edit workflows manually in our new Workflow Builder, just like you always have in Rewst.

<figure><img src="/files/rGgodJtlv6cmImMTxcfw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/xsoXkL4QRzxRJamcDYHs" alt=""><figcaption></figcaption></figure>

The left side menu of the Workflow Builder now contains *nodes*, the individual elements you can drag and drop onto the Workflow Builder Canvas. Nodes for particular integrations that you have already set up in Rewst will appear here, along with triggers, and any AI presence that Rewst has access to.

## Integrations

Our new Integration Builder simplifies the existing Rewst integration process into one streamlined menu. Choose from verified Rewst integrations built by the Rewst team, or ask the Rewst Agent to add your own integrations for whatever apps you choose using that same process— no more Custom Integration setup like there has been in the existing Rewst platform.

<figure><img src="/files/CYLeaa9y2Z9pwSn9XA0w" alt=""><figcaption></figcaption></figure>

Integrations are split into three components for easier reuse and sharing: authentication methods, credentials, and the integration itself.

* Authentication methods are reusable across multiple integrations
* Credentials are reusable across integrations and are stored as a managed entity
* Custom authentication methods can be created

## Settings

The next generation of Rewst has a robust permissioning system and granular settings that allow you to use Rewst the way that best suits you and your MSP.

You'll still need to manually configure SSO setup and user invitations, but the Rewst Agent can guide you through what every setting means and how to adjust each to your particular situation.

### Agents

Build your own agents to work in the platform. Custom agents allow end users to interact with Rewst automations in whatever way they desire, from platforms outside of Rewst.

### MCP server

The Rewst MCP server gives your AI coding tool direct, authenticated access to your Rewst tenant in the live platform. Create tokens for AI tools like Claude Code to access Rewst APIs. After creating a token, add the Rewst MCP server to your AI coding tool to:

* Build and edit automations from your editor
* Let the server can see what's actually connected in your tenant: integrations, workflows, forms, apps, real field names, etc.
* Debug runs without leaving your tool

## Security

The Rewst Agent has been designed with modern security practices and approaches in mind. Updated security documentation and architectural details will be released shortly before general access for the platform. The new Rewst features are included in our currently running SOC 2 audit and GDPR compliance audit, with our updated, full reports available in Q4 of 2026.

{% hint style="info" %}
Do you have questions or want to learn more about the new changes coming to Rewst? Reach out to <sales@rewst.io> for more information if you're not an existing Rewst customer, or <csteam@rewst.io> if you are a current Rewst customer.
{% endhint %}


# AI basics

If you're newer to AI, read through this document to get up and running with some of the terms you'll need to be familiar with to properly use Rewst. For more information on how our existing AI chatbot RoboRewsty works, see his documentation [here](/documentation/roborewsty).

## What is AI? How is it different from automation?

*Automation* follows predefined rules and specifically set instructions to perform repetitive tasks exactly the same way every time. *Artificial Intelligence*, or *AI*, is designed to learn from data, adapt to new information, and make decisions in unpredictable situations. *Generative AI* produces content like text, images, or code from learned patterns but can't reason its way through a problem or initiate action on its own. Rewst is moving towards using both AI and automation together as a joint solution, which will offer MSPs the greatest possible benefits in agility and efficiency.

## What is an LLM?

An *LLM*, short for *Large Language Model*, is a type of AI designed to understand, process, and generate human language. It functions as a highly advanced autocomplete system, trained on vast amounts of data to predict and produce coherent, contextually relevant text.

## What is an agent? How is it different from RoboRewsty?

An *AI agent* is an autonomous software system that uses artificial intelligence to perceive its environment, make decisions, and take actions to achieve a specific goal. Unlike basic chatbots like RoboRewsty that only respond to prompts, agents can plan multi-step workflows, use external tools, and remember past interactions.

* RoboRewsty is reactive. He answers specific questions or executes predefined commands, requiring continuous human direction.
* The Rewst Agent is proactive. You give it an end goal and it will plan and execute the necessary actions on its own.

## What is Agentic AI?

*Agentic AI,* related to agents, relies on LLMs to carry out tasks on behalf of users. Imagine that you need to reset a password and simply describe what you want in plain language. The AI agent can understand that goal, interpret the intent behind the request, develop a plan for achieving it, and call on the right tools to see it through— all without you the MSP manually involving yourself beyond your request.

This ability to process natural language, reason through problems, and make decisions in order to act independently is what sets agentic AI apart from other forms of AI and automation. Rather than waiting for human oversight at each step, AI agents can manage entire workflows, respond to changing conditions, and adapt to new tasks and information as they arise. Where basic AI automations follow predefined rules and stop there, agentic AI goes further by interpreting instructions and taking action based on real-time input.

## What is a prompt?

A *prompt* is an instruction, question, or input you give to an AI system to guide its response. It's the primary way humans communicate with AI tools and can be a simple sentence, a detailed paragraph, an image, or uploaded files. When you entered a question about your workflow into RoboRewsty, you were prompting him to guide his response. You'll make similar prompts to The Rewst Agent.

## How do I make good prompts?

The Rewst Agent needs quality instructions to know exactly what you want it to do and act intelligently on your behalf. Start with a solid objective, break complex instructions into step-by-step formatting, give any necessary background or constraints for what you are trying to achieve, and include specific examples to guide the output.

For The Rewst Agent in particular, a successful prompt includes:

* Outcome, not just steps
  * "When a ticket closes, post a summary to Slack" tells more than "use the Slack node." It can pick the right nodes if it knows the goal.
* The trigger
  * What kicks this off: A manual run, a form submission, a schedule, or an event like a new email or new ticket?
* The systems involved
  * Name the actual integrations — ConnectWise, Microsoft Graph, HaloPSA, Slack, etc.
  * The Rewst Agent verifies what's actually installed on your organization before proposing anything. Naming them lets it check and respond to your prompt more quickly.
* Scope
  * Do you want one workflow, or a form and a workflow? Is your goal an app in App Builder? Include whether you want the creation run and tested after building, or just created.
* Information that's specific to external systems
  * This is where vague prompts cost the most time. The Rewst Agent is strict about not guessing external contracts.
  * Include the exact business subset, in your words — "Only active agreements," "tickets in the triage queue," "users licensed for E3." It will map your phrasing to the real status values by checking the integration contract and sample data, but needs to know the intent.
  * Consider required record selections. If a mutation needs a company, board, queue, status, or member, indicate whether you want to (a) provide an ID/name, (b) have The Rewst Agent show you a picker, or (c) build a reusable form. It won't enumerate your records unless you ask.
  * Values it can't infer are things like a target ticket priority or a specific channel. If it's a closed choice, The Rewst Agent will either look up the valid options or ask you for the exact value.

#### Example prompt

> "When a new email hits our shared mailbox in Microsoft, create a ConnectWise ticket on the Service Board, and only if the sender is from an existing company. Build it and run a preview so I can check."

This gives The Rewst Agent a trigger, systems, outcome, a conditional, and how to verify. It contains enough to research and propose without a round of clarifying questions.

## What is an MCP?

The *Model Context Protocol (MCP)* was open sourced by Anthropic in November 2024 to provide users and developers with an easy way to extend the capabilities of AI-powered apps by integrating them with data sources and applications. An *MCP server* is a small program that acts like a bridge between an AI tool and another piece of software. It provides context for language models— like Claude or ChatGPT— to interact with resources, run tools, and do whatever else you can think of.

Instead of having the model to guess how a tool works or what data would be needed, the MCP server presents information in a format the AI tool can understand and interact with.\
In Rewstʼs case, the MCP lets approved AI tools see and use specific Rewst workflows that you choose to expose. Think of it as a safe, controlled way for an AI tool to call your Rewst workflows.

Our MCP server can help you by:\
• Discovering eligible workflows using natural language\
• Running approved automations directly from supported AI tools\
• Retrieving workflow results and insights without logging into the platform\
• Using conversational AI to explore and understand how your workflows operate


# Rewst Dashboard

The Rewst Dashboard is the home screen you'll see when you first log into the platform. Click the drop-down organization selector in the top right to choose which org's information will be displayed in the dashboard at any given time.

Use the dashboard to easily digest key metrics for every workflow executed within a selected timeframe and better understand how Rewst is bringing you value. Identify usage patterns, success rates, and estimated time savings.

<figure><img src="/files/7ax0gskWlbByQseH9WcR" alt="Screenshot of the Rewst dashboard analytics view showing February 2026 metrics, including charts for tasks performed, time saved, and workflow status. The dashboard is depicted in three shades of dark blue, with bar graph in the center of the screen to display the month&#x27;s information."><figcaption><p>The top of the Rewst Dashboard screen</p></figcaption></figure>

Choose to view the data in your desired timespan by clicking the relevant button at the top right of the dashboard for either **Weekly** or **Monthly** views. Note that the default for the dashboard timeline is monthly. Click **<** or **>** next to the indicated date to skip between date ranges. Click **Download CSV** to export the report to a file.

{% hint style="info" %}
Additional options to view metrics on a daily basis are coming soon!
{% endhint %}

The **Tasks Performed** chart shows all tasks performed in the prior month or week for your selected organization.

The **Time Saved** chart shows the total time saved by using your Rewst automations in the prior month or week for your selected organization.

{% hint style="info" %}
This estimate is generated from the time saved number entered in your workflow's settings, as well as Rewst's baseline assumption of the manual effort required without automation for prebuilt automations like Crates. An estimate of zero means your estimate was never filled out. To resolve a zero estimate, navigate to the workflow and enter the time saved estimate there.\
\
If you have a workflow that has been running without a time saving value, and you add that value later, your dashboard won't retroactively update to reflect that time savings. Calculation and tracking begins when you add a time savings value.
{% endhint %}

The **Workflows** menu shows stats for how many workflows in your selected time period were running, as well as how many executions were successful and how many errors were given. The time period selected at the top of your dashboard will determine the time period displayed in the widget.

Scroll further down the Rewst Dashboard page to see the **Workflows** widget. The data in this section updates daily.

<figure><img src="/files/g81GIg3dc7sKfgssh9dY" alt="A user interface displaying a table of word counts with columns for total words, word generations, and other related metrics. The table has a dark background with light text, showcasing various entries and pagination controls at the bottom."><figcaption><p>The lower workflow widget, viewable at the bottom of the Rewst Dashboard page</p></figcaption></figure>

This section of the dashboard provides a centralized view of individual workflow usage metrics in separate columns: **Success Rate**, **Total Executions**, **Total Tasks**, and **Time Saved**. Click on any individual workflow in the widget's workflow list to open that workflow in the workflow builder canvas. Use the fields at the top of each column to enter search and filtering parameters to find your desired workflows. Click **Download CSV** to export the workflow data to a file.


# Automations


# Workflows

## What is a workflow?

*Workflows*, made up of [actions](https://docs.rewst.help/documentation/workflows/actions-in-rewst) and [triggers](https://docs.rewst.help/documentation/intro-to-triggers), are the main component of Rewst's automated business processes. They gather relevant data from integrated tools such as a PSA or RMM, process it using conditional logic, and execute automated actions relating to that data. Workflows are the key to unlocking automation in Rewst.

[Crates](https://docs.rewst.help/prebuilt-automations/crates) contain pre-built workflows. Workflows can also be built from scratch, or edited to match your custom needs.

{% hint style="warning" %}
We recommend you only edit the pre-built workflows that come in Crates after taking our courses in [Cluck University](https://learn.rewst.io). This is a more advanced way to use Rewst.

Before building any workflow, remember to sketch out what you'd like the workflow to look like, and identify the trigger that will kick it off.
{% endhint %}

{% hint style="info" %}
As of mid 2025, Rewst also offers *kits.* A kit is a collection of pre-built, pre-defined actions that provide a quick start to setting up solutions to specific business needs, or to demonstrate all available actions within a given integration. For example, if you have a Halo PSA kit, there will be actions or automations Rewst has identified that are smaller use cases compared to our larger Crates.

Kits are a newer feature of our Crate Marketplace. Check back as the collection grows. See our up-to-date list of available kits [here](/documentation/automations/kits).
{% endhint %}

## Why build workflows?

While the pre-built workflows in Crates are the quickest way to get started, a workflow built custom to your situation can offer powerful, personalized efficiency measures that fit your particular MSP and customer needs.

## Find and use workflows in Rewst

Access workflows in the Rewst platform by navigating to **Automations > Workflows** in the left side menu. Click **Create Workflow** to create a new workflow from scratch.\ <br>

<figure><img src="/files/hzLijkMTyDNVOPCsyD1n" alt="Screenshot of the Workflows list view in the Rewst Automations section, showing a dark-themed interface with a left navigation menu, a top search bar and Create Workflow button, and a table of workflows with colored tags, attributes, update details, and configuration actions."><figcaption><p>The workflows list page, without any filters applied</p></figcaption></figure>

The list of workflows that appears in the center of your workflows list screen will include both the workflows you create and the workflows unpacked from Crates. As you continue to set up automation in Rewst, this list can grow quite a bit. The **Updated At**, **Updated By**, **Attributes**, and [**Tags**](https://docs.rewst.help/documentation/workflows/tags-in-rewst) columns each offer the option to filter your results by relevant criteria, with attributes and tags filters operating for both inclusion and exclusion of desired parameters. Use **Search** in the top center of your screen to find a particular workflow, and the <img src="/files/nDs6pPpcP8GJSgLVh5ly" alt="" data-size="line"> icon to the right to choose which columns you'd like to see in your workflows list.

<figure><img src="/files/OCz1b949iJ0OLDv9snvm" alt="" width="159"><figcaption></figcaption></figure>

Rewst will notify you when we make changes to actions that affect your workflows. These notifications will appear in the workflows page. Learn more about those notifications in our documentation for our [action version log](/documentation/automations/actions-in-rewst#action-version-updates). Once you create a workflow, you'll be taken to the [*Workflow Builder*](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow), a Canvas for assembling your workflows. See our documentation for how to use the Workflow Builder [here](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow).

## Synced versus unsynced workflows

Synced workflows unpacked from Crates can't be edited, and automatically update when Rewst makes changes. You have the option to unsync a workflow, which can be useful for using a Crate workflow as a building block for creating your own customized workflow. For more on synced workflows, including how to identify them, see our documentation on Crates and syntonization [here](/documentation/crates#synced-versus-unsynced-crates).

## View specific workflow results

The general results page will show you the results of every workflow that has run in your organization. Apply a date range filter to view execution results from a specific time period, up to 30 days prior.

To see all results for a specific workflow, you can do the following:

1. Navigate to **Automations > Workflows**.
2. Search for the specific workflow.
3. Select <img src="/files/fVN2VvMckY5cMn5dZgIa" alt="" data-size="line"> in the far right corner for that specific workflow. This will take you to a new page that will show all the results of that workflow.

<figure><img src="/files/1NazCmgXYjrnwsFuvjbq" alt="A user interface displaying a &#x27;Workflows&#x27; section with a dark background. It includes search and filter options, a list of workflows, and buttons for actions such as &#x27;Configure&#x27; and &#x27;Trigger&#x27; beside a specific workflow titled &#x27;Integration Checklists and WBS.&#x27;"><figcaption></figcaption></figure>

{% hint style="info" %}
When you delete the result of a workflow, consider it to be fully deleted. Only delete results when you are confident that they will not be needed. The result will remain in Rewst's database backup snapshots for a short length of time until it is past the retention period, at which point it will be purged. Meta data and stats about the deleted workflow execution remain in the system. Deleting a workflow execution will not affect time saved or remove time saved.
{% endhint %}

## View triggers for a specific workflow

From the workflows page, you can view triggers associated with each workflow, without leaving that page. Hover over the workflow's **triggers** count in the **Attributes** column to see a list of every trigger linked to your workflow, and toggle each on or off to suit your needs.

<figure><img src="/files/6rQORvoPUy67LXKkmnSr" alt=""><figcaption><p>The dialog that appears when hovering over trigger counts</p></figcaption></figure>

### Export and import workflows

You can export a workflow to share with other Rewst customers, or create your own hard copies of workflow backups. To export a workflow as a JSON bundle, navigate to the [Workflow Builder Canvas](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow#workflow-builder) and find the export option under the **Workflow Options** menu.

To import a workflow bundled as a JSON file, click **Import Bundle** in the top right navigation bar of the workflows page. Then, drag and drop your file into the upload dialog that appears.

<figure><img src="/files/x0ivM21ZGrS2yrfRr9lV" alt=""><figcaption></figcaption></figure>

## Subworkflows

A *subworkflow* is a workflow that is also a part of another workflow. In Rewst, every automation can function as either a larger executing workflow or a smaller subworkflow. Subworkflows help you simplify complex processes, reuse logic, and manage error handling and data gathering cleanly in your Rewst automations. You can create your own subworkflows, or use one of our pre-built subworkflows, cataloged in [this section of our documentation site](/documentation/automations/subworkflows).

In the example below, you have a main workflow called **Create Ticket**. In it, you choose which PSA the organization has. Once that has been decided, you then go to a subworkflow, which encompasses the actual creation of the ticket. Note the light teal border and <img src="/files/nfuswCSgZsbsCyq9N4ED" alt="" data-size="line"> icon on the action, denoting that it is a subworkflow.

Click **⋮** on a subworkflow to navigate directly to it or delete it from the Canvas. You can also view subworkflows on the main workflow page, indicated by the green **Subworkflow** button under the **Attributes** column. Clicking will reveal which workflow the subworkflow is a part of.

<figure><img src="/files/PbFVlASvoDeZyGHiPGmL" alt="An image of a small subworkflow, flowing out of a larger executing workflow. The subworkflow is composed of actions, via rectangles outlined in  pink. The flow of subworkflow out of larger workflow is communicated via blue directional arrows. Under each subworkflow action, there&#x27;s the option to click a blue plus button to add additional actions on success or failure of that action."><figcaption><p>An example of subworkflows, flowing out of a larger executing workflow</p></figcaption></figure>

<figure><img src="/files/LhIQDXVPuzTf4Kk2nkrN" alt="" width="563"><figcaption><p>The Subworkflow button, under the <strong>Attributes</strong> column of the workflows list page</p></figcaption></figure>

To create your own subworkflow from scratch, simply create a new workflow in the Workflow Builder and publish it. That new workflow will appear in the **Workflows** section of the Workflow Builder's actions menu, and you can drag it onto any other Workflow Builder canvas to be used as a subworkflow.

<figure><img src="/files/1FMXiRvtuDhd6KcRkGle" alt="A moving image of a user scrolling down a left side rectangular menu to find their selection. The user then clicks and drags the desired item from a menu titled &#x27;Workflows&#x27; onto the right side of the screen, where it rests and appears as a new rectangle. It contains a pink circular icon to identify itself as a subworkflow."><figcaption><p>Remember, subworkflows will appear on your Workflow Builder canvas with a teal color to help<br>you keep track of your action types.</p></figcaption></figure>

There are a few reasons to set up subworkflows.

* Ensure a tidy workflow. Rather than having 20 steps per PSA on a single workflow, we can split it up for convenience and ease of understanding.
* When addressing various objects, the equivalent of a [for each](https://docs.rewst.help/documentation/workflows/configuring-your-workflow-tasks/advanced-workflow-operations#with-items), we can pass all of the objects to a sub-workflow and get the output back of each object.
* Run logic inside a subworkflow to isolate errors, apply retry or skip logic, and handle failures cleanly while using [with items](/documentation/automations/workflows/advanced-workflow-operations-menu), without failing your parent workflow.
  * This is typically the best method for using with items loops inside Rewst. This allows you to run checks and balances on each iteration to prevent or handle possible failures on a per-item basis.
* Subworkflows allow you to write a workflow once and reuse it multiple times. Subworkflows also accept parameters, making them adaptable for different use cases.
* Smaller, self-contained workflows are easier to test and debug individually.

### Configure the subworkflow inputs and output

1. Click **⋮ > Open Subworkflow** on the dragged subworkflow to open it in the Workflow Builder Canvas.
2. Click <img src="/files/waKlgf9wITlR9KGqS8t8" alt="" data-size="line"> to open the workflow settings.
3. Configure which data comes into the subworkflow, and which data you want returned to the parent workflow upon completion— your [inputs and outputs](/documentation/automations/workflows/data-input-and-output-input-variables-and-context-variables). There are a variety of input types, which will differ depending on your subworkflow.

<figure><img src="/files/NvCmna6Jrhs7WltJEIHw" alt="A screenshot of a sub-workflow configuration screen. At the top, there are sections labeled &#x22;Variable Configuration&#x22; and &#x22;Input Configuration&#x22; with a plus icon. Three input fields are defined:  list (type: List) with default value {{ [ ] }}, description &#x22;used for passing JSON object,&#x22; optional required checkbox.  boolean (type: Boolean) with default value {{ true }}, description &#x22;true or false,&#x22; optional required checkbox.  input_configuration (type: Text) with description &#x22;configure Inputs in the sub-wf,&#x22; optional required and multiline checkboxes.  Below, an &#x22;Output Configuration&#x22; section contains a field:  output_data with value {{ &#x22;The sub-wf test data&#x22; }}.  Each entry includes text fields for name, label, type, default value, and description, along with a red &#x22;Remove&#x22; button. At the bottom, there are &#x22;Cancel&#x22; and &#x22;Submit&#x22; buttons.  Highlighted in red boxes are the &#x22;Input Configuration&#x22; and &#x22;Output Configuration&#x22; headers, as well as a pencil icon in the top-right toolbar."><figcaption><p>An example of the <strong>Input</strong> tab of a subworkflow's workflow settings</p></figcaption></figure>

{% hint style="info" %}
*Workflow wrapper* is an informal term sometimes used colloquially by the ROC to describe a situation where a primary workflow is used in a separate workflow as a subworkflow. More information on workflow wrappers can be found [here](broken://pages/fm8eIBTHO3CnDr23CZjX).
{% endhint %}

### Enable publish results in the parent workflow

This setting publishes the configured output, allowing your parent workflow to use the results of the subworkflow immediately.

1. Find your desired subworkflow in the **Workflows** actions menu in the left side of the Workflow Builder.
2. Drag your subworkflow from the actions list to the Workflow Builder Canvas within your parent workflow.
3. Click on the subworkflow to open its settings in the right side menu.
4. Enter `sub_wf_results` in the **Publish Results As** field.
5. Click **Deploy**.

<figure><img src="/files/wU87ZX1RdFrlauy3fDnL" alt=""><figcaption></figcaption></figure>

### Access subworkflow data

Results for subworkflows are nested inside published results for workflows. For example, the following Jinja would contain the subworkflow data.

```django
{{ CTX.sub_wf_results.output_data }}
```

<figure><img src="/files/I4HSs7Y7b0funo9wR2fU" alt=""><figcaption></figcaption></figure>

## Additional workflow documentation

{% content-ref url="/pages/LxXpAXU9SC77w7l2zCeD" %}
[Workflow builder: How to set up a workflow](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow)
{% endcontent-ref %}

{% content-ref url="/pages/IgLWPsIO9ptzH8SN9qYe" %}
[Actions](/documentation/automations/actions-in-rewst)
{% endcontent-ref %}

{% content-ref url="/pages/Xxy8F0zJJD7iXAXaLy1p" %}
[Task transitions](/documentation/automations/workflows/task-transitions)
{% endcontent-ref %}

{% content-ref url="/pages/tycqCa6n1r9V0j7kqERO" %}
[Data aliases](/documentation/automations/workflows/data-aliases)
{% endcontent-ref %}

{% content-ref url="/pages/PEwFqA4KStYUjn677hg1" %}
[Best practices for designing workflows](/documentation/automations/workflows/best-practices-for-designing-workflows)
{% endcontent-ref %}

{% content-ref url="/pages/9SdRfd65iSwDE2J8wZKy" %}
[Advanced workflow operations menu](/documentation/automations/workflows/advanced-workflow-operations-menu)
{% endcontent-ref %}

{% content-ref url="/pages/6LhkPJebg1zmkMdT9ejM" %}
[Data input and output: Input variables and context variables](/documentation/automations/workflows/data-input-and-output-input-variables-and-context-variables)
{% endcontent-ref %}

{% content-ref url="/pages/sRoXnINfQMRBHYE6aeHT" %}
[Option generator workflows](/documentation/automations/workflows/option-generator-workflows)
{% endcontent-ref %}

{% content-ref url="/pages/AKizolU9D5moj0PmITRM" %}
[Boolean logic in Rewst workflows](/documentation/automations/workflows/boolean-logic-in-rewst-workflows)
{% endcontent-ref %}

{% content-ref url="/pages/LmbPpKzrF3RsUtknUtvs" %}
[Kits](/documentation/automations/kits)
{% endcontent-ref %}

{% content-ref url="/pages/BNgwED5SFXGx9NU8Mzjr" %}
[Subworkflows](/documentation/automations/subworkflows)
{% endcontent-ref %}


# Workflow builder: How to set up a workflow

{% hint style="info" %}
Remember, the [Core](/documentation/automations/actions-in-rewst/core-actions) actions category contains your base actions that apply for all integrations. The [Rewst](/documentation/automations/actions-in-rewst/rewst-actions) actions category holds actions form the foundation of your interaction with the platform. The [workflows](/documentation/automations/actions-in-rewst/workflows-actions) actions category contains any existing workflows in the workflow list for the related child organization. The other categories contain actions that apply to that particular brand of integration.
{% endhint %}

<figure><img src="/files/FPAvo0z4vM3qteYIXM8L" alt=""><figcaption><p>A blank workflow builder canvas, as seen for a freshly created workflow</p></figcaption></figure>

The start screen of the Workflow Builder Canvas has three quick start tiles, which will disappear as soon as you drag any element onto the Canvas.

## The Workflow Builder toolbar <a href="#the-workflow-settings-toolbar" id="the-workflow-settings-toolbar"></a>

{% columns fullWidth="false" %}
{% column %}

### ![](/files/kf5RjEiYOPcxT7XJLC3R) <a href="#the-workflow-settings-toolbar" id="the-workflow-settings-toolbar"></a>

{% endcolumn %}

{% column %}
Use the top left toolbar to open, view, and use the features of the workflow builder.
{% endcolumn %}
{% endcolumns %}

* Click <img src="/files/ZQnZZSa1V8Yh89wpuPCf" alt="" data-size="line"> to expand or collapse the general left side menu of the Rewst platform.
* Click <img src="/files/uRisZ5stbztRNhMqHoPL" alt="" data-size="line"> to reveal the **Library**, where all your actions, triggers, subworkflows and favorites can be found. Read more about it in the [**Library**](#library) section of this document.
* Click <img src="/files/Rtkj01kAT14ci7i5l4LE" alt="" data-size="line"> or <img src="/files/FIOOVt4SlI1021aZxAKs" alt="" data-size="line"> to undo or redo your last change.
* Click <img src="/files/vg99uEH0JX8ZwsDKi9t6" alt="" data-size="line"> to open the **Settings** menu for your workflow. See more about this menu in the [**Settings**](#settings) section of this document.
* Click <img src="/files/qD1e18Et3cFoPAzVfZyE" alt="" data-size="line">to open the additional **Canvas** controls menu.
  * Zoom in, out, or to fit.
  * Enable compact auto layout to reduce spacing between nodes. Toggling the setting on doesn't immediately re-layout the canvas. The setting only takes effect the next time you run auto-layout. This preference carries across sessions and workflows.
  * Choose from vertical or horizontal layout for your canvas.
  * Check the view on and off for **Snap to Grid**.
* Click <img src="/files/Ukpr6CFB4T0nbCjupoHR" alt="" data-size="line">to **Show All Comments** or **Hide Comments**.
  * For seasoned Rewst users: Our feature previously called Notes has been renamed to Comments.
  * Comments are a great way to jot down your thinking behind workflow aspects, and an essential step to building workflows for any team that has multiple employees editing workflows. They save in the workflow itself, and can be viewed by anyone who has permissions to edit that workflow. Adding notes is disabled for synced clone workflows.

Center screen, the toolbar contains a drop-down selector for additional options for your workflow. This is also where you can toggle back to the legacy view of the Workflow Builder.

* Click **Rename** to change the name of your workflow.
* Click **Edit Workflow Attributes** to add a new tag or choose an existing tag from the drop-down **Tags** selector.

<figure><img src="/files/oSWIcMbV9OiUEdbnWTcx" alt="" width="296"><figcaption></figcaption></figure>

* Click **Edit Workflow JSON** to open the JSON editor in the right of your screen.
* Click **Version History** to open a menu on the right side of your screen displaying the record of when the workflow was created and edited. You also have the option to revert back to a previous version of your workflow, or view previous versions to compare changes.
* Click **Execution History** to view the list of execution results for the workflow, including their success or failure status.
* Click **Export** to [export a workflow](https://docs.rewst.help/documentation/automations/workflows#export-and-import-workflows).
* Click **Clone** to create an exact copy of your workflow without changing the original.

  The window that appears is the failsafe to confirm that you want to clone the workflow. In it, you can do the following:

  * Give your clone a different name from the original
  * Choose the organization where the workflow will be cloned to with the drop-down **Organization** selector
  * Choose to **Synchronize Changes** with the original workflow - any changes you make to the original workflow will be reflected in the clone if this is toggled on
* Click **Delete** to delete your workflow entirely.

<figure><img src="/files/EJZ1HzvlIjQKpNbrfrNz" alt=""><figcaption></figcaption></figure>

## Publish a workflow

In the top right corner of the Workflow Builder Canvas, you'll find the options to test and publish your workflow.

Click **Run** to test the workflow via an execution. This will open a new dialog where you can choose the organization for your test.

<figure><img src="/files/MSOQumd2fINaCHCdckpj" alt=""><figcaption></figcaption></figure>

Click **Deploy** to deploy the workflow fully. Before you deploy you'll be asked to confirm that you wish to make this decision.

<figure><img src="/files/zGkIFkeaKd6xwAOrunii" alt=""><figcaption></figcaption></figure>

## Library

{% columns fullWidth="false" %}
{% column %}

<figure><img src="/files/zH7LFFUSW7kK2Cob5Wmn" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}
The **Library** menu contains three distinct tabs:

1. **Actions** holds a complete list all available actions and subworkflows. At the very bottom of the list is **+ Add Integrations**, which launches the option to add a new integration to Rewst. Note that this is intended to allow you to add an integration quickly and facilitate the completion of workflow design, not to replace the full integrations menu. Any integration added through the library that requires [organization mapping](/documentation/integrations#what-is-organization-mapping) will need to be mapped from its full integration page.\
   Integration actions are divided by categories, viewable after you click into the integration. If you search within an integration, results will be scoped to that integration only. This rule applies for custom integrations in addition to Rewst-native integrations.
2. **Flow Control** contains the option to add a new Trigger, as well as a list of all triggers already added to your workflow.

<figure><img src="/files/XOZJtnVxi7nW5OMJ6kqV" alt=""><figcaption></figcaption></figure>

3. **My Library** stores your bookmarked, favorite actions. Click the bookmark icon on any action to add it to the My Library list.

<figure><img src="/files/z1mEcgDgnERQkSSbvWQu" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

At the very bottom of the menu you have the option to add a new custom integration.

1. Click **Add Integrations +**.
2. The dialog that appears contains many fields for information needed to set up the integration. Pull that relevant information from the partner app you wish to integrate.
3. When finished,

## Canvas view settings

{% columns %}
{% column %}
The canvas view menu is located on the left side of the Workflow Builder canvas. **+** and **-** zoom the view in or out. ![](/files/PoDy6xAqST8EjLXwgQcE) snaps the view to fit the entire workflow into the center frame of your screen. ![](/files/VCWE5yTjWrnS1oYQnCoV)toggles the visualization interactivity of the workflow on or off. See more about this in the [#view-task-flow](#view-task-flow "mention") and [#view-trigger-flow](#view-trigger-flow "mention")sections of this document.
{% endcolumn %}

{% column %}

<figure><img src="/files/k2UXYpca4HLht0Fhv4FG" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

Compact view

## Add transitions between actions

To add a transition, hover over your desired starting action. Note the circles on the right and bottom on the action. These represent the action’s outputs, and are where you can create transitions to following. The triangle on the top and left of the action are inputs into the action, and where you can connect a transition. Click on the circle under or to the right of the action, drag, and release on the top of the ending action where you would like the transition to conclude.

<figure><img src="/files/TQokgxYmR0y9g73TecoJ" alt=""><figcaption></figcaption></figure>

The diamond that appears between the two actions is the *transition indicator*. Click on it to open the transition settings menu.

{% columns fullWidth="false" %}
{% column %}

<figure><img src="/files/FpgCvErCqmDbcvutm3C2" alt="" width="300"><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}
\
From this menu you can:

* Optionally add a **Custom Transition Label.**
* Choose the **Condition** of your transition. - note the appearance and meaning of the condition statuses in the table below, the symbols of which will appear in your transition indicator once chosen.
* Add a data alias.

<figure><img src="/files/D10XEpuDsnbTNzXuGHhA" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

| Transition indicator symbol | Label       | Meaning                                                               |
| --------------------------- | ----------- | --------------------------------------------------------------------- |
| ✓ - Check mark              | **Success** | The transition will only be followed if the preceding action succeeds |
| ✗ - X mark                  | **Failure** | The transition will only be followed if the preceding action fails    |
| ↻ - Circle/always           | **Always**  | The transition will be followed regardless of the action outcome      |
| { } - Braces/custom         | **Custom**  | The transition uses a custom Jinja condition                          |

## View action flow

View the relationship between actions via the animation depicted on their transitions. Note that the way the animation flows depicts the order of the actions in the workflow. You'll need to to run the workflow or pull up an execution histoy and select an execution for the animation to kick on. It automatically turns off when you return to the edit view in the Workflow Builder Canvas.

<figure><img src="/files/t5m5XbZZgXBY4ntoEOt2" alt="" width="375"><figcaption></figcaption></figure>

## View trigger flow

Triggers appear directly on the Workflow Builder Canvas, and have an arrow to visually indicates which action the workflow will start executing when that trigger fires.

<figure><img src="/files/9ulGRoDTR6CCb5MgcGeE" alt="" width="289"><figcaption></figcaption></figure>

## General settings

The **Settings** menu has distinct tabs, each with its own configuration options.

<figure><img src="/files/7zds0JWCAEUZoZGhYluv" alt=""><figcaption></figcaption></figure>

* **General** provides a field to view and edit the **Workflow Name**, as well as the **Workflow Timeout** in seconds, the **Time Saved** in seconds, and a drop-down selector for the **Workflow Type** - either Standard, Option Generator, or Stream Output. Here you can also choose to **Delete Workflow** or **Download Workflow as JSON** file.
* **Data Aliases** displays a list of all defined [data aliases](/documentation/automations/workflows/data-aliases).
* **Input** displays existing input configuration, as well as options to **Add Schema** or **+ Add Input**.
* **Output** displays existing output configuration, as well as options to **Add Schema** or **+ Add Output**.
* **Variables** displays existing variables, as well as an option to **+ Add Variable**.
* **Triggers** displays existing [triggers](/documentation/automations/intro-to-triggers), as well as an option to **+ Add Trigger**.
  * Click **+ Add Trigger** to reveal the **Trigger Settings** menu. Each of the tabs contains the following options. Remember to click **Save Trigger** at the bottom of the menu when finished making your selections.
    * In the **General** tab:
      * Here you can update the fields for **Trigger Name**, **Trigger Mode**, and **Trigger Type**.
      * Under the **Mock Results** and **Workflow Input Parameters** menus, the **Query Conditions** fields allow for the entering of string values only.
      * Any previously set trigger variables will appear here in the **Trigger Variable** section.
    * In the **Overrides** tab:
      * **+ Integration Override** reveals a list of all integrations and allows you to specify which integration configurations should be used. Otherwise, the default integration configuration for the triggering organization will be used.
      * **+ Add All** will add integration overrides for all installed integrations in the organization.
    * In the **Criteria** tab, set up your [trigger criteria](/documentation/automations/intro-to-triggers/trigger-criteria).
    * In the **Run For** tab, choose your [Activate Triggers to Run For](/documentation/automations/intro-to-triggers#activate-trigger-to-run-for) settings.
* **Edit JSON** provides three separate code editors, including one each for **Trigger Outputs** and **Action Parameters**.

<figure><img src="/files/kuaLw1r0FLMawSxiRtWh" alt="" width="375"><figcaption></figcaption></figure>

## Action settings

Click into your action to open the **Action Settings** menu, which contains four tabs.

**General** - This includes:

* **Task Name** - A user-editable field for the action's identifier
* **Description** - A user-fillable text box for additional action information
* **Output -** Specifies where the action's output gets stored in the task logs
* **Publish Result As** - A friendly name you assign for the action's results that you can use as an a context variable for calling it's content in future actions
* **Time Saved**: - This is for just the time saved by that action- see more about total workflow time savings in [this section](#add-time-saved-to-a-workflow) of the document
* **Edit Task JSON** - Opens the action's code editor

<figure><img src="/files/Hf1gMuJhS6J6VwulAM1d" alt=""><figcaption></figcaption></figure>

**Parameters** - Unique to each action, this tab houses options for defining the action's behavior during execution. Think of them like fill-in-the-blank options that make workflows adaptable.

**Testing** - This tab provides the option to simulate the action's function with a user-defined result, useful for testing and debugging. Toggle **Mock this action** on or off. Click **Add Mock Result** to add additional guidelines for JSON content to be returned by this action to the **Mock Results** list.

<figure><img src="/files/SHTo6egEefaumuyYZffV" alt=""><figcaption></figcaption></figure>

**Advanced** - Here you'll find settings for several advanced action properties. The use and purpose of each is more fully documented [here](https://docs.rewst.help/documentation/automations/workflows/advanced-workflow-operations-menu#integration-overrides).

* [**Integration Overrides**](/documentation/automations/workflows/advanced-workflow-operations-menu#integration-overrides)
* [**Task Transition Criteria**](/documentation/automations/workflows/advanced-workflow-operations-menu#task-transition-criteria-sensitivity)
* [**Run as Org**](/documentation/automations/workflows/advanced-workflow-operations-menu#run-as-org)
* [**With Items**](/documentation/automations/workflows/advanced-workflow-operations-menu#with-items)
* [**Items Concurrency**](/documentation/automations/workflows/advanced-workflow-operations-menu#items-concurrency)
* [**Task Timeout**](/documentation/automations/workflows/advanced-workflow-operations-menu#task-timeout)
* [**Security Features**](https://docs.rewst.help/documentation/jinja/jsonpath-for-data-redaction-in-rewst)
  * **Redacted Input Parameters**
  * **Redacted Output Parameters**

## Trigger settings

Click and drag **Trigger** under the Flow Control tab of the Library to add a new trigger to your Workflow Builder Canvas. This will reveal a new menu to the right with your **Trigger Settings** that contains four tabs.

**General** - Set your **Trigger Name**, choose the **Trigger Mode** and **Trigger Type**, and toggle your trigger to **Enabled** or **Disabled**. Under the **Trigger Parameters** menu, set your timezone, Cron Schedule, and [Critical Timing](/documentation/automations/intro-to-triggers#critical-timing). Under the **Trigger Variables** menu, any workflow variables set in the workflow settings will appear.

**Overrides** - Add [Integration Overrides](/documentation/automations/intro-to-triggers#integration-overrides) for the trigger.

**Criteria** - Add [trigger criteria](https://docs.rewst.help/documentation/automations/intro-to-triggers/trigger-criteria#save-trigger-criteria) to filter trigger events.

**Run For** - Choose which organization or organizations to activate the trigger to run for. Here you can also choose tags to select activation.

### Completion handlers: Inbound and outbound triggers

In the new Workflow Builder, the concept previously known as a completion handler is treated as triggers instead. Find these in the trigger menu under the **Trigger Mode** drop-down selector. Read more about how to use inbound and outbound triggers in our [triggers documentation](/documentation/automations/intro-to-triggers).

<figure><img src="/files/qIR6vt5fd7eQBDbIBVdR" alt="" width="242"><figcaption></figcaption></figure>

An **Inbound** selection will set the workflow to trigger by another workflow. An **Outbound** selection will trigger another workflow to run when this workflow completes.

## Test workflows

<figure><img src="/files/Re7H99zbPQEa8jty7TCx" alt=""><figcaption><p>In the dialog that appears after clicking <strong>Deploy</strong>, click <strong>Show Detailed Changes</strong> to expand the accordion and display a side-by-side comparison of your original workflow and all changes that would be published.</p></figcaption></figure>

Click **Run** to initiate your test, then click to confirm that you want to **Run Test** in the dialog that appears.

<figure><img src="/files/rrf40vFFRa8fw7oxuQ3Z" alt=""><figcaption></figcaption></figure>

After your test is complete, view the workflow execution results in the right side menu. Click on any of the events in the execution log to expand and view information. Click **View Results** to launch a new browser tab with the complete results, in the Rewst platform outside of the Workflow Builder. When satisfied with your workflow, then click **Deploy** and **Submit** to save your changes and implement them on all future runs.

<figure><img src="/files/SjnpVvcxbCOWczBl0Oow" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
Inbound and outbound trigger data is hard to fake for testing, as it's represented as `COMPLETED_WORKFLOW.` instead of `CTX.COMPLETED_WORKFLOW.` Rather than running an entire workflow multiple times to test just this one element, create a [noop action](https://docs.rewst.help/documentation/workflows/actions-in-rewst/core-actions#no-operation-noop) that sets the test data, and use it to trigger your inbound our outbound trigger.

In the noop, set all of the variables that will be used in the On Success transition as data aliases.

It’s important that the names of the data aliases you create in the On Success transition of the noop match both:

* the names of the variables that will be used in your inbound or outbound trigger
* the names of the variables that will be used in the live parent workflow that your trigger is triggered by

Add static values that represent a good test case for ensuring that your related workflow functions the way you expect.
{% endhint %}

## Build a workflow

### Create the workflow

1. Click **Create**.
2. Give your workflow a **Name**, and add any tags you would like via the **Tags** drop-down selector.
3. Click **Submit**. This will launch the Workflow Builder.

### Set up the trigger

{% hint style="success" %}
Recall that every workflow is kicked off by a trigger. Which trigger you choose will depend on the goals of your workflow. There's no right or wrong order to build your workflow as long as it contains all the correct parts at the time of publication. You could start with adding actions to your canvas first, then set up your trigger.

If your trigger is form, you'll need to create and set up that form first before pulling it into your workflow.
{% endhint %}

1. If you have not yet added any triggers, click **Add a Trigger > + Add Trigger** to add a new trigger.
2. If you have already added a trigger and want to add an additional trigger, click the yellow **Triggers** bar on the Workflow Builder Canvas **> + Add Trigger**. Note that if you have one trigger or many triggers, all will show up in this right side menu in a list, which is always accessible by clicking the yellow bar. The number of total triggers will appear in a counter box in the far right of the dragged yellow bar.
3. Name your trigger something simple but descriptive, and unique. Depending on your trigger, new **Trigger Parameters** will appear as a new section in the setup menu with additional selections to be made to set parameters for the trigger. For example, if your trigger is a [form](https://docs.rewst.help/documentation/forms), you would be asked to select the name of an existing form to use as the trigger.

<figure><img src="/files/Q9JEkLdyfODoJpNolBUX" alt=""><figcaption><p>Note the Flow Control tab on the left, and the trigger settings on the right.</p></figcaption></figure>

3. Fill out the **Trigger Settings** menu as follows:
   1. Enter a descriptive name into the **Trigger Name** field.
   2. Toggle the trigger to **Enabled** to use it in the workflow.
   3. Use the **Trigger Mode** drop-down selector to choose the mode for your trigger:
      1. **Integration**: The workflow is triggered by an integration with Rewst.
         1. **Inbound**: The workflow is triggered by another workflow.
         2. **Outbound**: The workflow triggers another workflow.
   4. Use the **Trigger Type** drop-down selector to chose the type from the list of all available triggers in your Rewst instance. Depending on your trigger, new **Trigger Parameters** will appear as a new section in the setup menu with additional selections to be made to set parameters for the trigger. For example, if your trigger is a [form](https://docs.rewst.help/documentation/forms), you would be asked to select the name of an existing form to use as the trigger.
4. If needed, add an [integration override](/documentation/automations/intro-to-triggers#create-a-trigger).\
   \
   ![](/files/XjAyQCHai3w9ruOTqCEg)
5. Set your trigger criteria, if required for your workflow.\
   \
   ![](/files/tK5BXit7dh095uBHK1N7)
6. Think about which organizations you want the trigger to run for.
   1. **Selected Organization (Org Name)** will be toggled on by default. Toggle to off if desired.
   2. If you want the automation to work for your main org as well as all child organizations, toggle **All current and future managed organizations** to on.
   3. If you want the automation to apply only for certain organizations, select them manually in the **Organizations** selector field.\
      \
      ![](/files/SoDb4fFnCRGT7WZPcTLU)
7. Click **Save Trigger** at the bottom of the menu to save the trigger.

{% hint style="info" %}
A workflow can be called by multiple forms through the use of triggers. All that is required is to open the workflow and create a new trigger with **Core - Form Submission** selected for the Trigger Type.
{% endhint %}

### Drag the action

1. Search for your desired action in the library. You can do this via the **Search** field or by scrolling down the library to your known integration and clicking its category to expand and view all its available actions.
2. Click on the action, drag it, and drop it onto the Workflow Builder Canvas.
3. Repeat this process to add all needed actions to your workflow.

### Configure actions

1. Click on the placed action, which will open its settings in the right side menu.
2. Fill out all fields and tabs for your desired task setup.
3. Remember to add [transitions](https://docs.rewst.help/documentation/workflows/configuring-your-workflow-tasks/navigating-between-tasks-with-transitions) between your tasks.
4. Click **Run** **> Run Test** to see if your workflow executes as desired.
5. Click **Deploy** to save your changes and push them to the desired effect.

### Add time saved to a workflow

One of the key metrics you can use to understand the value added by your automations is time saved. You can configure this in Rewst by identifying how long it takes to manually work through your process before automating it and adding it into your workflow.

{% hint style="info" %}
**Considerations for time saved**

* When determining how much time to set for any given process, it's a good practice to consider not only how much time it may take you or your most experienced tech to go through that process manually, but also how much time it takes to fix any human errors that may happen during this process.
* Action-level time-savings are not included in calculations. Workflow-level time-savings drives reporting on time saved in Rewst.
* Time saved in seconds can only be manually reported on by using our [GraphQL](/documentation/automations/actions-in-rewst/generic-graphql-request-action) action. To do so, you would pulling the information via the GraphQL action and compute time saved based on values entered and execution history.
  {% endhint %}

1. Click on the workflow that you want to configure to open it in the Workflow Builder.
2. Click <img src="/files/waKlgf9wITlR9KGqS8t8" alt="" data-size="line"> to edit the workflow settings.
3. Enter the number of seconds it takes a human to complete the manual version of the process in the **Time Saved** field.

<figure><img src="/files/lgqX1Pg4QF2P6gDtxcaP" alt=""><figcaption></figcaption></figure>

### Add, edit, or delete workflow comments

{% hint style="info" %}
Rewst now also offers our [RoboRewsty](/documentation/roborewsty#document-with-roborewsty) note taking feature, to automate your documentation. Choose to document manually, or with RoboRewsty.
{% endhint %}

Comments are a great way to jot down your thinking behind workflow aspects, and an essential step to building workflows for any team that has multiple employees editing workflows. They save in the workflow itself, and can be viewed via the <img src="/files/stS5BxBa7eL6aNerxRr2" alt="" data-size="line"> button by anyone who has permissions to edit that workflow. These boxes provide a title and a markdown editor.

{% hint style="warning" %}
Adding comments is disabled for synced clone workflows.
{% endhint %}

1. Right-click the canvas and select **Add Comments**. Alternatively, press and hold the **control** key to expose the menu.\
   \
   ![](/files/VJa9HJcOidkkkUoFlHV2)
2. Click and drag it to the desired location on the canvas.
3. Click <img src="/files/6L2kKtvYDsoH1L6nZHNh" alt="" data-size="line"> to edit a comment's content in the right side menu. Click ⋮ to expose options to **Edit Markdown**, **Edit Attributes**, or **Delete**.<br>

   <figure><img src="/files/7yYsgtz6mPbkkGrvJxKH" alt="" width="201"><figcaption></figcaption></figure>
4. To delete comments right from the comment on the Canvas, right-click the comment and click **Delete***.*

<figure><img src="/files/CGRHLyCEJgxZWPwuDuf9" alt="" width="322"><figcaption></figcaption></figure>

5. Comments may also be pinned to the canvas so that you can navigate without accidentally moving notes around. Click **Pin** to enable or disable pinning.

## Additional Workflow Builder features

### Select multiple elements on the Canvas

Select multiple workflow actions and comments simultaneously by drawing a selection box around them.

1. Hold shift and drag your mouse, or hold the middle-mouse button and drag your mouse.
2. Once you’ve selected multiple actions or comments, move them by dragging the selection box to the desired location.

Commonly used actions can be favorited to easily find and add actions to workflows. When favorited, actions can be found in the **favorites** section and added on the Workflow Builder Canvas by right-clicking.

### Clone and synchronize a workflow

Custom-designed workflows can be cloned to create an exact copy without changing your original.

1. Click <img src="/files/E0VyPaGNj1MrpuFwS7ug" alt="" data-size="line"> .
2. Click **Clone**.
3. The dialog that appears is the failsafe to confirm that you want to clone the workflow. In it, you can do the following:
   1. Give your clone a different name from the original
   2. Choose the organization where the workflow will be cloned to with the drop-down **Organization** selector
   3. Choose to **Synchronize Changes** with the original workflow - any changes you make to the original workflow will be reflected in the clone if this is toggled on
4. Click **Clone**.<br>

   <figure><img src="/files/siuSl2CYKhvSHDK8K7K4" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Creating a clone of your workflow is a great way to make a siloed test environment for your custom workflow. Make upgrades, fixes, or updates to your original workflow with synchronized changes toggled off.
{% endhint %}

## Retrieve the name of a workflow

Run the command `{{ WORKFLOW.name }}` .

Similarly, if you're searching for the name as it relates to completion handlers, run the command\
`{{ COMPLETED_WORKFLOW.WORKFLOW.name }}` .

{% hint style="info" %}
Information for the **Advanced** tab of tasks and actions in a workflow can be found in our documentation for the [advanced workflow operations menu](/documentation/automations/workflows/advanced-workflow-operations-menu).
{% endhint %}

### Workflow wrappers <a href="#workflow-wrappers" id="workflow-wrappers"></a>

*Workflow wrapper* is an informal term to describe a parent workflow that "wraps around" a subworkflow, where a primary workflow is used in a separate workflow as a [subworkflow](https://docs.rewst.help/documentation/automations/workflows#subworkflows). Whereas a completion handler only runs when a workflow completes, a workflow wrapper can run before or after completion. You apply this strategy when you want certain tasks to run before or after the tasks within a subworkflow, and want to visualize the process on one workflow canvas. For example, you might create a workflow wrapper to handle custom input from a Rewst form, prior to a Crate running. The visual below shows this strategy, running a few tasks before the Microsoft User Onboarding subworkflow.

![](/files/yM2nWkQs6IuRybgZKiK3)<br>


# Task transitions

## **What are task transitions?**

*Task transitions* are the bridges that connect different action, ensuring that workflows move forward as designed. Each action has two circular nodules on its side and bottom. Click on either and drag to the next action to set up the transition. Depending on the criteria set, one action might branch out to multiple subsequent actions.

<figure><img src="/files/CIgjcSYTGlhlunTydfHc" alt=""><figcaption><p>An action with no set transition - note the two circular <strong>Add Transition</strong> bubbles</p></figcaption></figure>

The diamond that appears between the two actions once the transition has been created is called the *transition indicator*. Click on it to open the transition settings in the right side menu.

<figure><img src="/files/M5rGHEadNrGZWkdSJwzw" alt=""><figcaption><p>The transition indicator for a dragged action that has had its transition created</p></figcaption></figure>

### **Task transition order**

The Workflow Builder will evaluate transitions on the Canvas for follow-first actions. Order is shown by the number on the transition, but can be reordered to preference.

1. Right on the related action. This will open the right side menu.
2. Click the **Advanced** tab.
3. If **Follow First** is selected, the option to edit the order of transitions will appear, and order of the transitions can be dragged to preference. If **Follow All** is selected, order does not matter.<br>

{% columns %}
{% column %}

<figure><img src="/files/UUSTzR8MvdQelvwRJSbF" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}
![](/files/kDZMi9VDQ6UF0tKzuNrw)
{% endcolumn %}
{% endcolumns %}

## **Transition settings options**

<figure><img src="/files/snPAcpBpVK4UBX0ZRsH6" alt=""><figcaption></figcaption></figure>

* **Edit Transition**: Buttons beside the **Edit Transition** title give you options to either clone the current transition or remove it if it's no longer needed.
* **Custom Transition Label**: This is an editable field allowing you to give a meaningful name to the transition, aiding clarity as your workflow grows.
* **Condition**: This criteria governs the action's progression based on the options defined below. Depending on the outcome of this action, this rule determines which path to follow next. Left to right, these are:
  * **On Success**: Progress if the action succeeds.
  * **On Failure**: Progress if the action fails.
  * **Always**: Progress regardless of the outcome of the action.
  * **Custom Condition**: This is set custom, with Jinja.
* [**Data Aliases**](/documentation/automations/workflows/data-aliases): Click the **+ Add Data alias** button to define an easy-to-use variable that stores the results of the action transition.

{% hint style="success" %}
In the advanced options in the workflow body, you can opt to either follow the first left to right transition condition that returns true, or to follow all transitions from the action.
{% endhint %}

Right click on any transition indicator to open a submenu to **Duplicate Transition,** **Delete Transition**, or **Edit Transition Order**. Duplicate will recreate the exact transition and place it next to the original on the Workflow Builder Canvas. Edit Transition Order controls the sequence in which transitions are evaluated and executed. Transition order at any given time is indicated by numbers on the transition indicators. Learn more about this setting in our [Advanced Workflow Settings](/documentation/automations/actions-in-rewst) documentation.

<figure><img src="/files/tPMzeGSa58ojp16EMCSm" alt=""><figcaption></figcaption></figure>

## Transition modes

Settings for transition modes exist in the **Advanced** tab of the workflow's settings. For information on how these work, see our documentation for [advanced workflow operations](/documentation/automations/workflows/advanced-workflow-operations-menu#transition-modes).


# Data aliases

{% hint style="info" %}
To understand this topic, you'll need to first complete Lesson 3 of the Cluck University course Automation Basics. This will introduce you to JSON and teach you how to both understand and use JSON in Rewst. If you haven't done your coursework yet, start there, then come back to this document.
{% endhint %}

## **What are Data aliases?**

A *data alias* is a shortcut that extracts specific pieces of information from a JSON response and stores them in an easy-to-use *variable*. Instead of navigating the entire JSON structure every time, a data alias pulls out exactly what you need—like a user’s name or email—and makes it accessible throughout your workflow. Think of data aliases as custom labels you assign to specific data.

Recall that *the context* is where all data generated, captured, or used in a workflow is stored. Think of it as a shared memory for a specific workflow. Data aliases are stored in the context, making them available for reuse at any step in your workflow without re-fetching the data.

For example, imagine that you've set up your Microsoft Graph integration. You send a request via API call to get info about a user. The response comes back to you in JSON format, which can be lengthy and time consuming to search through. A data alias would let you get all of the information, or pinpoint specific information like the user's name or email address, and store it in a simpler variable in the context for use.

Together, variables, data aliases, and the context make your workflows in Rewst more efficient, organized, and adaptable. These tools help you reuse workflows, reduce manual work, and customize data handling to fit any automation need.

### Data alias requirements

When adding a new data alias, you'll need the following:

* **Key**: The name you assign to specific data.
* **Value**: The actual data it corresponds to. The code editor button allows for the use of Jinja customization for intricate data or expressions.

### Data alias context example

If you set an alias such as `my_task_result -> {{ RESULT }}`, tasks can later refer to this data using `{{ CTX.my_task_result }}`.

You can also use a data alias to extract specific information and manipulate data. Expanding on our example from above, take the input from the Microsoft Graph get user action and extract the user's name and user principal name for ease of use.<br>

1. Drag the Microsoft Graph **Get User** action onto the Workflow Builder Canvas.
2. Click on the action, then its **Parameters** tab.
3. Add your user into the **User ID** field.

<figure><img src="/files/u1pfE5XhCo2GPNBnNuCw" alt="" width="375"><figcaption></figcaption></figure>

4. Click the **General** tab.
5. Set your context variable name under **Publish Result As.** The workflow action results will be stored as this value.<br>

   <figure><img src="/files/wBCaIj3o3HyAt6tEH3qF" alt="" width="375"><figcaption></figcaption></figure>
6. Open the Jinja editor and set up your data alias.
7. Use the following Jinja to create a new dictionary object and set the `displayName` and `userPrincipalName` keys.<br>

   ```
   {{
   {
   "displayName": CTX.user_details.data.value.displayName,
   "userPrincipalName": CTX.user_details.data.value.userPrincipalName
   }
   }}
   ```
8. Run the workflow. Then, click **View Results**
9. Click **Load Context.**
10. Expand the context to see our data alias `filtered_user_details` now only showing the `displayName` and `userPrincipalName` .

    <figure><img src="/files/r8q5eTe9k1Nv8uYt8Dy9" alt=""><figcaption></figcaption></figure>

## Add a data alias to a workflow

Data aliases are added via transitions. See more about how to use [transitions in workflows here](/documentation/automations/workflows/task-transitions).

1. Click on the transition in your workflow in the Workflow Builder Canvas.\
   \
   ![](/files/M5rGHEadNrGZWkdSJwzw)
2. Click **+ Add Data Alias** in the right side menu.
3. Paste the key into the **key** field. Click ![](/files/yRhzrk2xPyH045czZ3PH) to open the Jinja editor and set up your data alias.
4. Click ![](/files/FJxFktN4V7ooGXjZKj4Q)to remove a data alias.
5. Click ![](/files/Q8G2ewL7jnYBcXIcoQFl) and drag it as desired to move multiple data aliases up and down in the data alias list.

<figure><img src="/files/8rbCdY8taxd1CKKVcw4l" alt=""><figcaption></figcaption></figure>

## Access data aliases in a workflow

1. Navigate to **Automations > Workflows**.
2. Search for your desired workflow.
3. Click **>** to the far right of that workflow to open its Workflow Builder Canvas.\ <br>

   <figure><img src="/files/Zing7k6gj1QWQl8tK42h" alt=""><figcaption></figcaption></figure>
4. Click <img src="/files/waKlgf9wITlR9KGqS8t8" alt="" data-size="line"> in the top navigation bar to open the **Settings** in the right side menu.
5. Click the **Data Aliases** tab. This will show a complete list of all existing data aliases for that workflow.


# Best practices for designing workflows

## Design principles

When designing workflows, keep these three guiding principles in mind.

1. Simplicity: Create workflows that are user-friendly and easy to understand.
2. Modularity: Break down workflows into smaller, reusable components.
3. Maintainability: Build workflows that are straightforward to update and maintain.

## Automation build standards

A good workflow should meet all of these requirements.

* Consistency: Standardized practices lead to a consistent experience across different workflows.
* Quality assurance: Adhering to standards makes quality checks more efficient.
* Reusability: Modular design enables the reuse of components, speeding up development.
* Scalability: Design your workflows to handle increased complexity as your needs grow.
* Efficiency: Avoid redundancy by following a standardized approach.
* Knowledge Transfer: Standards foster collaboration and knowledge sharing within your team.
* Flexibility: Rewst's standards allow easy integration of new features without major rework.

## Design, test, and document workflows

{% hint style="info" %}
For more on templating in Rewst, see our documentation [here](/documentation/automations/templates-and-scripts).
{% endhint %}

* Use pre-defined templates to speed up development and ensure adherence to best practices.
* Develop and test your workflows in a sandbox or development environment. Make necessary changes, test, and sync to your live environment. Always test a workflow before publishing.
* Document workflows manually or with RoboRewsty to keep track of the intent of each action and subworkflow.
* When publishing a workflow, document the changes made in that update to help with version control of your workflow.

## Workflow naming and categorization

{% hint style="info" %}
You can also use [tags](/documentation/settings/tags-in-rewst) within Rewst to organize your automations effectively.
{% endhint %}

Properly naming and categorizing your workflows is essential for clarity and navigation, especially as the number of workflows you use in Rewst grows over time.

Adhering to a consistent naming convention helps in understanding the purpose and function of each automation.

{% hint style="success" %}
**Proper example**: `List Disabled User Accounts`

**Improper example:** `Steve's Workflow`
{% endhint %}

* Put the name of the service in square brackets at the beginning - for example, `[servicename]`
* Put the name of the project in the square brackets if you're building a larger workflow - for example `[projectname]`
* Add `— OG` if the workflow type is an option generator
* Use a name that describes exactly what the workflow does - for example, `List Active Contracts in AT`

## Manage variables and actions

### Organization variables

* Employ descriptive and straightforward wording using `snake_case` for clarity.
* Prefix integration-specific variables appropriately, like `psa_` for PSA-related variables.

### Work with data aliases

* Separate complex [data alias](/documentation/automations/workflows/data-aliases) creation or modification into `Set Variable` tasks rather than creating them on the actual task doing the API call. This helps with easier troubleshooting should you encounter errors, such as determining if the API is experiencing issues versus if there is a Jinja error in your variable assignment.
* Separating the data aliases makes debugging easier, allowing you to test your code with real data.

### Naming actions

* Use snake case - for example, `this_is_snake_case` .
* Use descriptive names that help explain what the action does.
  * For example, you may have an action to list templates, with the intent to extract a specific template. The action shouldn't be `rewst_list_templates` or even `list_templates`, it should be closer to `get_ai_prompt_template`*.*
  * Descriptive naming makes readability much easier when checking the results of your workflow.
* Use BEGIN and END for noops at the beginning and end of the workflow.

### Naming variables: data aliases

* Use snake case - for example, `snake_case` .
* Names should be descriptive about what the data alias is storing - for example, `excluded_user_age` is more descriptive than `age`*.*
* JSON and dictionaries should use camel case for keys - for example, `{"userName": "thomas"}` rather than `{"user_name": "thomas"}`.
* Lists should use a plural name. All others should use singular - for example, `active_users` instead of `active_user` for a list of active users
* Don't use the variable type in the name as in `active_contracts_list`*.* Instead, it should be `active_contracts`*.*
* Don't abbreviate in names. The benefits of abbreviating variable names are negligible compared to the readability of using full descriptive names.

### Work with task transitions

{% hint style="info" %}
For more on transitions, see our documentation [here](/documentation/automations/workflows/task-transitions).
{% endhint %}

* Use conditions like `{{ SUCCEEDED and CTX.list_of_things|d }}` to control the flow based on task success or failure.
* Transitions are evaluated from left to right, so order them carefully.
* Follow All/Follow First:
  * **Follow All**: The task will follow every path that meets the criteria.
  * **Follow First**: The task will follow the first criteria that it matches and then stop. Use this when you expect only one condition to be met or when, as soon as a condition is met, you do not want the process to use other workflow branches.

## Limit API field results

Limiting the API field response to only the data you need helps in building clean workflows that are easy to understand, without overloading your tools.

* If unsure about the fields you need, consider running the query without any filtering initially. This approach lets you explore the available fields and understand what information is at your disposal.
* Once you've identified the necessary fields, be sure to limit the response to include only those. For instance, if you're listing users in Microsoft Graph and only require the UPN (User Principal Name) and User's ID, you should select the `userPrincipalName` and `id` fields.


# Advanced workflow operations menu

{% hint style="info" %}
This document assumes that you've mastered earlier workflow building concepts from Cluck University and our introduction to the workflow builder [here](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow). If you haven't yet completed that reading, come back to this page later.
{% endhint %}

These operations can be found inside each task's **Advanced** tab.

## Integration overrides

For more on integration overrides and how to use them, see our documentation [here](https://docs.rewst.help/documentation/automations/intro-to-triggers#integration-overrides).

Add an integration override to the task by clicking ![](/files/NgWXghDJGhgu569Dq4EK). This will expose a new submenu for **Configuration Selection Mode**.

<figure><img src="/files/BKaXXJ7DyU0VimqCYkvG" alt=""><figcaption></figcaption></figure>

## Transition modes: Saved configuration

*Transition modes* in Rewst are responsible for determining how transitions attached to a workflow action are followed. There are two primary modes:

<figure><img src="/files/O0shYVRUkrXNntuOqEc6" alt=""><figcaption><p>Note the two different colored transitions arrows</p></figcaption></figure>

* **Follow All**: This is the default mode. If your task has multiple conditions attached, the Follow All mode attempts to follow all of the specified transitions. In the workflow visualization, this mode is represented by the standard color blue.
* **Follow First**: In this mode, conditions are evaluated from left to right and as soon as the first condition is satisfied, the remaining conditions are disregarded. To differentiate these transitions in the workflow visualization, they are color-coded orange.
  * When Follow First is selected, a second option will appear to **Edit Transition Order**. Learn more about transition order in our [transitions documentation](/documentation/automations/workflows/task-transitions).\
    \
    ![](/files/ruiOtrJCKi92jKUDxGNn)![](/files/fn70Apvja1LiCsvKS6qT)

## Task transition criteria sensitivity

<figure><img src="/files/cFDvv84lg6DOCuNYofM9" alt=""><figcaption></figcaption></figure>

This setting is used to indicate how many parent tasks need to be satisfied. For example, `0` would indicate all tasks. If the workflow has two tasks with arrows pointing to a third task, that sensitivity is the number of tasks above it which need to be complete before it runs. This is particularly important when building workflows that contain [subworkflows](/documentation/automations/workflows#subworkflows).

## Run as org

<figure><img src="/files/I76E0Li3Z8bSvakgRApY" alt=""><figcaption></figcaption></figure>

The *Run as Org* option allows the workflow action to run in the context of another organization.

{% hint style="warning" %}
You can only run as org going from a parent organization to child organization. The workflow will fail when attempting to run as the parent organization, when the workflow is running in the child organization context.
{% endhint %}

The purpose of `Run as Org` is to temporarily pass the execution of a workflow task into the context of another organization. This is something you may see done when you have a task— be it an individual action or a subworkflow— that needs to be executed as if it were for a different org than the one the workflow is running for.

For example, if you wanted to have something run once for the parent organization that needed to also reference items for a child organization, a Run as Org option would solve this issue. Start by listing all organizations. Then, using `Run as Org` on a subworkflow, do things within that subworkflow for one or many of your managed organizations.

Or, when a form has an organization picker on it, where the organization ID is passed into the workflow from the form, `Run as Org` is used to have the actions in the workflow run as if they were for the selected organization, instead of the organization for which the form was loaded.

<figure><img src="/files/SQxUL8QEP3PR4UIZMeIZ" alt=""><figcaption></figcaption></figure>

## With items

<figure><img src="/files/b4ZdgVFBeoC8onmiXWOc" alt=""><figcaption></figcaption></figure>

*With Items* is the equivalent to a `foreach` statement in other languages.

With this, you can pass a number of objects into a certain action and collect the results from each and then do something.

{% hint style="warning" %}
When using with items in Rewst, it's important that you make the name of the task unique, and different from any other task name in that workflow.
{% endhint %}

In the example below, you're going to list every user that is enabled in the child organization, and create or update a contact for each one.

List all enabled users, then output this to a data alias called

```django
{{ CTX.all_users }}
```

The data alias has the following Jinja:

{% code overflow="wrap" %}

```django
{{
  [
    user
    for user in TASKS.m365_list_users.result.result.data.value
    if user.enabled
  ]
}}
```

{% endcode %}

You then have a subworkflow that creates or updates a contact. As per the best practice, use a subworkflow with your **With Items**.

In the **Advanced** tab, set the **With Items** field with this data alias.

The action now has the additional icon indicating that it has a `With Items` set on it.

During testing, or for example if creating tickets from an alert, you may sometimes want to limit the amount of alerts you get during this phase. Test the workflow on a subset of your total users initially to make sure it works as expected.

To achieve this, you could create an input variable on the workflow called `max_tickets_to_create_per_action`and set it to the maximum number of times you want that **With Items** to run.

If set to 1, it will only run on a single object within CTX.all\_users.

The below code is what you would use in the **With Items** field in the **Advanced** tab.

```django
{{ CTX.all_users[:CTX.max_tickets_to_create_per_action | int] }}
```

### Use inputs after creating With Items

Iterating through CTX.all\_users on the action means you can't use {{ CTX.all\_users.X }} as the property for the input.

Instead, you must use `{{ item() }}`

Say you want to get the first name of each user as an input. On your **`With Items`** action you would execute:

```django
{{ item().firstName }}
```

## Items concurrency

<figure><img src="/files/Ybzw9p32U7Ndqqx0WSp9" alt=""><figcaption></figcaption></figure>

If you're running a workflow task using With Items, this allows you to set how many of these processes run at the same time. It's recommended that no more than 10 concurrent actions be performed at a time to guarantee performance.

## Task timeout

<figure><img src="/files/U2HtF1QSptLVA9hfmqpL" alt=""><figcaption></figcaption></figure>

This allows you to adjust the number of seconds to wait for a task to complete. The default value is 10 minutes.

## Shallow clone a workflow

*Shallow cloning* is a feature of the Rewst platform that allows you to create a copy of an existing workflow or form. This is useful if you have a workflow that is very similar to another workflow, but which requires a few small changes.

Standard cloning copies the entire resource *pack—* workflow, forms, templates, triggers, etc— and when cloning into your own org, you end up with multiple duplicates of the same resource. Shallow cloning copies that single selected resource, but re-uses all of the dependencies that it has. If you have a subworkflow that's part of a main workflow, and you shallow clone that subworkflow, you will end up with a copy of the subworkflow. This lets you make changes to the subworkflow without affecting the original workflow.

There is no difference between the steps to clone or shallow clone a resource. Rewst will automatically detect if you are cloning something into your own org. If so, the platform will shallow clone it instead. Note that this removes the **Synchronize** button on the dialog, and instead shows a text to explain.


# Data input and output: Input variables and context variables

{% hint style="success" %}
To understand this topic, you'll first need to learn the difference between an input and an output.

An *input* is information that will be put into Rewst automations. This could be the contents of a form, or information sent via integration, for example. Knowing what your input is will help you determine what to use when crafting your automations.

An *output* is the expected result of the automation.
{% endhint %}

### Workflow input: Input variables

Workflow inputs are commonly known as *input variables*. The role of input variables is to provide data that can be used by tasks within the workflow, or into a subworkflow.

Input variables can be broken down into two parts:

1. A key
2. The specific data or values that vary

This is an example of a variable where \[first\_name] is the key and Ashley is the value:

\[first\_name] : "Ashley"

{% hint style="warning" %}
Input variables can only be modified or added on the source workflow, not clones of workflows unpacked from Crates.
{% endhint %}

You can add new variables, or modify existing ones, by navigating to your **Workflow >** <img src="/files/waKlgf9wITlR9KGqS8t8" alt="" data-size="line"> **> Input**.

Click **+ Add Input** to see a number of new fillable fields and checkboxes.

<figure><img src="/files/BV3ttqxgeDBceBEldKeR" alt=""><figcaption></figcaption></figure>

1. **Name:** This can be a unique entry relevant to what the aim of the input is going to be. This should not contain spaces.
2. **Label:** This text field is used to set a friendly name. It's the field name visible at the time of input.
3. **Type:** Short for data type, this field defines what format the data will be in. The most common types are Text (general string), Integer (whole number), and String (a combo of characters).
4. **Default:** You can specify a value that will be used if no other input is specified manually.
5. **Description:** You can give a better description of what the field is used for.
6. **Required** checkbox: When checked, this marks the input parameter as mandatory. The workflow will expect a value to be provided for this input when it's executed. This is especially relevant when the workflow is called as a sub-workflow: the parent workflow must supply a value for any required input, or the execution will fail. It essentially enforces that the parameter cannot be left empty or omitted.
7. **Multiline** checkbox: When checked, this changes the input field from a single-line text box to a larger, multi-line text area. This setting affects how the input appears when configuring the workflow— for example, when setting up a subworkflow action that calls this workflow. It's useful for inputs that expect longer content like Jinja expressions, JSON blobs, descriptions, or any text that benefits from more editing space. It doesn't change the data type, and only gives you a bigger box to type in.

Input variables get their values in a Rewst workflow through the workflow's initial trigger event. Any data type that is valid in JSON can be used as an input variable.

### Workflow action inputs

When variables are created within the workflow, they become context variables, and can be used directly in action inputs.

{% hint style="info" %}
Recall from your Cluck University training that *the context* is where all data generated, captured, or used in a workflow is stored.
{% endhint %}

In the example below, creating a user in Microsoft 365 using three variables:

1. First Name
2. Last Name
3. Domain

For now, these are all specified directly on the workflow rather than being submitted via a form.

<figure><img src="/files/JbrTTYBpiZEKSyyoSaFX" alt=""><figcaption></figcaption></figure>

Create an action by dragging it from the integration list on the left menu.

<figure><img src="/files/qBSXR3O4lqlP8Uo2h2m1" alt="" width="375"><figcaption></figcaption></figure>

Click on this action to reveal a number of input parameter fields in the right side menu. Click ![](/files/yRhzrk2xPyH045czZ3PH) to the right of the field to open up a Monaco editor.

Click ![](/files/aPgXyVSjbdkTjcW9DSub) to the right of the field to open up a Monaco editor, the same type that VSCode uses. Learn more about the [code that Rewst uses, called Jinja, here](broken://pages/Xie1v7V1Vqm4kxsoGpiM).

Use the variables by using CTX, which stands for context, and then the name of the variable, as outlined in the code block below. This will autocomplete to make it easier to reference.

<img src="/files/1NMdTDUEDWiGqCiFmo4K" alt="" width="370">

```django
{{ CTX.first_name }}
{{ CTX.last_name }}
{{ CTX.domain}}
```

Despite the data being static at this point, the process is the same regardless of where the data is coming from.

### Workflow output

Similarly to the above, you can configure an output of a workflow. These are generally used in two situations:

1. In an [Options Generator](/documentation/automations/workflows/option-generator-workflows#create-an-option-generator-workflow) workflow, the output is what is passed through to the form. For example, if you have a workflow that lists users in a variable called `{{ CTX.users }}` - you would configure an output variable of options mapped to this variable, as per the below image. This then, in the form, would list the users in a dropdown field. This is how dynamic data works in form. Read more about that in [types of workflows](/documentation/automations/workflows/option-generator-workflows).

<figure><img src="/files/7ukg0X9TBPOiqKIrXCfa" alt="" width="546"><figcaption></figcaption></figure>

2. The other time this would be used is if you have a [subworkflow](/documentation/automations/subworkflows). A subworkflow is no different from a standard workflow, except for the fact it lives within another workflow. If you were passing data back from the subworkflow into the main workflow, this would be done via an output variable.

### Workflow action outputs

One of Rewst's ultimate purposes is to integrate various platforms into a workflow and use data from each to do something else. In this example, you'll get a list of users where the userPrincipalName matches X, then create a ticket using information from that request.

First, take the action of **List Users** from the Microsoft Graph integration in the action menu of the workflow builder. There are no inputs required here, and it will list every user on the tenant that it is integrated with, or that the [trigger](/documentation/automations/intro-to-triggers) is set for. If you ran this action as-is, you would get the list of users, but wouldn't be able to use that data anywhere.

This is where [task transitions](/documentation/automations/workflows/task-transitions) come into play. Click the **On Success** transition on the action. This gives you the option to create a [data alias](/documentation/automations/workflows/data-aliases).

A data alias allows you to create a variable, similar to an input variable, but with data direct from an action API request. In our example below, we are creating a variable with the key called `user_details` and populating it with the data of the user using Jinja.

{% code overflow="wrap" %}

```django
{{ [ user for user in TASKS.m365_list_users.result.result.data.value if user.userPrincipalName == "RewstDocs@rewst.io" ] }}
```

{% endcode %}

Take your **create\_ticket** action from your respective PSA from the actions menu of the Workflow Builder. Using your newly created data alias, add the inputs onto that `create_ticket` input.

```django
User Exists {{ CTX.user_details.displayName }}
```

This would create a ticket with the title `User Exists RewstDocs@rewst.io`.


# Troubleshoot workflow executions and results

{% hint style="success" %}
If the issue involves another platform like your [RMM](/documentation/integrations/top-5-integration-types-get-started-with-integrations-in-rewst#rmm-integrations),[ PSA](/documentation/integrations/top-5-integration-types-get-started-with-integrations-in-rewst#psa-integrations), or email system, check that platform's documentation or status page for recent changes or requirements.
{% endhint %}

## Workflow executions for troubleshooting

{% hint style="info" %}
See our documentation for how to view workflow results [here](https://docs.rewst.help/documentation/automations/workflows#view-specific-workflow-results).

To learn the fundamentals of troubleshooting in Rewst, sign up for our course in [Cluck University](https://learn.rewst.io/troubleshooting-in-rewst).
{% endhint %}

* Use the organization-level view to see all workflow executions for one organization.
* Use the workflow-level view to focus on one workflow across all organizations.
* Both paths lead to the Workflow Execution Summary, where troubleshooting begins.

{% embed url="<https://www.youtube.com/watch?t=36s&v=rX60BBs15yc>" %}

## How to read the workflow execution summary

The inputs and context sections of the summary tell the story of what data your workflow received and what the workflow did with that data. Learning to scan these two areas quickly is one of the most important skills in Rewst troubleshooting.

* The **Inputs** section shows the raw data that entered into the workflow, usually via form, webhook, or parent workflow.\ <br>

  <figure><img src="/files/85fgTIguUORdpPLdAo72" alt=""><figcaption></figcaption></figure>
* The **Context** section shows variables created or passed between actions. [Context variables](/documentation/automations/workflows/data-input-and-output-input-variables-and-context-variables) can change over the execution of the workflow, and each new iteration of variables will be in this list in chronological order.\ <br>

  <figure><img src="/files/5sGBWNFaLT4vt0zmTsjD" alt=""><figcaption></figcaption></figure>
* Common issues which lead to failed workflow tasks include typos, casing mismatches, missing values, or broken Jinja.

## Task results

Task results give you a detailed view of what happened in a workflow, and why something may have failed. By learning to read the request, the response, and the action logic, you can identify the issue and know where to work next.

Task results display two key pieces of information:

* The request Rewst sent—such as a JSON payload or API call to an integration
* The response that came back—typically with a status code and message body

Reading both helps you determine if the failure came from your setup, your data, or the external system.

### **How is data stored in context?**

* `{{ RESULT.result }}` stores a specific part of the action’s output, often the core data value.
* **Publish result as** saves the full response object to a named key in a context variable.
* These outputs can be reused in later actions through Jinja. For example, by using `Publish result` on one action to create the context variable `user_list`, you can reference that action's output on a future task with the Jinja syntax `{{ CTX.user_list }}`.

### Most common action failures

| Failure type                  | What the failure means                                                                                                                                    | How to resolve the issue                                                                                                                                                                                                                                                     |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Jinja error`                 | Rewst couldn’t evaluate the action due to bad syntax, missing data, or invalid filters                                                                    | Use the live context editor to test the Jinja expression and verify available values                                                                                                                                                                                         |
| `Integration not authorized`  | 401 or 403 errors mean the integration is either not connected or lacks permissions                                                                       | Recheck integration settings and scopes. If you change permissions in the external tool, reauthorize the integration in Rewst to apply the updates.                                                                                                                          |
| `Request rejected by API`     | 404, 405, or other 4XX/5XX errors mean the request structure is incorrect—or you may not have access to view the item being requested                     | Compare the request to the integration’s documentation—check the endpoint path, HTTP method, and resource IDs                                                                                                                                                                |
| `200 OK, but no result`       | The request was accepted, but didn’t return useful data. This may mean no results matched the query, or the operation isn’t designed to return a response | Review the request parameters and expected output. Check if the API is designed to return a result for this operation, or if it executed successfully with no output                                                                                                         |
| `Transition criteria not met` | The action was skipped because a transition condition wasn’t met—often due to logic that didn’t evaluate as expected or pathing that skipped this action  | <p>Review the transition logic and action flow. Check for incorrect conditions or action paths that prevent the transition from executing</p><p>If the issue isn’t obvious, look at the last successful action—errors upstream often cause transitions to fail silently.</p> |

## Use contextual tools to troubleshoot your workflow

Rewst gives you three powerful tools: the [live editor](/documentation/automations/the-live-editor), which lets you test Jinja expressions using real context data without re-running the full workflow, the **re-run** button, which lets you re-run the full workflow using the same inputs, and the test button, which offers a quick way to demo the workflow.

### Use the [live editor](/documentation/automations/the-live-editor) when:

* You’re troubleshooting a Jinja error
* You’re checking if a context variable exists or is formatted correctly
* You want to preview loops, filters, or logic before adding it to a workflow
* You need to manipulate or explore context safely without running the workflow

### Use the [test button](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow) in the workflow editor when:

* You’re building or editing a workflow
* You want to test changes as you go by running a true execution, not just testing data
* You need a fast feedback loop while adjusting actions

### Use the re-run button when:

* You’ve fixed something and want to confirm the outcome
* You’re testing workflows with consistent inputs like forms or webhooks
* You want to validate that a change resolved the issue end-to-end

{% hint style="warning" %}
If you do plan to re-run the workflow but want to avoid unintended changes, take steps to isolate it for safe testing. That might include:

* Temporarily commenting out actions that make changes
* Using a test org or test input values
* Adding conditional logic to skip sensitive steps during testing
  {% endhint %}

## Know when to escalate your failure to Rewst support

{% hint style="info" %}
This four step model is introduced and outlined in our Cluck University training. For details on these steps with visual examples, see our course [**Troubleshooting in Rewst**](https://learn.rewst.io/troubleshooting-in-rewst).
{% endhint %}

Remember to ask yourself the following questions while troubleshooting your results.

{% stepper %}
{% step %}

### Where did it run?

Check the org-level vs. workflow-level execution. Use ![](/files/E0VyPaGNj1MrpuFwS7ug) **> Execution History > Executions** from the Workflow Builder, or **Automations > Results** in the left side menu of your Rewst platform.
{% endstep %}

{% step %}

### What data came in?

Review the **Inputs** section to confirm trigger values or parent workflow data were passed correctly.
{% endstep %}

{% step %}

### What was created in context?

Open the **Context** tab and look for expected variables. Check for typos, nulls, or casing mismatches.
{% endstep %}

{% step %}

### What failed, and why?

Click into the failed action. Read the error message and check:

* Jinja issues
* Transition criteria
* Integration authorization
* API request and response details
* External system behavior - check platform documentation if the action involves an outside service
  {% endstep %}
  {% endstepper %}

If you've dealt with each of these points and still can't resolve the issue, [escalate to Rewst's support team](/support-and-community/roc-support). Include the following in your ticket:

* The organization and workflow name
* A link to the workflow execution summary
* Action result screenshots
* What you've tried so far


# Option generator workflows

When automating certain processes, it's important to use dynamic options that adjust based on the input. Using the same list of options every time can lead to errors by applying choices that don't fit the situation. When an automation gets information from a form, it's important that the data on the form be dynamic, and adjust based on previous inputs or selections on that same form.

An *option generator* workflow will always be connected to a form, and allows you to provide tailored, dynamic options for specific fields in that form. For example, in an automation that updates a user's group memberships, the list of groups is tailored to the input. You wouldn't want to add an individual to a group that they're already a member of, nor would you want to remove them from a group that they're not a member of. To add a user to a group, you would generate a list of groups that are not already part of the user's group memberships. To remove a user from a group, you would generate the user's current list of group memberships.

{% hint style="info" %}
The order of operations for creating the pieces needed to pull off an option generator is flexible. You can create the option generator workflow first, or the form that connects to the option generator workflow. In the below example, the workflow is made first.

Ultimately, an option generator workflow needs three things:

1. A workflow designated as an option generator in the workflow configuration.
2. Workflow output configuration that sets the value of options to the relevant workflow context variable.
3. A Rewst form that contains a form field connected to the option generator workflow and its trigger.

[RoboRewsty](/documentation/roborewsty) can also help you generate option generator workflows, but the order of operations for how you make your ask and generate the pieces is important. If you ask for his help to make the option generator workflow from scratch, you'll be required to manually set up the form he uses before asking for his help. If you build the option generator yourself, then ask RoboRewsty to build a form for use with the option generator, he can generate the form for you.
{% endhint %}

### Create an option generator workflow

Before you begin, decide which options need to be displayed based on the user’s selection. For this example, the list of groups will change depending on whether the action is to add or remove a user.

1. [Create a new workflow](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow).
2. Click <img src="/files/waKlgf9wITlR9KGqS8t8" alt="" data-size="line"> in the top menu bar of your workflow's Workflow Builder Canvas.
3. Click the **Workflow Type** drop-down selector.
4. Select **Option Generator**.<br>

   <figure><img src="/files/ukoZykguOn6b1Jn12mpy" alt=""><figcaption></figcaption></figure>
5. Click the **Output** tab.
6. Click **+ Add Variable** to create an output variable. Name the variable `options`. Every option generator workflow must have an [output variable](/documentation/automations/workflows/data-input-and-output-input-variables-and-context-variables#workflow-output) called `options`, which will contain the context variable that holds the data that you want to display.<br>

   <figure><img src="/files/K0VjnFlGkk3UKuk1vH5k" alt=""><figcaption></figcaption></figure>
7. Set up a [trigger](/documentation/automations/intro-to-triggers) for the workflow. We recommend using an always pass trigger, to allow the corresponding form to 'always' be available to use. When you attach the trigger, you have the ability to add an integration override, which allows you to choose which organizations will run that specific option generator.

### Create a form to be used with the workflow

Remember, workflow generated options allow forms to be highly dynamic. When a form field is connected to an option workflow, it will return a list of options based on the input.

See the documentation for how to use our form builder to achieve this step [here](/documentation/automations/forms/intro-to-forms#option-two-workflow-generated-options).

### How the form and workflow come together to generate options

1. When the workflow runs, it should result in a context variable `{{ CTX.options }}` that contains a list of items with key-value pairs that will be referenced in the form editor.<br>

   <figure><img src="/files/cjjOuQKAPzF9dK72yzxO" alt=""><figcaption><p>An example of an options generator workflow for one of our unpacked Crates</p></figcaption></figure>
2. The values here will be used in the **Label Field** an **Value Field** for a form fiel&#x64;*.*
   1. The **Label** is what gets shown to the user who fills out the form as an available choice.
   2. The **Value** field will be set to the value of the **Field Name** when that form is submitted. Workflows will reference this as `{{ CTX.<field_name> }}`
   3. Using the **Default Selected Field** will evaluate an attribute of the `options` list for truthiness. Items which evaluate `true` will be selected by default when this field populates.

<figure><img src="/files/JBtqoJi48bK43MSQAbSW" alt=""><figcaption></figcaption></figure>


# Keyboard shortcuts for the Workflow Builder

## **Workflow**

<table data-search="false"><thead><tr><th>Action</th><th>Mac</th><th>Windows and Linux</th></tr></thead><tbody><tr><td>Save</td><td>Cmd+S</td><td>Ctrl+S</td></tr><tr><td>Rename workflow</td><td>F2</td><td>F2</td></tr><tr><td>Edit Workflow JSON</td><td>Cmd+J</td><td>Ctrl+J</td></tr><tr><td>Export</td><td>Cmd+Shift+E</td><td>Ctrl+Shift+E</td></tr><tr><td>Clone workflow</td><td>Ctrl+Shift+D</td><td>Ctrl+Shift+D</td></tr><tr><td>Version History</td><td>Cmd+Shift+V</td><td>Ctrl+Shift+V</td></tr><tr><td>Execution Viewer</td><td>Cmd+Shift+X</td><td>Ctrl+Shift+X</td></tr></tbody></table>

## **Layout**

| Action                 | Mac    | Windows and Linux |
| ---------------------- | ------ | ----------------- |
| Auto-layout vertical   | Ctrl+G | Ctrl+G            |
| Auto-layout horizontal | Ctrl+H | Ctrl+H            |

## **History**

| Action | Mac                 | Windows and Linux     |
| ------ | ------------------- | --------------------- |
| Undo   | Cmd+Z               | Ctrl+Z                |
| Redo   | Cmd+Shift+Z / Cmd+Y | Ctrl+Shift+Z / Ctrl+Y |

## **Navigation**

| Action   | Mac           | Windows and Linux |
| -------- | ------------- | ----------------- |
| Zoom in  | Cmd+= / Cmd++ | Ctrl+= / Ctrl++   |
| Zoom out | Cmd+-         | Ctrl+-            |
| Fit view | Cmd+1         | Ctrl+1            |

## **Selection**

| Action                   | Mac                | Windows and Linux  |
| ------------------------ | ------------------ | ------------------ |
| Duplicate selected tasks | Cmd+D              | Ctrl+D             |
| Delete selected tasks    | Delete / Backspace | Delete / Backspace |

## **Overlays and panels**

| Action                         | Mac                | Windows and Linux  |
| ------------------------------ | ------------------ | ------------------ |
| Close Execution Viewer overlay | Esc                | Esc                |
| Close Notes panel              | Esc                | Esc                |
| Delete selected note           | Delete / Backspace | Delete / Backspace |

## **Modifiers**

| Action       | Key          |
| ------------ | ------------ |
| Multi-select | Shift (hold) |


# Boolean logic in Rewst workflows

## Boolean values and their role in automation

*Boolean* values represent simple yes/no conditions, like on/off or true/false. They define rules and logic in workflows by evaluating conditions.

Boolean values are fundamental in automation workflows, controlling decision-making and process flow. Understanding Boolean logic helps ensure that workflows are efficient, reliable, and easy to maintain.

## Key boolean concepts

* **Boolean values**: Represent `true` or `false`, similar to `1` (on) and `0` (off).
* **Logical operators**: `and`, `or`, `not` determine conditions in workflows.
* **Comparison operations**: Evaluate conditions (e.g., `user_role == "admin"`).
* **Custom conditions in workflows**: Enable transitions based on Boolean evaluations.

## Boolean operators in Rewst workflows

Boolean logic controls workflow decisions using these key operators:

* **`and`** – Requires both conditions to be true.
  * Example: `user_logged_in and is_admin`
* **`or`** – Requires at least one condition to be true.
  * Example: `is_manager or is_admin`
* **`not`** – Inverts a Boolean value.
  * Example: `not user_logged_in` (returns `true` if `user_logged_in` is `false`).

## Boolean logic in action

* **True and false = false** – Both conditions must be true for `and` to return `true`.
* **True or false = true** – Only one condition needs to be true for `or` to return `true`.
* **Not false = true** – Flips the Boolean value to its opposite.

## Best practices for boolean logic in Rewst

To ensure efficiency and maintainability, follow these best practices.

### Structuring logical conditions

* **Group logic with parentheses**: Ensures conditions execute in the correct order.
  * Example: `(is_admin and is_active) or is_super_admin`
* **Use `in` for cleaner conditions**:
  * Before: `if role == "admin" or role == "super_admin"`
  * After: `if role in ["admin", "super_admin"]`

### Simplifying boolean expressions

* **Use ternary operators for concise logic**:
  * Syntax: `variable = value_if_true if condition else value_if_false`
  * Example: `status = "Active" if is_active else "Inactive"`
* **Leverage short-circuit evaluation**:
  * Skips unnecessary checks by placing the most likely condition first.
  * Example: `if user_logged_in and is_admin:` (Skips `is_admin` check if `user_logged_in` is `false`.)

{% hint style="info" %}
For more on how boolean values relate to Rewst, complete our Clean Automation course in Cluck University.
{% endhint %}


# Triggers

## What is a trigger?

*Triggers* initiate [workflows](https://docs.rewst.help/documentation/workflows) in Rewst. Every workflow must have a trigger to define when and how it starts. Essentially, triggers put the automate in automation. Choosing the right trigger ensures that your workflows execute at the right time, with the right data, to drive efficiency and consistency in your operations.

A trigger is also used on any [form](https://docs.rewst.help/documentation/forms) input that requires a workflow. If a form uses the **Dynamic** button, then you must also create a trigger on the workflow associated with that form.

For more on how to see which triggers appear on a specific workflow, view our documentation [here](/documentation/automations/workflows#view-triggers-for-a-specific-workflow).

## View all triggers

Navigate to **Automations > Triggers** in the left side menu of Rewst to view the total triggers page, which contains a sortable list of all triggers in your Rewst instance, organized by tabs labeled with automation type. This includes triggers from your custom-built workflows and from unpacked Crates. Click on any of the column headers to sort the list by that criteria. Use the **Tags** drop-down selector to filter the list by specific tags.

<figure><img src="/files/wG4JT8P9l8UcoopEfDUL" alt=""><figcaption></figcaption></figure>

Toggle any trigger to enabled or disabled in the **Status** column. Once toggled on, the slider will turn green, and a green checkmark will appear to the right to let you know that the enablement is complete.

{% hint style="warning" %}
We're currently working on a feature limitation that prevents the last activity display for Always Pass and Interval triggers. Instead of listing the last activity, the trigger will show that it has never been activated. For these particular trigger types, confirm the last time the trigger was activated directly in the trigger rather than in the triggers page.
{% endhint %}

## Three trigger modes in Rewst

{% hint style="info" %}
Rewst launched the new Workflow Builder in May of 2026. Prior to that product change, the term *completion handler* was used to refer to the interlinking of workflows. If you're a seasoned Rewst user, note that completion handlers are now achieved via inbound and outbound triggers.
{% endhint %}

There are three trigger modes in Rewst. All are selected when creating your trigger in the trigger settings of the right side menu. Trigger modes can't be edited after a trigger is created. Click each type below to expand and learn about different modes.

<details>

<summary>Integration mode: Workflow triggered by an integration</summary>

his is the default choice for standard events within the Rewst platform. The workflow waits for specified events to happen in your partner tools, if those partner tools are integrated with Rewst. Examples include ticket updates in your PSA, or user creation alerts. When you choose integration mode, the **Trigger Type** drop-down selector appears with a complete list populated to include all of your Rewst integrations.

<figure><img src="/files/0xVUmFY9C3ElOiS8fE8b" alt="" width="238"><figcaption></figcaption></figure>

</details>

<details>

<summary>Inbound mode: Workflow triggered by another workflow's completion</summary>

This enables the workflow to start when another workflow completes, pulling in the data from each run. The workflow you're currently setting up is the first, enabling workflow in this scenario. Examples include alerting for failed workflow executions, like kicking off the trigger based on a failed status. These workflows have a [context variable ](/documentation/automations/workflows/data-input-and-output-input-variables-and-context-variables)that can be used to reference previous contexts from the workflow that was completed. Select one or more status conditions that will trigger the target workflow

<figure><img src="/files/Hz1exlTnTAaNemaKY1LW" alt="" width="241"><figcaption></figcaption></figure>

Contexts from the previously run workflow can be accessed with the `COMPLETED_WORKFLOW` variable. You can access most info via the context including ORG and CTX such as:

1. `{{ COMPLETED_WORKFLOW.ORG.VARIABLES.cw_manage_company_id }}`
2. `{{ COMPLETED_WORKFLOW.CTX.user.username }}`

Inbound and outbound triggers will always run in the context of the parent organization. If you are taking actions on a suborganization in the workflow, then you must use the run-as-organization functionality and overrides set at the trigger level.

The organization ID that was used in the previous workflow context can be referenced with the following Jinja:

`{{ COMPLETED_WORKFLOW.ORG.ATTRIBUTES.id }}`

### Test inbound triggers <a href="#access-the-context-of-the-previous-workflow" id="access-the-context-of-the-previous-workflow"></a>

Inbound trigger data is hard to fake for testing because it's represented as `COMPLETED_WORKFLOW.` instead of `CTX.COMPLETED_WORKFLOW.` Rather than running an entire workflow multiple times to test just this one element, create a [noop action](https://docs.rewst.help/documentation/workflows/actions-in-rewst/core-actions#no-operation-noop) that sets the test data, and use it to trigger your inbound trigger.

In the noop, set all of the variables that will be used in your inbound trigger in the On Success transition as data aliases.

It’s important that the names of the data aliases you create in the On Success transition of the noop match both:

* the names of the variables that will be used in your inbound trigger
* the names of the variables that will be used in the live parent workflow that your inbound trigger is triggered by

Add static values that represent a good test case for ensuring that your inbound trigger functions the way you expect.

#### **Example:** Test inbound triggers

In the example below, we’ve created a workflow with a single noop. In the **On Success** transition, we’ve added several data aliases that represent user data that could be used to test a completion handler, which could be used after a user is onboarded or offboarded.

<figure><img src="/files/Y8DrljYSaxBS1CKJb3VN" alt=""><figcaption><p>The noop action, its On Success transition, and the corresponding data aliases</p></figcaption></figure>

Once you’ve created the noop and added the correct data, attach this workflow to your other workflow's inbound trigger as another parent workflow that will trigger the the inbound trigger. This will enable testing. If you need to run your test workflow for organizations other than your parent MSP organization, add a trigger to the workflow which will allow you to select which organization the test workflow runs for.

</details>

<details>

<summary>Outbound mode: Workflow's completing triggers another workflow</summary>

This enables another workflow to start when your workflow completes, pulling in the data from each run. The workflow you're currently setting up is the second, completing workflow in this scenario. These workflows have a [context variable ](/documentation/automations/workflows/data-input-and-output-input-variables-and-context-variables)that can be used to reference previous contexts from the workflow that was completed. Select one or more status conditions that will trigger the target workflow

<figure><img src="/files/TbbO9yzzmz7y36Tod9FM" alt="" width="242"><figcaption></figcaption></figure>

Contexts from the previously run workflow can be accessed with the `COMPLETED_WORKFLOW` variable. You can access most info via the context including ORG and CTX such as:

1. `{{ COMPLETED_WORKFLOW.ORG.VARIABLES.cw_manage_company_id }}`
2. `{{ COMPLETED_WORKFLOW.CTX.user.username }}`

Inbound and outbound triggers will always run in the context of the parent organization. If you are taking actions on a suborganization in the workflow, then you must use the run-as-organization functionality and overrides set at the trigger level.

The organization ID that was used in the previous workflow context can be referenced with the following Jinja:

`{{ COMPLETED_WORKFLOW.ORG.ATTRIBUTES.id }}`

</details>

{% hint style="warning" %}
Inbound and outbound workflow triggering should be linear, never circular. Don't set two workflows to continually run when the other completes. This will cause the workflows to trigger each other in an infinite loop.
{% endhint %}

## Create a trigger

Depending on your workflow, you may have one trigger or multiple triggers— for example, a webhook trigger and a trigger that runs when a ticket gets saved in your PSA. In either case, to begin:

1. Click ![](/files/17lCeuoq6HByl9lrLING) to open the library.
2. Click the **Flow Control** tab.
3. Drag the yellow **Triggers** bar onto your Workflow Builder Canvas.
4. Click on the bar to open trigger settings in the right side menu. Note that if you have one trigger or many triggers, all will show up in this right side menu in a list, which is always accessible by clicking the yellow bar. The number of total triggers will appear in a counter box in the far right of the dragged yellow bar.

<figure><img src="/files/Q9JEkLdyfODoJpNolBUX" alt=""><figcaption><p>Note the Flow Control tab on the left, and the trigger settings on the right.</p></figcaption></figure>

5. Click + **Add Trigger**.
6. Fill out the **Trigger Settings** menu as follows:
   1. Enter a descriptive name into the **Trigger Name** field.
   2. Toggle the trigger to **Enabled** to use it in the workflow.
   3. Use the **Trigger Mode** drop-down selector to choose the mode for your trigger:
      1. **Integration**: The workflow is triggered by an integration with Rewst. If this is selected, choose a **Trigger Type** from the drop-down selector. Read more about trigger types in the [later sections of this document](#core-triggers).
      2. **Inbound**: The workflow's start is triggered by another workflow.
      3. **Outbound**: The workflow's completing triggers another workflow.
   4. Fill out the fields that appear depending on your trigger mode selection. For more on trigger modes and their required fields, see the [trigger mode section](#three-trigger-modes-in-rewst) of this document.
7. Optional: Click the **Overrides** tab and add [integration overrides](/documentation/automations/intro-to-triggers).
8. Optional: Click the **Run For** tab and add or [tags](/documentation/settings/tags-in-rewst).
9. Click **Save Trigger**.
10. Follow the process again to add additional triggers.

<figure><img src="/files/F9HPhRDDExfzbuJuQQ0d" alt="" width="233"><figcaption></figcaption></figure>

### Trigger criteria

When you're comfortable with the basics of triggers, learn more about [trigger criteria here](#trigger-criteria). It's a separate submenu tab the trigger menu, and has its own documentation page. The below table outlines the fields in the trigger criteria configuration menu.

<table data-full-width="false"><thead><tr><th width="267">Item</th><th>Description</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>Whatever you would like to name your trigger, with a descriptive word or phrase for what it does.</td></tr><tr><td><strong>Enabled</strong></td><td>Toggle this on or off.</td></tr><tr><td><strong>Organizations</strong></td><td>Select all the organization that exist within Rewst that may need to use this workflow. If you add a new client, they will have to be added in that workflow trigger.</td></tr><tr><td><strong>Integration Override</strong></td><td>To give the workflow access to integrations and credentials owned by the parent organization, that default behavior must be explicitly overridden. In the above example image, the trigger allows your clients to use your PSA, RRM and licensing integration. See more about integration overrrides in the next section of this document.</td></tr><tr><td><strong>Trigger Type</strong></td><td>There are a number of types to choose from, such as a webhook, form submission, ticket saved, M365 alerts. See <a data-mention href="#core-triggers">#core-triggers</a> for more information on common trigger types.</td></tr><tr><td><strong>Form</strong></td><td>If your trigger type is a form submission, you would select the form that links to the workflow.</td></tr></tbody></table>

### What are integration overrides

*Integration overrides* allow selection between multiple versions of the same integration at both the trigger and action levels, enabling granular control over workflow execution. When a workflow is triggered by and running within the context of a child organization, by default it only has access to the org's own integrations and configurations. To give the workflow access to integrations and credentials owned by the parent organization, that default behavior must be explicitly overridden. Rewst recommends adding more integration overrides rather than fewer.

<figure><img src="/files/kSd6tdKMHxM9EcXXNyZ4" alt=""><figcaption><p>Choose the integration for which to apply configuration overrides to by clicking<br><strong>+Add Integration Override</strong> and selecting from the list.</p></figcaption></figure>

1. Click <img src="/files/sBncG6SVwvekQSqJzcOV" alt="" data-size="line"> next to integration overrides.
2. Choose your desired integration or integrations from the drop-down selector that appears. This will populate the options for that integration below the selector. Each selected integration will have its own accordion menu added to the trigger configuration page.
   1. Configuration Selection Mode options
      1. **Use Default** - The default configuration for the workflow owner will be used
      2. **Use Selected Config** - Select a specific integration configuration to use: choosing this option reveals a new **Integration Configuration** drop-down selector where you'll choose an existing configuration
      3. **Use Name Search** - Search the workflow owner's integration configurations by name: choosing this option reveals a new **Configuration Name** field where you'll enter the name
   2. **Configuration Fallback Mode** - The behavior to be used if the selected configuration is not found, available for all Configuration Selection Mode options excluding Use Default
      1. **Use Org Mapping** - Use the organization mapping defined in the integration settings page to select the configuration to use
      2. **Fail Workflow** - If the matching configuration is not found, the workflow will fail with an error

         \ <br>

### Add an integration override

1. Click the **Overrides** tab.
2. Choose your desired integration from the selector that appears. You may select multiple integrations, but must choose one at a time. Click **+ Add Integration Override** each time to add another integration, and **Edit Integration Override** to return to the list for additional selections. This will populate the options for that integration below the selector. Each selected integration will have its own menu added to the overrides list.

{% columns %}
{% column %}

<figure><img src="/files/E041XVVltcdxzLl0ZRJb" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/ALzJUZKGcMdHjtv6CdAM" alt="" width="239"><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

3. For each integration override, choose from the following settings:
   1. **Use Default** - The default configuration for the workflow owner will be used
   2. **Use Selected Config** - Select a specific integration configuration to use: choosing this option reveals a new **Integration Configuration** drop-down selector where you'll choose an existing configuration
   3. **Use Name Search** - Search the workflow owner's integration configurations by name: choosing this option reveals a new **Configuration Name** field where you'll enter the name
   4. **Configuration Fallback Mode**, available for Use Selected Config and Use Name Search only - The behavior to be used if the selected configuration is not found, available for all Configuration Selection Mode options excluding Use Default
      1. **Use Default** - If the matching configuration is not found, the default configuration for the workflow owner will be used
      2. **Fail Workflow** - If the matching configuration is not found, the workflow will fail with an error
4. Click **Submit**.

{% columns %}
{% column %}

<figure><img src="/files/cZvL65L9NCesHzJp70F7" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/HyZ8tSiRVk9wZbQXPwBn" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

{% hint style="warning" %}
Note that when you unpack a Crate, it will automatically look at your installed integrations to decide which integration overrides to apply to your particular unpack. If you add additional integrations or change integrations after a Crate has been unpacked, and want that integration to be recognized and used with integration overrides for the Crate's workflow, you'll need to go to the trigger for that workflow and manually add the new integration to the integration overrides field.
{% endhint %}

#### Integration override on an action

While integration overrides mainly live on and apply to triggers, you can also add them to actions under the **Advanced** tab of their right side configuration menu. The main use case for an action-based integration override is when you use [multi-instance integration](/documentation/integrations/multi-instance-integration) in Rewst.

The process and selections for this integration override are the same as for those set on a trigger.

<div><figure><img src="/files/JTZ1ma7HJInjm4SqiIxr" alt=""><figcaption></figcaption></figure> <figure><img src="/files/yqQQ5hF0bq7PMZZCeq7f" alt=""><figcaption></figcaption></figure></div>

{% hint style="info" %}
If you've set integration overrides on both the trigger and an action in a workflow, the action override takes precedence over the trigger override and will cancel it out.
{% endhint %}

### Activate trigger to run for

This submenu controls which organization**s** a workflow trigger is enabled for. When a triggered, it determines which organizations the workflow can execute in the context of. Each trigger on a workflow has its own Activate Trigger To Run For settings. They aren't shared between multiple triggers on the same workflow.

1. **Selected Organization** toggle
   1. Toggled on by default, this enables the trigger for the organization that owns the workflow, usually the parent organization
   2. Toggle off if you don't want the workflow to run for the owning organization
2. **Organizations** drop-down selector
   1. Manually select specific organizations
   2. Choose individual child organizations that should have this trigger active
3. **All Current and Future Managed Organizations** toggle
   1. Toggle on to automatically enable the trigger for:
      1. All currently existing child organizations
      2. Any new organizations added in the future - automatically included
4. Click the **Run For** tab.
5. Choose your settings:
   1. **Selected Organization** toggle
      1. Toggled on by default, this enables the trigger for the organization that owns the workflow, usually the parent organization
      2. Toggle off if you don't want the workflow to run for the owning organization
   2. **All Current and Future Managed Organizations** toggle
      1. Toggle on to automatically enable the trigger for:
      2. All currently existing child organizations
      3. Any new organizations added in the future - automatically included
   3. **Organizations** drop-down selector
      1. Manually select specific organizations
      2. Choose individual child organizations that should have this trigger active
   4. **Tags** drop-down selector
      1. Choose to activate organizations which have been given the specified tags
      2. Any future organizations tagged will be pulled in via the tag

<figure><img src="/files/pTrHauU7OBbnUYRH2eto" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}

* If you don't enable All current and future managed organizations, you must manually add new clients to the trigger when they're onboarded.
* You can't filter organizations by tags in this menu - it's either individual selection, all, or all plus future.
* Even if a trigger is activated for an organization, the workflow will only work if that organization has the required integrations configured and mapped.
* If the workflow uses parent organization integrations like your PSA, you must configure integration overrides on the trigger to give child orgs access to those credentials.
  {% endhint %}

### Critical timing

{% hint style="warning" %}
Starting on May 2, 2026, all workflows will default to their critical timing set as **False**. If you want a workflow to run at a specific time without flexibility, be it a new workflow or an existing workflow, you'll need to manually indicate this in the Critical Timing selector.
{% endhint %}

*Critical timing* is Rewst's setting for indicating if a workflow with a cron trigger must be run at a certain time or if there can be allowed variation in when the workflow is triggered. Choose **true** if the workflow must run at the same time each day. Choose **False** or **None** if the workflow's schedule has flexibility. This will adjust the start time, but maintain the frequency of when the workflow is triggered. By default, triggers that share the same schedule are spread across a short window to reduce load spikes and improve performance.

<figure><img src="/files/AdbEe6huZGwQKUh8Bkos" alt=""><figcaption></figcaption></figure>

The time window will depend on your schedule's frequency, capped at 30 minutes:\
`*/5 * * * *` : every 5 min — within \~1 min\
`0 * * * *` : hourly — within \~15 min\
`0 10 * * *` : daily at 10 AM — within \~30 min\
`0 0 1 * *` : 1st of each month — within \~30 min

## Modify an existing trigger

To modify an existing trigger, click on the yellow trigger bar. Then, click on the individual trigger in the trigger list. Update any of the settings in the tabs as desired, then click **Save Trigger**.

## Use a trigger on a form

Once the trigger has been created on a workflow, it can then be used on a form. This must be an options generator workflow. The requirements for this[ can be found here](/documentation/automations/workflows/option-generator-workflows).

<figure><img src="/files/UVPWLL1Mo1HBDj8Bo7jM" alt=""><figcaption></figcaption></figure>

The above is a screenshot from a form where a dropdown field has been selected and the output will be based on the workflow output. When running the form, if the client is added on the trigger and the trigger is set on the form, the workflow will run, and the options will fill into the form field.

## Core triggers

There are seven key triggers to understand when getting started with Rewst. These triggers cover a range of automation scenarios, from scheduled executions to real-time event responses. In Rewst, we denote these from other triggers by calling them *core triggers*. Type `core` into the **Trigger Type** field to isolate most of these trigger types from the total list.

<figure><img src="/files/INr1tnrEfX5fFsrN5idq" alt=""><figcaption></figcaption></figure>

<details>

<summary>Core - Always Pass</summary>

The *always pass trigger* allows a workflow to start without conditions. It is commonly used in workflows that do not depend on external events or schedules. It's mostly used with the **Test** button in the Workflow Builder Canvas, and options generators for forms that need an override for its fields. You might use this trigger when testing workflows, executing a workflow from another workflow without needing a specific event, or populating dynamic options in a Rewst form.

This trigger is most useful for:

* Manual workflow execution: running a workflow on demand
* Subworkflows or completion handlers: workflows triggered by other workflows
* Testing automation: verifying workflow functionality
* Option generators: dynamically populating form fields in Rewst

{% hint style="info" %}
For more information on option generators, refer to [Rewst Foundations](https://learn.rewst.io).
{% endhint %}

</details>

<details>

<summary>Core - App Platform</summary>

This trigger functions the same as Core - Always Pass. By using this trigger type, you create a clear indication that the intended use case is for Rewst's [App Builder](/documentation/app-builder). Note that it is only useful in locations where you can select a trigger— Data Tables and Charts.

</details>

<details>

<summary>Core - Cron Job</summary>

The *cron job trigger* initiates a workflow on a predefined schedule. This allows you to automate recurring tasks without manual intervention.

Schedules are configured using cron syntax. Consult [crontab guru](https://crontab.guru/) for help configuring this syntax.

For example, you can configure a workflow to run every Monday at 3:00 PM to generate weekly reports or clean up outdated records.

This trigger is most useful for:

* Scheduled maintenance workflows: clearing stale data, running audits
* Recurring notifications: sending reminders, generating reports
* Automated check-ins: verifying system statuses, updating dashboards

This trigger also uses [critical timing](#critical-timing).

</details>

<details>

<summary>Core - Form Submission</summary>

A workflow can be triggered when a user submits a form. Forms collect structured information, ensuring the workflow has the necessary data to proceed.

For example, you can submit an employee onboarding form to trigger a workflow that creates user accounts, assigns permissions, and sends welcome emails.

This trigger is most useful for:

* Request-based workflows: access requests, service requests
* Intake processes: user registrations, issue reporting
* Approval workflows: leave requests, expense approvals

{% hint style="info" %}
For help building a form, refer to [Conditional fields](/documentation/automations/forms/form-best-practices).
{% endhint %}

</details>

<details>

<summary>Core - Time Interval</summary>

Time intervals can be set to trigger a workflow repeatedly over specified periods. This trigger is suitable for workflows that need to repeat on a regular basis.

* **Examples**:
  * Every 5 minutes
  * Every hour
  * Daily
  * Weekly

{% hint style="info" %}
Check out our [Use webhook triggers](/documentation/automations/intro-to-triggers/use-cases-and-examples/using-webhook-triggers) page for a more detailed example.
{% endhint %}

</details>

<details>

<summary>Core - Webhook</summary>

A *webhook* *trigger* starts a workflow when external data is received in real time. Webhooks eliminate the need for manual checks, making them efficient for event-driven automation.

The webhook URL serves as a *listening endpoint*. When an external system like a CRM, ticketing system, or another Rewst workflow sends data to the webhook URL, the workflow is triggered immediately. This enables seamless integration between Rewst and external applications without requiring a direct API connection.

For example, a webhook could trigger a workflow whenever a new customer signs up in a CRM, automatically assigning them an account manager and setting up follow-up tasks.

This trigger is most useful for:

* Event-driven automation: responding to new leads, updating records on status changes
* Real-time notifications: escalating high-priority tickets, alerting teams to critical updates
* External system integrations: syncing data between platforms, processing incoming requests

{% hint style="info" %}
For more information on webhook triggers, refer to [Use webhook triggers](/documentation/automations/intro-to-triggers/use-cases-and-examples/using-webhook-triggers).
{% endhint %}

</details>

<details>

<summary>PSA: Ticket record saved</summary>

{% hint style="info" %}
Note that this is the only common trigger type that does not start with Core, as the trigger name will be specific to your brand of PSA. Search for that in the trigger type list instead.
{% endhint %}

This trigger is similar to the webhook trigger but is specific to PSA systems. When a ticket record is saved in an integrated PSA, the workflow starts automatically. This includes both newly created tickets and updates to existing tickets.

For example, if a ticket is updated to **Escalated**, a workflow can trigger an alert to the appropriate team or assign a senior technician.

This trigger is most useful for:

* Automating ticket management: escalating high-priority tickets, auto-assigning technicians
* SLA enforcement: sending reminders for unresolved tickets, auto-responding to specific cases
* Status-based automation: triggering follow-up workflows when a ticket is created or reaches a certain stage

{% hint style="info" %}
For more detailed information on PSA triggers, refer to [Customize PSA ticket triggers](/documentation/automations/intro-to-triggers/use-cases-and-examples/customizing-psa-ticket-triggers).
{% endhint %}

</details>

## Rewst triggers

*Rewst* triggers are additional triggers that can be used across all integrations and relate directly to the Rewst platform. Type `Rewst` into the **Trigger Type** field to isolate most of these trigger types from the total list.

<details>

<summary>Rewst - Added User</summary>

The Rewst - Added User trigger starts the workflow when a new user is added in Rewst. The triggering event is when the user signs in for the first time, not when the invite is sent. This trigger is useful for:

* Onboarding automation when new users are added to Rewst
* Sending welcome notifications to new users
* Syncing new user accounts to external systems
* Auditing and logging new user creation events
* Automatically assigning resources or permissions to new users

When this trigger kicks off, it provides the following data in `triggering_user_data`:

| Field          | Type             | Description                             |
| -------------- | ---------------- | --------------------------------------- |
| `id`           | string           | The user's unique identifier            |
| `role`         | string           | The user's role                         |
| `org_id`       | string           | The organization ID the user belongs to |
| `role_ids`     | array of strings | List of role IDs assigned to the user   |
| `username`     | string           | The user's username                     |
| `created_at`   | datetime         | When the user was created               |
| `updated_at`   | datetime         | When the user was last updated          |
| `is_superuser` | boolean          | Whether the user is a superuser         |

</details>

<details>

<summary>Rewst - Added User in Whitelist</summary>

The Rewst - Added User in Whitelist trigger starts the workflow when a user is whitelisted, or invited, in Rewst. This trigger is useful for:

* Sending custom welcome emails when users are invited to Rewst
* Logging and auditing user invitation events
* Triggering approval workflows before invites are finalized
* Syncing invite information to external ticketing or documentation systems
* Tracking who is inviting users and to which organizations

When this trigger kicks off, it provides the following data in `triggering_user_invite_data`:

| Field           | Type             | Description                                      |
| --------------- | ---------------- | ------------------------------------------------ |
| `id`            | string           | The invite's unique identifier                   |
| `email`         | string           | The email address of the invited user            |
| `org_id`        | string           | The organization ID the user is being invited to |
| `role_ids`      | array of strings | List of role IDs assigned to the invited user    |
| `created_at`    | datetime         | When the invite was created                      |
| `updated_at`    | datetime         | When the invite was last updated                 |
| `accepted_at`   | datetime         | When the invite was accepted - if applicable     |
| `is_accepted`   | boolean          | Whether the invite has been accepted             |
| `created_by_id` | string           | The ID of the user who created the invite        |

</details>

<details>

<summary>Rewst - Crate Published Trigger</summary>

The Rewst - Crate Published Trigger kicks off the workflow when a Crate is published in Rewst, allowing you to react programmatically. This trigger is useful for:

* Automating notifications when new crates are published to the Rewst marketplace
* Triggering review or approval workflows when crates are published
* Logging and auditing crate publication events
* Syncing crate publication information to external documentation or communication systems
* Automating post-publication tasks like announcements or version tracking

The Crate will include the following in the workflow execution once triggered.

`CTX.triggering_crate_data.crate_id` ID of the Crate `CTX.triggering_crate_data.workflow_id` ID of the parent workflow in the Crate

</details>

<details>

<summary>Rewst - Deleted User</summary>

The Rewst - Added User trigger starts the workflow when an existing user is removed in Rewst. This trigger is useful for:

* Offboarding automation when users are removed from Rewst
* Auditing and logging user deletion events for compliance
* Syncing user deletions to external systems (e.g., removing access elsewhere)
* Sending notifications when users are removed
* Cleaning up resources or permissions associated with deleted users

When this trigger kicks off, it provides the following data in `triggering_user_data`:

| Field          | Type             | Description                                     |
| -------------- | ---------------- | ----------------------------------------------- |
| `id`           | string           | The deleted user's unique identifier            |
| `role`         | string           | The user's role (at time of deletion)           |
| `org_id`       | string           | The organization ID the user belonged to        |
| `role_ids`     | array of strings | List of role IDs that were assigned to the user |
| `username`     | string           | The user's username                             |
| `created_at`   | datetime         | When the user was originally created            |
| `updated_at`   | datetime         | When the user was last updated                  |
| `is_superuser` | boolean          | Whether the user was a superuser                |

</details>

<details>

<summary>Rewst - Deleted User in Whitelist</summary>

The Rewst - Deleted User in Whitelist trigger starts the workflow when a user is deleted from a whitelist, meaning that their invite is removed in Rewst. This trigger is useful for:

* Auditing and logging when user invites are revoked or removed
* Sending notifications when pending invites are cancelled
* Syncing invite deletions to external ticketing or documentation systems
* Tracking invite lifecycle events for compliance purposes
* Cleaning up any resources or pending actions associated with revoked invites

When this trigger kicks off, it provides the following data in `triggering_user_invite_data`:

| Field           | Type             | Description                                             |
| --------------- | ---------------- | ------------------------------------------------------- |
| `id`            | string           | The invite's unique identifier                          |
| `email`         | string           | The email address of the invited user                   |
| `org_id`        | string           | The organization ID the user was invited to             |
| `role_ids`      | array of strings | List of role IDs that were assigned to the invited user |
| `created_at`    | datetime         | When the invite was originally created                  |
| `updated_at`    | datetime         | When the invite was last updated                        |
| `accepted_at`   | datetime         | When the invite was accepted - if applicable            |
| `is_accepted`   | boolean          | Whether the invite had been accepted                    |
| `created_by_id` | string           | The ID of the user who created the invite               |

</details>

<details>

<summary>Rewst - Managed Organization Added</summary>

The Rewst - Managed Organization Added trigger starts the workflow when a new parent organization is added in Rewst. This trigger is useful for:

* Automating client onboarding workflows when new managed organizations are added
* Sending notifications to internal teams about new clients
* Automatically provisioning resources or configurations for new organizations
* Syncing new organization data to external PSA, documentation, or CRM systems
* Triggering initial setup tasks like creating default users, permissions, or integrations
* Auditing and logging new organization creation events

When this trigger kicks off, it provides the following data in `triggering_organization_data`:

| Field             | Type     | Description                                  |
| ----------------- | -------- | -------------------------------------------- |
| `id`              | string   | The organization's unique identifier         |
| `tid`             | string   | The tenant ID                                |
| `name`            | string   | The organization's name                      |
| `domain`          | string   | The organization's domain                    |
| `is_msp`          | boolean  | Whether the organization is an MSP           |
| `created_at`      | datetime | When the organization was created            |
| `updated_at`      | datetime | When the organization was last updated       |
| `customer_id`     | string   | The customer ID                              |
| `roc_site_id`     | string   | The ROC site ID                              |
| `managing_org_id` | string   | The ID of the managing (parent) organization |
| `subscription_id` | string   | The subscription ID                          |

</details>

<details>

<summary>Rewst - Managed Organization Deleted</summary>

The Rewst - Managed Organization Added trigger starts the workflow when an existing parent organization is removed in Rewst. This trigger is useful for:

* Automating client offboarding workflows when managed organizations are removed
* Sending notifications to internal teams about client departures
* Cleaning up resources, configurations, or integrations associated with the deleted organization
* Syncing organization deletions to external PSA, documentation, or CRM systems
* Auditing and logging organization deletion events for compliance
* Revoking access or permissions tied to the deleted organization
* Archiving data or records related to the removed client

When this trigger fires, it provides the following data in `triggering_organization_data`:

| Field             | Type     | Description                                  |
| ----------------- | -------- | -------------------------------------------- |
| `id`              | string   | The deleted organization's unique identifier |
| `tid`             | string   | The tenant ID                                |
| `name`            | string   | The organization's name                      |
| `domain`          | string   | The organization's domain                    |
| `is_msp`          | boolean  | Whether the organization was an MSP          |
| `created_at`      | datetime | When the organization was originally created |
| `updated_at`      | datetime | When the organization was last updated       |
| `customer_id`     | string   | The customer ID                              |
| `roc_site_id`     | string   | The ROC site ID                              |
| `managing_org_id` | string   | The ID of the managing (parent) organization |
| `subscription_id` | string   | The subscription ID                          |

</details>

<details>

<summary>Rewst - Managed Organization Updated</summary>

The Rewst - Managed Organization Added trigger starts the workflow when an existing parent organization is updated in Rewst. This trigger is useful for:

* Syncing organization changes to external PSA, documentation, or CRM systems
* Sending notifications when client organization details are modified
* Auditing and logging organization update events for compliance
* Triggering workflows when organization settings or configurations change
* Updating related resources or integrations when organization data is modified
* Tracking changes to organization names, domains, or other key attributes

When this trigger kicks off, it provides the following data in `triggering_organization_data`:

| Field             | Type     | Description                                  |
| ----------------- | -------- | -------------------------------------------- |
| `id`              | string   | The organization's unique identifier         |
| `tid`             | string   | The tenant ID                                |
| `name`            | string   | The organization's name                      |
| `domain`          | string   | The organization's domain                    |
| `is_msp`          | boolean  | Whether the organization is an MSP           |
| `created_at`      | datetime | When the organization was originally created |
| `updated_at`      | datetime | When the organization was last updated       |
| `customer_id`     | string   | The customer ID                              |
| `roc_site_id`     | string   | The ROC site ID                              |
| `managing_org_id` | string   | The ID of the managing parent organization   |
| `subscription_id` | string   | The subscription ID                          |

</details>

<details>

<summary>Rewst - Updated User</summary>

The Rewst - Updated User trigger starts the workflow when a user is updated in Rewst. This trigger is useful for:

* Auditing user changes within Rewst
* Syncing user updates to external systems
* Triggering notifications when user roles or permissions change
* Logging user modifications for compliance purposes

When this trigger kicks off, it provides the following data in `triggering_user_data`:

| Field          | Type             | Description                             |
| -------------- | ---------------- | --------------------------------------- |
| `id`           | string           | The user's unique identifier            |
| `role`         | string           | The user's role                         |
| `org_id`       | string           | The organization ID the user belongs to |
| `role_ids`     | array of strings | List of role IDs assigned to the user   |
| `username`     | string           | The user's username                     |
| `created_at`   | datetime         | When the user was created               |
| `updated_at`   | datetime         | When the user was last updated          |
| `is_superuser` | boolean          | Whether the user is a superuser         |

</details>

<details>

<summary>Rewst - Updated User in Whitelist</summary>

The Rewst - Updated User in Whitelist trigger starts the workflow when a whitelist is updated in Rewst. This trigger is useful for automating actions when user invitations are modified in Rewst, such as:

* Logging changes to user access
* Notifying administrators of whitelist updates
* Triggering onboarding or offboarding workflows based on invite status changes

When this trigger kicks off, it provides the following data in `triggering_user_invite_data`:

| Field           | Type     | Description                                  |
| --------------- | -------- | -------------------------------------------- |
| `id`            | string   | The unique identifier of the user invite     |
| `email`         | string   | The email address of the invited user        |
| `org_id`        | string   | The organization ID the invite belongs to    |
| `role_ids`      | array    | List of role IDs assigned to the user        |
| `created_at`    | datetime | When the invite was created                  |
| `updated_at`    | datetime | When the invite was last updated             |
| `accepted_at`   | datetime | When the invite was accepted (if applicable) |
| `is_accepted`   | boolean  | Whether the invite has been accepted         |
| `created_by_id` | string   | The ID of the user who created the invite    |

</details>

## Other triggers

Rewst offers additional triggers for some of our integrations tailored to different automation needs. Explore the available triggers in the trigger type list to find the best fit for your specific processes. Try asking [RoboRewsty](/documentation/roborewsty) what each integration-specific trigger does to learn more about how it can be used, or read more about included triggers on each integration's info page in this site.

<figure><img src="/files/pgZ0vIIXA6gJca0L3P2m" alt="A moving GIF image depicting scrolling through the trigger type list in an example organization in Rewst. Various integrations&#x27; actions are shown."><figcaption><p>The contents of the complete trigger type list will depend on your particular integrations</p></figcaption></figure>


# Trigger criteria

*Trigger criteria* are a set of conditions that determine whether a workflow should start. A condition can be a simple comparison of two values, a complex set of conditions, or even a Jinja-based query. In simple terms, you're setting up the automation to only trigger when certain conditions are met or values are present. This can be helpful to customize when you want a workflow to run. For example, rather than having it run for all incoming tickets, you would use trigger criteria to set a workflow to run for just tickets related to password reset requests.

The trigger criteria tab of the trigger menu will only appear if you've chosen a trigger type that works with criteria. This includes [core webhook](/documentation/automations/intro-to-triggers#core-webhook) triggers and any integration-type triggers.

<figure><img src="/files/wtaloTOlcMRHHPkioJXD" alt="An animated image of the user choosing a trigger typed ConnectWise PSA. As the user clicks, a new section of the menu appears titled &#x27;Trigger Criteria.&#x27; The test is white on a dark blue screen."><figcaption><p>Scroll down to the bottom of the trigger menu once you've chosen your trigger type to see the trigger criteria submenu.</p></figcaption></figure>

## Trigger criteria submenu

<figure><img src="/files/CsXCcFzvhFQyruaT6BXl" alt=""><figcaption></figcaption></figure>

1. Click **+Add Criterion** to add new trigger criteria. This will reveal a new set of fields. You can only add one set at a time, but may add multiple criterion.
2. Click **Test Criteria** at the bottom of the right side menu to open the trigger criteria test dialog. This option will only appear after you've saved both your trigger and your trigger criteria. The dialog allows you to use past events in your relevant tool to test out conditions for future events. From this dialog, you can also add new trigger criteria. Note that the trigger must be set to **enabled** for this dialog to work. Learn more about this dialog in the [Trigger criteria test dialog](#trigger-criteria-test-dialog) section of this document.
3. The **Key** field is used to access the trigger context. A trigger context is a dictionary of key-value pairs that contain the data of the event that triggered the workflow.
4. Click <img src="/files/yRhzrk2xPyH045czZ3PH" alt="" data-size="line"> to open a Monaco editor dialog.
5. The **Operator** drop-down is used to compare the value of the Key field with the **Value** field. Click the arrow to open the drop-down list of all possible operators.
   1. Equals
   2. Equals (case sensitive)
   3. Not Equals
   4. Contains
   5. Starts With
   6. Ends With
   7. Greater Than
   8. Less Than
   9. Exists
   10. Does Not Exist
   11. In - be sure to press the `Enter` key to convert the value into a list
   12. Not In - be sure to press the `Enter` key to convert the value into a list
   13. Jinja Evaluation
6. The **Value** field contains the text parameter of the **Key** field to compare with the value of the trigger context. Note that only string values are supported in this field. If you need to evaluate non-string values, you can use Jinja Evaluation to do so.
7. Click **Delete Condition** to remove the related trigger criteria.

<figure><img src="/files/weJTX8Dv83PV5SGAHmhZ" alt=""><figcaption></figcaption></figure>

## Trigger criteria test dialog

The dialog can be viewed in the right side menu in condensed form, or via a full dialog that appears in the center of your screen by clicking <img src="/files/UMBAisxwIISgGIV2JVfK" alt="" data-size="line">.

<figure><img src="/files/eYQTbgK4aEtEh6w8Mm70" alt="" width="239"><figcaption><p>The condensed view</p></figcaption></figure>

The full dialog is made up of two panels. The right panel shows all prior triggering events in a list, with the most recent events displayed at the top. You must enable the trigger to receive trigger events, and also slide the **Test Trigger Criteria** toggle to play, not pause. The system will approximately log the latest 10 events for one day. There is no throttling on the logging system.

<figure><img src="/files/Ab7Y3KKhQNRafwdqbQJo" alt=""><figcaption><p>The full dialog</p></figcaption></figure>

Click on the value of the trigger context for any of these events to generate and display its criteria in the left panel. This will automatically map the field accessor and the selected value of the trigger context. Note that the events in the right panel list have color coded headers at the top of each, with the color denoting a different status for that event. Each trigger type may have different trigger context data or formatting.

| Status                                            | Meaning                                                                                                                                                                                                                                                                                                                                                   |
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| VALID - Blue![](/files/zBgaSmwq0MF9j784yDbI)      | A valid trigger criteria means the triggered event satisfies all possible conditions and will start the workflow. A criteria is satisfied when all specified conditions are satisfied by logical means against the trigger context. All valid trigger events should have a corresponding workflow execution.                                              |
| FILTERED - Yellow![](/files/BWOHlTMAxkrNJKNFSMkC) | A filtered trigger will not start the workflow, typically for one of the following reasons: a condition is logically unmet by design, a condition is malformed and unparseable, or the trigger request itself is malformed and rejected by the system. A filtered trigger event may show warnings if errors are found while processing the trigger event. |

{% hint style="warning" %}
If no criteria are set, anything will be considered a valid triggering event.
{% endhint %}

Alternatively, click **+ Add Criteria** to create a new set of fields for a new criteria.

{% hint style="success" %}
You can’t set more than one condition on the same field. Rewst will adopt the first condition and destroy any future conditions without giving a warning message.

Though you can only have one condition on specific field at a time, you can have as many conditions as you wish, as long as they are each on a different field.
{% endhint %}

## Trigger context examples

<details>

<summary>Basic example: Apple, orange, banana</summary>

In plain speak, we want to set the criteria to be that a fruit is an apple, where all possible fruits are apple, orange and banana. The price of the apple is $1.99. The colors corresponding to each type of the fruits are red, orange, and yellow respectively.

Now let's look at it in Rewst. Given the following trigger context:

```javascript
{
    fruit: "apple",
    fruits: ["APPLE", "orange", "banana"],
    price: 1.99,
    types: {
        colors: ["red", "orange", "yellow"],
    }
}
```

The following trigger criteria will be valid, and match our statement:

<figure><img src="/files/0jQJEI5kuOpIiDNaObMM" alt=""><figcaption></figcaption></figure>

* For this example, note that while you could have each of the types of fruits with an operator of Equals and the value set to the entire text name of each fruit, using the alternative operators such as contains, Starts With and Ends With allow you to pull in more results for your criteria. If you only know that the domain you want to act as a trigger ends in co.uk, you could use an operator other than Equals, to pull in results that contain those few letters rather than requiring it to match an entire address' exact text.
* The field accessor uses dot notation to access the value in the trigger context: apple = fruits,0, orange = fruits.1, banana = fruits.2, etc.
* If you are making use of the In or Not In operator, be sure to press the **Enter** key to convert the value into a list.
* You can't have identical field accessors in the same trigger criteria, with the exception of Jinja criteria.
* We make use of simple Python operators to compare the values of the trigger context and the field value. For more information, please refer to the [Python Operators](https://www.w3schools.com/python/python_operators.asp)
* Default conditions are And conditions. If you want to use Or conditions, you can use the Jinja criteria. Please see the advanced examples below.

</details>

<details>

<summary>Advanced example: Jinja evaluation</summary>

Given the following trigger context:

```javascript
{
    fruit: "apple",
    fruits: ["APPLE", "orange", "banana"],
    price: 1.99,
    types: {
        colors: ["red", "orange", "yellow"],
    }
}
```

The following Jinja evaluation will be valid:

```jinja2
{{ CTX.fruit == 'apple' or CTX.price < 2 }}
```

Jinja evaulations do not require a field accessor, and the entire trigger context is available under the CTX variable.

</details>

## Save trigger criteria

You'll need to save your updates for the trigger criteria to take effect. How you do this will depend on if you are adding criteria directly under the **Trigger Criteria** submenu or within the Trigger Criteria Test dialog.

Click **Save Trigger** under the Trigger Criteria submenu to save your added or updated trigger criteria.<br>

<figure><img src="/files/OEAaLb9b2vMuJ58y7aW1" alt=""><figcaption></figcaption></figure>

Click **Save Trigger Criteria** in the Trigger Criteria Test dialog to save and close the dialog.

{% hint style="success" %}
While the Trigger Criteria Test dialog is open, you can press the **`F8`** key to save the trigger.
{% endhint %}


# Trigger use cases and examples

{% content-ref url="/pages/5Ii4gMurr7uwZWcWzCUN" %}
[Customize PSA ticket triggers](/documentation/automations/intro-to-triggers/use-cases-and-examples/customizing-psa-ticket-triggers)
{% endcontent-ref %}

{% content-ref url="/pages/FVzl5mmXgVzAHfdwKEb0" %}
[Use webhook triggers](/documentation/automations/intro-to-triggers/use-cases-and-examples/using-webhook-triggers)
{% endcontent-ref %}

{% content-ref url="/pages/ic8ny1cJnkRdK2pv82da" %}
[Configure a webhook trigger for CORS requests](/documentation/automations/intro-to-triggers/use-cases-and-examples/configure-a-webhook-trigger-for-cors-requests)
{% endcontent-ref %}


# Customize PSA ticket triggers

In Rewst, setting specific trigger criteria for PSA Ticket triggers can be crucial to ensuring that workflows are initiated only under certain conditions. This page provides a step-by-step approach to customizing these triggers.

## Get started with trigger setup

### Create the workflow

In the Rewst platform:

1. Navigate to **Automations > Workflows > Create Workflow**.
2. Enter a workflow name, like `My First Webhook Trigger`.
3. Click **Submit** to proceed to a blank Workflow Builder Canvas.
4. Add a single [no-op](/documentation/automations/actions-in-rewst/core-actions#no-operation-noop) action to the canvas. Name it `BEGIN`
5. Click **Deploy** to save your workflow. No other actions are needed, as you'll just be working with triggers.
6. Click <img src="/files/17lCeuoq6HByl9lrLING" alt="" data-size="line"> **> Flow Control**.
7. Drag the yellow **Triggers** to the Canvas. This opens up the new trigger's **Trigger Settings** in the right side menu.

### **Create the trigger**

1. Name your trigger.
2. Toggle **Enabled** on.
3. Use the **Trigger Type** drop-down selector to choose the trigger type relevant to your particular PSA ticket system:
   1. ConnectWise PSA: **Ticket Record Saved**.
   2. Datto PSA: **Ticket Webhook**
      1. Note: Ensure that webhooks are enabled as per [Rewst Documentation](https://docs.rewst.help/documentation/integrations/psa/autotask-datto-psa/webhook-configuration).
   3. Halo PS&#x41;**:** **New Ticket Record**.
4. Click the **Criteria** tab.
5. Click **+ Add Criterion**. Add your[ trigger criteria](/documentation/automations/intro-to-triggers/trigger-criteria).

<div align="left"><figure><img src="/files/OhrKjF0cZ6OK6BU0uFIQ" alt=""><figcaption></figcaption></figure></div>

The trigger is now active and will capture data when a new ticket is submitted. This screen is listening for your ticket records to be saved, and will show you live results as they come in.

<figure><img src="/files/S81h9TT6Z1g6EbYqyZwz" alt=""><figcaption></figcaption></figure>

## Test the trigger with a PSA ticket

To see the trigger in action follow the below steps

### **Create a test ticket**

* In your PSA system, create and classify a new ticket with desired criteria.
* Submit the ticket.
* You should see the ticket record appear in Rewst.

{% hint style="info" %}
Once the ticket is visible in Rewst, click the pause button to stop more tickets from coming in while you're building your trigger criteria.
{% endhint %}

### **Select criteria**

Find and click the values in the ticket you want as trigger criteria. They will have their corresponding path entered into the Trigger Criteria on the right.

<figure><img src="/files/7ral5KK5rokN9H2Hm65b" alt=""><figcaption></figcaption></figure>

## Finalize and implement trigger criteria

### **Save your criteria**

* After selecting all desired criteria, click `Save` then `Close`.
* Your trigger criteria are now set and visible.

### **Apply criteria to workflows**

* Copy these criteria values.
* Paste them into other workflows you are configuring.

<div><figure><img src="/files/HZuaAj5cmhWUeXInInGZ" alt=""><figcaption></figcaption></figure> <figure><img src="/files/CsXCcFzvhFQyruaT6BXl" alt=""><figcaption></figcaption></figure></div>


# Use webhook triggers

## What is a webhook trigger?

*Webhook triggers* are an effective way to kick off a workflow with context from external systems. By sending an API request to a webhook trigger, Rewst will fire the workflow and include any data and or queries included in the request. For example, when a customer submits a support ticket, a webhook instantly sends that information to Rewst and starts a workflow.<br>

{% hint style="warning" %}
When using webhook triggers, design your workflow with our [rate limiting policy](/security/webhook-trigger-rate-limits) in mind.
{% endhint %}

### **Webhook trigger process**

Webhooks follow a simple process:

1. An event happens, such as when a new ticket is submitted.
2. The webhook sends a message with data to a URL.
3. A workflow is triggered based on that message.

### **Webhook URLs**

A *webhook URL* is a unique address where data is received for that particular webhook. It continuously listens for data, and kicks off the related workflow the moment data is received. Once that data is captured, we call it a *payload*, and it becomes usable inside the workflow. This allows you to do things like:

* Assign tasks based on field values
* Push updates to other systems
* Send messages or alerts
* Store or log information for reporting

Webhook URLs are formatted consistently using the trigger ID and organization ID. The format is as follows: `https://engine.rewst.io/webhooks/custom/trigger/{{ Trigger ID }}/{{ Organization ID }}`

## Create the workflow

In the Rewst platform:

1. Navigate to **Automations > Workflows**.
2. Click **Create Workflow**.
3. Enter a workflow name, like `My First Webhook Trigger`.
4. Click **Submit** to proceed to a blank Workflow Builder Canvas
5. Add a single [no-op](/documentation/automations/actions-in-rewst/core-actions#no-operation-noop) action to the canvas. Name it `BEGIN`
6. Click **Deploy** to save your workflow. No other actions are needed, as you'll just be working with triggers.
7. Click <img src="/files/17lCeuoq6HByl9lrLING" alt="" data-size="line"> **> Flow Control**.
8. Drag the yellow **Triggers** to the Canvas. This opens up the new trigger's **Trigger Settings** in the right side menu.

<figure><img src="/files/p0uqjmNn3dSdNqoZJyqq" alt=""><figcaption></figcaption></figure>

## **Create the webhook trigger**

1. Name your trigger.
2. Toggle **Enabled** on.
3. Choose the trigger type **Core - Webhook**. This will reveal a new **Parameters** section in the right side menu.\
   \
   ![](/files/CbePLmKExpmwVthonfNR)

## **Set trigger parameters**

*Parameters* are like fill-in-the-blank options that make workflows adaptable. Webhooks deliver data to workflows, and parameters use that data to customize actions. For example, instead of hardcoding a date, you could use a parameter called `ReminderDate` to customize it each time the workflow runs.

The following parameters are available for editing in workflow trigger configuration:

* **Allowed methods**
  * Used to define which HTTP request method is accepted by the trigger. Attempting to send a request with a method not in this list will result in an error.
* **Include raw body**
  * Whether to include the raw string sent in the request body in the results as `raw_body` .
* **Response body**
  * Content to return in response body. `{{ REQUEST }}` may be used to access request data.
* **Response headers**
  * HTTP headers to include in response. `{{ REQUEST }}` may be used to access request data.
  * **TIP:** Set your content type here if returning a specific format of data, such as `text\html` .
* **Response status**
  * HTTP status to return in response. `{{ REQUEST }}` may be used to access request data.
* **Secret key**
  * Recommended to be used with Wait For Results. This value must be included in the header as x-rewst-secret when making calls to this webhook. You will receive a 401 if this field is filled out and the secret key is not provided when making the request. Secrets can be defined in the Organization Variables section of the UI.
* **Wait for results**

  * If true, this calls to the trigger endpoint will redirect to a results endpoint that will return the output of the workflow.<br>

  <figure><img src="/files/gwXqpH9BBv6RZFwaFVYu" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
When finished updating your parameters, remember to click **Save Trigger**.
{% endhint %}

## **Access data in a webhook trigger request**

When a webhook receives a request, it will include data received in the following schema:

```json
{
    body:{},
    headers:{},
    method:"",
    params:{},
    timestamp:""
}
```

Data can then be pulled from this as context variables. For example, to access the value for `test` sent to the webhook as:

```json
{
    "test": "Hello, World!"
}
```

The value can be accessed at `{{ CTX.body.test }}`.

Similarly, if a URL parameter is sent as `?test=Hello`, this can be accessed at `{{ CTX.params.test }}`

#### Webhook payload example

Below is a real webhook payload that was received in a Rewst workflow. You can view payloads in the [workflow results](/documentation/automations/workflows/troubleshoot-workflow-executions-and-task-results#workflow-executions-for-troubleshooting) for that particular workflow.

```
{
  "ticket_id": 67890,
  "customer": "Jamie Smith",
  "priority": "high",
  "issue": "Password reset not working"
}
```

* The customer is named Jamie Smith.
* The priority level of high indicates the urgency of the ticket.
* The next logical step in a workflow might be to assign the ticket for resolution, since the issue is a password reset problem that must be solved by human intervention.

## Trigger criteria and webhook triggers

Once you connect an external tool to Rewst with a webhook, you may run into a problem: too many workflows firing at once. Every webhook that hits your Rewst URL will start the workflow, even if the event isn’t important. That can quickly eat up task cost and make it harder to focus on what matters. [Trigger criteria](/documentation/automations/intro-to-triggers/trigger-criteria) solve this by acting as filters. They check the webhook data against conditions you set, and only start the workflow if those conditions are met. You can add as many conditions as you need, across any attributes available in the webhook data.


# Configure a webhook trigger for CORS requests

{% hint style="info" %}
Though this is related to triggers, it's most often used in conjunction with App Builder. Learn more about Rewst's App Builder in our documentation [here](/documentation/app-builder).
{% endhint %}

## What is a CORS request?

When referencing a Rewst web hook in JavaScript in an App Builder page— or outside of Rewst— you may see the error `TypeError: Failed to fetch.` This happens when the browser blocks your request because it does not allow *cross-origin* requests by default.

To make your webhook accessible from a web page, you must configure *CORS (Cross-Origin Resource Sharing)* headers and enable OPTIONS requests on your webhook.

{% hint style="info" %}
Note that **wait for webhook** cannot be set to `true` for this to work. Additionally, this webhook shouldn't use a secret key.
{% endhint %}

## Add CORS headers to your web hook response

1. Open your webhook trigger inside the workflow.
2. Click ![](/files/yRhzrk2xPyH045czZ3PH) to open the response headers code editor.
3. Add the following headers:

```django
{
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "https://YOURDOMAINHERE",
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type"
}
```

<figure><img src="/files/y5tCjsgzYe801aY3QSPk" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
**Important -** Match the *exact* origin of your site.

> ✅ <https://bclimer-cors-test.rew.st>

> ❌ <https://bclimer-cors-test.rew.st/>

Avoid using \* unless the webhook is fully public and returns no sensitive data.
{% endhint %}

## Reference table

| Header                       | Description                              | Example                            |
| ---------------------------- | ---------------------------------------- | ---------------------------------- |
| Access-Control-Allow-Origin  | Defines which site may call your webhook | <https://your-frontend-domain.com> |
| Access-Control-Allow-Methods | Lists allowed HTTP verbs                 | GET, POST, OPTIONS                 |
| Access-Control-Allow-Headers | Lists allowed custom headers             | Content-Type                       |
| OPTIONS                      | Preflight permission check               | Must return 200 with headers       |

## Handle OPTIONS preflight requests

Browsers send an *OPTIONS* request before certain POST or PUT requests to confirm that CORS is allowed. Your webhook must allow OPTIONS requests for this to succeed.

Add OPTIONS under the **Allowed Methods** field of your **Trigger Parameters** menu in workflow setting&#x73;**.**

<figure><img src="/files/a9KBjXHCBBAljgDoowXR" alt=""><figcaption></figcaption></figure>

## Troubleshoot the CORS webhook trigger

#### Trailing slash in origin

Try removing the slash from the end of your domain.

#### Missing OPTIONS handler

Add the OPTIONS method to the webhook.


# Forms

## What is a form?

In Rewst, every automation starts with a single click. *Forms* are powerful tools used to collect the information your workflows need to start. They streamline the data collection process by gathering key details from users such as names, dates, or options. Forms can be manually created, or added as part of [Crate unpacking](https://docs.rewst.help/prebuilt-automations/crates#unpack-a-crate).

Rewst's form functionality is designed to empower users with the tools to build interactive, responsive, and customizable forms.

## Why use forms?

Forms collect data in one simple step, reducing manual data entry and saving you time. They can also function as triggers in Rewst when building workflows, allowing for seamless transitions and increased efficiency. Use a form submission in your workflow if user input is required for the automation to run. You wouldn't use a form, for example, if the all the information needed for the automation to run could be retrieved via webhook trigger.

Expand the reach of your forms by embedding them into various web pages, providing increased accessibility to users. Tailor forms to specific scenarios through cloning and modification, ensuring the right fit for every situation.

## View forms in Rewst

Access all forms, be they manually created by you or obtained as part of unpacking Crates, by navigating to **Automations > Assets > Forms** in the left side menu.

<figure><img src="/files/jRv6vyl7HWocL8xewlO8" alt=""><figcaption><p>An example of what your forms page might look like</p></figcaption></figure>

### Export and import forms

You can export a form to share with other Rewst customers, or create your own hard copies of form backups. To export a form as a JSON bundle, **click ⋮ > Export** next to your relevant form in the total form list.

To import a form bundled as a JSON file, click ![](/files/pSRxSYvjj8rtjxgRxLTC) in the top right navigation bar of the forms page. Then, drag and drop your file into the upload dialog that appears.

## Request a forms feature update

We’re constantly adding new features to Rewst. If you have a suggestion for what we could add to our forms functionality, add a request or upvote other existing suggestion posts [in our Canny.](https://rewst.canny.io/integrations)

{% hint style="success" %}
Want to learn more? Search for the **How to build forms** course in Cluck University.
{% endhint %}


# Build a form with Rewst's Form Builder

Learn how to build and customize your Rewst Forms

## Create a new form

The part of Rewst you use to create and edit forms is called the *Form Builder*. To access it, navigate to **Automations > Assets > Forms**, and click ![](/files/BUQkmPYXmm8ZhrULwib4).

<figure><img src="/files/bTQuFiKshHRF3wzdXhJv" alt="" width="375"><figcaption></figcaption></figure>

In the **Create New Form** dialog, give your form a descriptive name. Remember, as you build more in Rewst, your list of forms will grow significantly. Following proper naming conventions will save you time in finding your right form later on.

<figure><img src="/files/t391VVxCmM7IM0VHsQqO" alt=""><figcaption></figcaption></figure>

The Form Builder is similar to Rewst's Workflow Builder in that it has a list of options on the left, called *form fields*, which can be dragged and dropped onto the canvas in the center of your screen.

Each of these options will relate to your *inputs***,** or the information that goes into the form. With the exception of the **Text/Markdown** field which is only used for presenting data to the end user, all other fields are used as data input and contain a field name, field label and field description. The field name is the variable name used within the workflow once the form has been submitted. The field label and field description are used to format the appearance of the form.

Using the correct fields ensures your workflows receive clean, organized data.

### Form field options

{% hint style="info" %}
Click on any of the below form field options to expand and see its information.
{% endhint %}

<details>

<summary>Text/Markdown</summary>

The **Text/Markdown** field lets you present text, optionally formatted with Markdown. You can also render Jinja in these fields, which can be useful for presenting organization variables, or rendering a Markdown table with data from elsewhere in the form.\
\ <img src="/files/ysYQd7uV0YdMTcoIG8Vx" alt="" data-size="original">

</details>

<details>

<summary>Drop-down</summary>

**Drop-down** fields let you select from multiple options, which can either be hard coded into the form or dynamically generated. Each option on the form has a *label* and a *value*, and default options can be preselected if specified. There are also options for:

* **Auto-Populate**: if enabled, will always pre-populate the field if only a single option has been returned.
* **Allow Custom Input**: lets the enduser write in the field and have that be the value passed into the workflow.
* **Always Skip Cache**: causes the option generator to always run instead of pulling from a cache. Note that the cache for a form field invalidates every 8 hours. Typically the first run of the day will be slower than the rest.
* **Always Override Option**: used when the auto-populate setting is enabled, this will cause the field to repopulate itself. This is needed in cases where the field is populated via an option generator and another field is being used as input for the option generator. In that case, you would need the option generator to run again, as the output would likely be different.

These are used most commonly when the list of options is being generated via an options generator *.*\
Drop-down selection is limited to a single option. For multiple options for selection, see the multi-select form field option.\
\ <img src="/files/xSRNfLxTLjm7sZQ0rHfk" alt="" data-size="original">

</details>

<details>

<summary>Multi-Select</summary>

**Multi-select** is similar to the dropdown field, but lets you select as many options as you like, up to a maximum number of options which can be specified on the field.\
\
![](/files/eM5kk8L3Xj68bv3Jy1QR)

Here are two examples, one for returning a specific item within the list, and one for checking if values are provided:

```
{{ CTX.<field_name>[0].value|d }}
```

```
{{ CTX.<field_name>|length > 0 }}
```

</details>

<details>

<summary>Checkbox</summary>

The **Checkbox** field provides a toggle with a true/false value for the form. You can also change the label positioning.\
\
![](/files/gKyANwaWQofoJZMwfp1h)

</details>

<details>

<summary>Radio Buttons</summary>

The **Radio Buttons** field offers a selectable single option. It can also be dynamically populated in the same way as a dropdown or multi-select field, but doesn't allow for the additional options of auto-populate, allow custom input, always skip cache and always override option. For this reason, radio buttons are rarely used with dynamic options.\
\
![](/files/QHqaANPJ2XuJUWXeLU3H)

</details>

<details>

<summary>Text Input</summary>

The **Text Input** field accepts a single line text string. You can also perform regex validation and error reporting, or populate the field with a default value.\
\
![](/files/WNUqSWsktTg2SunCUTKm)

</details>

<details>

<summary>Number Input</summary>

The **Number Input** field accepts numbers, as long as they meet the Python definition of numbers: whole numbers or floats. Set a default value, as well as minimum and maximum values.\
\
![](/files/WNUqSWsktTg2SunCUTKm)

</details>

<details>

<summary>Multi-Line Input</summary>

The **Multi-Line Input** field accepts large amounts of text. No validation is available for this field.\
\
![](/files/zu14Ges4bNM2Uc3txtqo)

</details>

<details>

<summary>Date</summary>

The **Date** field can be set up to accept dates, or times and date times together.

Note that the time zone or this field is based on your browser locale. Rewst converts the time into UTC when passed into the workflow without the time zone data. As an example, if you're in EST and you select 6pm, the workflow will receive this as 1pm UTC, due to the 5 hour offset. Adjust your submission for this time difference when you are submitting a form for a customer in a different time zone from yourself, and need to specify a time.\
\
\
![](/files/tLiwUFsdWG8AaIhDtYF7)

</details>

<details>

<summary>File Upload</summary>

The **File Upload** field allows for the uploading of specific file types:

.CSV\
.JSON\
\
If you are working with an XL or XLSX file format, [convert it to CSV ](https://support.microsoft.com/en-us/office/import-or-export-text-txt-or-csv-files-5250ac4c-663c-47ce-937b-339e391393ba)before uploading.\
\
![](/files/y50FptFDbOd2DqIuwDLn)

</details>

## Dynamic options in forms

*Dynamic options* automatically fetch data from integrations, thereby eliminating the need for manual data entry and keeping form options up-to-date with the latest data. For example, if you're managing hiring information within your PSA, dynamic options can automatically pull this data into the form, ensuring that users always have the most current information.

There are two types of dynamic options: integration reference and workflow generated.

### Option one: Integration reference

A *reference option* is a dynamic field pulled directly from predefined actions. It works well for straightforward data retrieval, but may require conversion to a workflow-generated option for data manipulation, as this doesn't give any filtering options and will pull directly from the API endpoint.

#### Integration reference example

Selecting the Microsoft Graph integration to list all users.

<div align="left"><figure><img src="/files/JMGrYQaQZ6NIAEfAanIs" alt=""><figcaption></figcaption></figure></div>

{% hint style="info" %}
Pulling data straight from the integration like this only works at the top, parent level organization where the integrations are installed. This option won't work for dynamically pulling child organization data. To achieve this, you would require an options generator.
{% endhint %}

### Option two: Workflow generated options

If you want more flexibility around the output of the data your user is seeing, you may need to opt for a workflow generated option instead, which allows for in-depth data manipulation using [Jinja](/documentation/jinja). We cover what these are and how to use them in Cluck U’s [Rewst Foundations](https://learn.rewst.io) and [micro course](https://learn.rewst.io). If you’ve already taken our courses and want a refresher, see our documentation on option generators [here](https://docs.rewst.help/documentation/workflows/workflow-generated-options) and [here](https://docs.rewst.help/documentation/workflows/different-types-of-workflows#option-generator).

Alternatively, dynamic forms use cases can be handled with our options filter feature. The options filter makes customizing drop-down fields within forms straightforward for those who want to add filtering without updating an options generator workflow. It takes inputs, filters them, and produces an output agnostic of the data source. See our separate [options filter documentation here](/documentation/automations/forms/options-filter-filtering-in-forms).

{% hint style="info" %}
This setup requires the workflow type be an option generator. See our [option generator workflow page](/documentation/automations/workflows/option-generator-workflows) for more details on this functionality. The below documentation is high-level only.
{% endhint %}

#### Options generator example

In this image, what is shown to the user is what is set as the label for the list contents. Ultimately, it can be whatever you want it to be, using Jinja to manipulate that output correctly. The ID is the value or unique ID of what the workflow is referencing for its future actions.

<div align="left"><figure><img src="/files/Zqadme1m1NISW7ErRJs4" alt="" width="444"><figcaption></figcaption></figure></div>

#### **Set default options**

Default options can be selected for a form field linked to a workflow by following these steps.

1. Add a boolean property to each option result.
2. Define the boolean property for the **Default Selected Field** value.

Sample data returned by a workflow:

{% code lineNumbers="true" fullWidth="false" %}

```json
[
    {"label": "Adam", "id": "1", "current_default": false},
    {"label": "Matt", "id": "2", "current_default": false},
    {"label": "Jareth", "id": "3", "current_default": true}
]
```

{% endcode %}

Fields to be filled out in the form:

* **Value Field**: `id`
* **Label Field**: `label`
* **Default Selected Field**: `current_default`

### Dynamic form links

A *dynamic form link* is a special type of URL that automatically directs users to the form specific to the organization they belong to in Rewst. Rather than using a static form link that always goes to the same location, a dynamic form link adapts depending on who is accessing it.

<figure><img src="/files/XYWSVC7UmFAe8PAzgflY" alt=""><figcaption></figcaption></figure>

When sharing a form, instead of clicking **View Direct URLs**, you can click **Copy URL**.\
This generates a dynamic link that looks like this:

```
https://app.rewst.io/form/<form_trigger_guid>
```

When a user opens this link:

1. The system checks who is logging in.
2. It validates which organization the user belongs to.
3. The user is then automatically redirected to the correct form URL for their organization.

This ensures that users always land on the right form instance without needing to know or select their organization manually. Use a dynamic form link whenever you have a form that multiple organizations or users need to access, or when you want to provide a single, easy-to-share URL rather than multiple specific links.

### Dates in forms

{% hint style="info" %}
Form date formats — DD/MM/YYYY) versus MM/DD/YYYY— are influenced by browser locale settings, not controlled by the application itself. IT admins could deploy the desired locale to all of their customers if they want to ensure consistent appearance. Setting it once in the browser will set it for all forms.
{% endhint %}

#### Set your browser's locale

Your browser’s locale controls:

* How dates and times appear
* The language used in websites and spellcheck
* The region format for numbers and currency

Follow the steps below for your relevant browser to use only the region you need, and remove the others for consistent behavior.

<details>

<summary>Mozilla Firefox</summary>

**Open Language Preferences**

1. Navigate to **Settings > General > Language**.
2. Under **Language and Appearance**, click **Choose…** next to **Language for displaying pages**.
3. Add only your desired language region:
   * English (Australia)
   * English (United States)
   * English (United Kingdom)

**Remove Others**

* Highlight any extra languages and click **Remove** so only one remains.

**Confirm Locale**

(Optional advanced step)

1. In the address bar, type `about:config`.
2. Search for: `intl.locale.requested`
3. Set it to:
   * `en-AU` for Australia
   * `en-US` for United States
   * `en-GB` for United Kingdom
4. Restart Firefox.

</details>

<details>

<summary>Google Chrome</summary>

**Open language settings**

1. In the address bar, go to:

   ```
   chrome://settings/languages
   ```
2. Under **Languages**, click **Add languages**.
3. Search for and add **only one** of the following, depending on your region:
   * **English (Australia)** → `en-AU`
   * **English (United States)** → `en-US`
   * **English (United Kingdom)** → `en-GB`

**Remove unused languages**

* Click the **⋯** next to any other languages and select **Remove**.\
  This prevents Chrome from using fallback locales.

**Set as display language**

* Click the **⋯** next to your chosen language.
* Select **Display Google Chrome in this language**.
* Restart Chrome to apply the change.

**Check your date/time format**

* Open your system settings to make sure the region matches your browser locale:
  * **Windows:** `Settings > Time & language > Language & region`
  * **macOS:** `System Settings > General > Language & Region`

</details>

<details>

<summary>Microsoft Edge</summary>

**Open Language Settings**

1. Navigate to:

   ```
   edge://settings/languages
   ```
2. Click **Add languages** and add only one:
   * English (Australia)
   * English (United States)
   * English (United Kingdom)

**Remove Extra Languages**

* Click the **⋯** beside any other languages and choose **Remove**.

**3. Set Display Language**

* Click the **⋯** next to your chosen language.
* Select **Display Microsoft Edge in this language** and restart Edge.

**4. Match Your System Region**

* Go to `Settings > Time & language > Language & region > Regional format`
* Choose the same region: Australia, United States, or United Kingdom.

<br>

</details>

Then, confirm your browser's locale:

1. Open the browser console by pressing `F12`, then navigating to **Console.**
2. Run:

   ```
   console.log(navigator.language);
   console.log(new Date().toLocaleString());
   ```
3. Expected outputs are as follows.

| Region         | navigator.language | Date rxample            | Format                    |
| -------------- | ------------------ | ----------------------- | ------------------------- |
| Australia      | `"en-AU"`          | `09/10/2025, 13:30:00`  | DD/MM/YYYY                |
| United States  | `"en-US"`          | `10/9/2025, 1:30:00 PM` | MM/DD/YYYY                |
| United Kingdom | `"en-GB"`          | `09/10/2025, 13:30:00`  | DD/MM/YYYY, 24-hour clock |

<br>

### Workflow inputs

*Workflow inputs* in Rewst offer a flexible way to define specific inputs to a workflow via a form. This functionality allows you to handle various client cases and attributes dynamically. By understanding these concepts and utilizing the provided examples, you can create versatile and dynamic forms tailored to your specific needs.

Below are some key aspects of workflow inputs:

#### **Use org variables for client-specific workflows**

If you have a form used across multiple clients, each with distinct environments like Microsoft 365 or On-Prem, you can use an [org variable](/documentation/integrations/organization-variables) to dictate the source of the data.

For example, by employing `{{ ORG.VARIABLES.primary_identity_provider }}`, which is set per client as either `on_prem` or `azure_ad`, you can use the same form for both client cases. The form will be pulled from the relevant system.

<div align="left"><figure><img src="/files/t4OVJJAbt7yVwAUEqMss" alt=""><figcaption></figcaption></figure></div>

#### **Hard-code attributes for efficiency**

Instead of creating separate workflows for various attributes such as department, userPrincipalName, or ID, you can use a single workflow with a hard-coded element. This approach takes your input and returns the desired property.

For example, **t**he attribute `department` can be hard-coded to allow a single workflow to handle different returned properties.

Here's a Jinja code snippet for achieving this:

{% code overflow="wrap" %}

```django
{%- set attribute_collection = [] -%} 
{%- set my_attribute = CTX.attribute -%} 
{%- set my_data = CTX.data|selectattr(my_attribute) -%} 
{%- for user in my_data -%}
    {%- if user[my_attribute] or false -%}
        {%- set value=user[my_attribute] -%}         
        {%- set tmp = attribute_collection.append({my_attribute:value}) -%}     
    {%- endif -%} 
{%- endfor -%} 
{{- attribute_collection | unique(attribute=my_attribute) | sort(attribute=my_attribute)  -}}
```

{% endcode %}

## Test a form: How to get a form's URL

Recall that you can access all forms in your form list in Rewst. Understanding how to test a form can sometimes be confusing due to its intrinsic link to a workflow. To get the Form URL for testing directly from a workflow:

1. Locate the [trigger](/documentation/automations/intro-to-triggers) on the workflow.
2. Click **View URL**.
3. Select the desired organization's form from the list.
4. Click **Copy**.
5. Paste the URL into a new tab and launch.

## Restrict form drop-downs

The onboarding form includes a number of fields to be filled out when onboarding new users. The default behavior of all the drop-down fields is to pull the list of options from the API. This is because the drop-down fields have **Dynamic Options** toggled on.

<figure><img src="/files/5N6hrZ3x37JGmRaG1qgg" alt=""><figcaption></figcaption></figure>

While this may work in many cases, there are scenarios where it makes sense to limit the number of options based on the customer segment you're working with. An example of this might be that you need to limit which email domains each customer sees. You may also want to limit which locations customers can choose from. In any case, you can set specific values for the `default_form` organization variables to use in your forms.

{% hint style="info" %}
The example below is specifically for the User Onboarding Form and workflow, as it is currently the most likely use case.
{% endhint %}

## Add an organization variable to a form

You can add default values for any of the form organization variables below:

{% hint style="info" %}
To view the form org variables table, [click here](/documentation/automations/forms/form-organizational-variables).
{% endhint %}

## Limit the email domains in the user onboarding form

#### Add the organization variable to an organization

1. Navigate to **Settings > Organization Variables**.
2. Click **Add** at the top right.
3. Enter in the following for the new organization variable:
   * **Name**: `form_default_email_domain`
   * **Value**: `["email domain"]`
   * **Category**: General
   * **Organization**: Choose Your Organization

<figure><img src="/files/ZMCgfQLCb0WtUvFsOUg0" alt=""><figcaption></figcaption></figure>

{% hint style="danger" %}
Any value you add to a variable must exist in the list that the form value is pulling from. An example of this would be that any email domain added as a default must exist in the list that is pulled from the Microsoft API.
{% endhint %}

Next, the variable can be added to the form field.


# Options filter: Filtering in forms

## What is options filter?

The *options filter* makes customizing fields within forms straightforward for those who want to add filtering without updating an options generator workflow. It takes inputs, filters them, and produces an output agnostic of the data source.

Options filter works for the following form field types:

* [Dropdown](https://docs.rewst.help/documentation/automations/forms/intro-to-forms#drop-down)
* [Radio Button](https://docs.rewst.help/documentation/automations/forms/intro-to-forms#radio-buttons)
* [Multi-Select](https://docs.rewst.help/documentation/automations/forms/intro-to-forms#multi-select)

Option generators are still a fantastic option for those who need a more powerful, in-depth, solution. We cover what these are and how to use them in Cluck University's [Rewst Foundations](https://learn.rewst.io/creating-an-option-generator) . If you’ve already taken our courses and want a refresher, see our documentation on option generators [here](https://docs.rewst.help/documentation/workflows/workflow-generated-options).

## Options filter guidance

* Modifying a form using the options filter will work for both parent and child organizations, as long as data formatting is set up the same way for both organizations.
* Add as many conditions as desired.
* Access the options filter feature in our standard form builder.
* Options filter works in the context of the current organization.

## Practical uses for options filter

* Say you offer 10 different types of licenses, but your users only ever use a single Business Premium type. Filtering down to just that license would simplify the list, and leave no room for error.
* Using a multi-select form field, present multiple licenses to a user to be filtered down to a specific set of licenses.
* Filter out admins from a total list of users, to create a cleaner list for copying into user onboarding.
* When offboarding a user, you may want to exclude a list of specific people to prevent accidental offboarding of key individuals, like the CEO.
* Hide on.microsoft email domains that are purely administrative, to provide a cleaner list.

### Detailed options filter example

You work at an MSP and are building a license request form for technicians. Your customer, XYZ Corp, only purchases Microsoft 365 Business Premium licenses, not E3, E1, or other license types. To prevent techs from accidentally selecting the wrong license type, which would lead to support tickets and billing issues, you want the drop-down in your form to only show Business Premium.

<figure><img src="/files/3H59A04Tv1xIcAlq6zad" alt=""><figcaption><p>Building the form with the different license types</p></figcaption></figure>

<figure><img src="/files/x21esZ3tp03o234djrg4" alt=""><figcaption><p>What is seen after clicking <strong>filter options</strong></p></figcaption></figure>

<figure><img src="/files/FqSab3LPWrZ1n9eHCAMF" alt=""><figcaption><p>Filtering using the <strong>simple</strong> logic option. The $.label equals Microsoft 365 Business Premium. Note that you haven't clicked <strong>apply filter</strong> on the bottom right, so there are still 4 filtered options shown under <strong>Dropdown Options</strong>.</p></figcaption></figure>

<figure><img src="/files/7WfVgAq0akbYLdWtRO3m" alt=""><figcaption><p>What you see after you click <strong>apply filter</strong>. Now, there's only 1 filtered option: Microsoft 365 Business Premium</p></figcaption></figure>

<figure><img src="/files/VjydT52R72334voPBN8u" alt=""><figcaption><p>A preview of the form, or a preview of what the end user would see. Only one option would display.</p></figcaption></figure>

## Options filter dialog

Click **Filter Options** under the **Dynamic Options** submenu of the right side forms menu. This will open the **Create Option Filters** dialog. In the dialog, you’ll see two submenus: **Dropdown Options** and **Options Filter**.

<figure><img src="/files/e2P7txhw2vicSA5pM8t3" alt=""><figcaption></figcaption></figure>

### All Options

The **All Options** drop-down selector holds all of the options which you’ve set in the standard form builder right side menu. Adding more options in that menu will populate those options into your drop-down selector.

<figure><img src="/files/AtuuEYvBTnGrWe1IBRtu" alt="" width="375"><figcaption></figcaption></figure>

<figure><img src="/files/X7ZGtOIFoGpmQvIiq0GO" alt=""><figcaption></figcaption></figure>

The **Filtered Options** drop-down selector holds a list of your selected options after applying the filter. It acts as a preview for what to expect from your filtering.

<figure><img src="/files/fZ58vSSlI0QVYjRPqJq3" alt=""><figcaption></figcaption></figure>

If your form field uses a custom options filter, there will be a badge indicator in the top right of the field.

<figure><img src="/files/wiVurA2gnLMT0qrxdnXz" alt=""><figcaption></figcaption></figure>

#### The JSON interface

Toggle from the default **Simple** view to the **JSON** view. This will switch to show the code of the filter. You may have a scenario where your desired filter is more complex than just label and value, such as ID. Using this code editor, filter out custom objects from complex queries.

<figure><img src="/files/dN9GJIXnQILRrt8wWlxD" alt=""><figcaption></figcaption></figure>

#### Jinja for options filters

If you manage many organizations, use Jinja in options filters to scale filtering logic without manually configuring filters for every suborganization. When simple boolean logic operators feel limiting, go straight to Jinja for greater customization.

{% hint style="info" %}
The CTX variable you want to reference will always be called `options`.
{% endhint %}

<figure><img src="/files/NKvrK1ikhn5OGRQFDx0W" alt=""><figcaption></figcaption></figure>

### AND and OR conditional options filtering

{% hint style="info" %}
Using the options filter for forms will require a basic understanding of Boolean. If you’re new to the topic, be sure to complete our Clean Automation course in Cluck University before trying out this feature.
{% endhint %}

The options filter works off of two boolean operators, which are used to build queries for a variety of filtering situations.

1. **AND** sets that all conditions must be true to be filtered into the returned result. E.g., Red AND white would count only items with both those characteristics.
2. **OR** sets that either of several conditions can be true to be filtered into the return result E.g., Red OR white would count items with either of those characteristics.

<figure><img src="/files/JhAf47TFdt6xBkVLsxUd" alt=""><figcaption></figcaption></figure>

Click **X** to the right of any added rule or group to delete it from your options filter list.

Click **+Rule** to add a filter field, which is customizable by a list of parameters. Choose from either **$.value** or **$.label**, then choose from the long drop-down list of conditions. E.g., **$.value equals `15`** would filter all results with a value of exactly 15.

<figure><img src="/files/YjhIF1dxNM2eQ1H0PVHd" alt=""><figcaption></figcaption></figure>

In Boolean logic, a *group* refers to a set of terms or expressions that are treated as a single unit by using parentheses, allowing you to perform Boolean operations on them together. Essentially, it defines the order of operations by grouping certain elements within a complex logical statement.

When you want to combine multiple Boolean operations in a specific way, you enclose them within parentheses to indicate that these operations should be calculated first.

By grouping terms, you can control the order in which Boolean operators like AND and OR are applied. Use the +**Group** button to define your conditions more precisely. For example:

* Without grouping, A OR B AND C would be evaluated as: A OR (B AND C) due to precedence rules
* With grouping, (A OR B) AND C forces OR to be evaluated before AND.

## Forms and options filter

### Use the options filter in a form

1. Navigate to **Automations > Assets > Forms > + Add**.
2. Name your form, and click **Submit**.
3. Drag one of the three applicable form fields onto the form builder canvas. Remember, options filter is only available for Radio Buttons, Dropdown, and Multi-Select.
4. Click on the dragged form field to open the right side menu.
5. Click on **Filter Options**. This will open the **Create Option Filters** dialog.

<figure><img src="/files/HGOA3vZ7zhzf2rsuuIO5" alt=""><figcaption></figcaption></figure>

6. Set up your desired filters using the AND and OR options, with relevant use of the **+Rule** and **+Group** buttons.
7. Click **apply filter** at the bottom right of your screen.
8. Click **Close** when finished. The option filter will automatically save and be applied to your form. Note that you’ll still need to click **Save** at the top right of your form builder screen to update these changes within your form.

![](/files/aw2tNK5lIrXnJiQCSI7W)

### Options filter and syncing of forms

The greatest advantage of the options filter is that it allows for the overriding of a form. Synchronized forms will block you from modifying attributes to prevent sync malfunction, by default. Under filter options in the form builder, you’ll find an **Override** button at the bottom right. Clicking will override this individual filter. Note that if you have multiple filters, and want to modify all of them, you’ll need to click **Override** for each filter.

<figure><img src="/files/S1eN40JMmfZ9zqygqUeX" alt=""><figcaption></figcaption></figure>

### Org-based preview and org-specific instances

Use the org context drop-down selector to choose the child organization that you'd like to preview, and see how the form will function for that specific organization. Previews don't require cloning, and won't affect the saved form configurations except for the options filter. The options generator will display data as if the form were triggered in just that specific organization. The default-set options filter will be used if no custom filters were provided for the selected organization.

Click the drop-down selector to view and chose from your list of all total organizations.

<div data-full-width="false"><figure><img src="/files/K7fOjIkU64TPPyE5XvFa" alt=""><figcaption></figcaption></figure></div>

Selecting the preview organization sets the context of the form builder. and opening the preview dialog will use that organization's context to generate the correct preview, tailoring filtering logic for each instance without duplicating forms or unsyncing fields.

{% hint style="info" %}
By default, a field will inherit the parent organization's filter unless if it explicitly overridden.<br>
{% endhint %}


# Embed a form into an iFrame

### Embed forms

There is often a need to embed a form in an iframe to give users the ability to complete a form and trigger automation. The form can be embedded into other web pages that use iFrame links.

{% hint style="success" %}
To get the dynamic form URL, make sure your form is already set up as a trigger for a workflow.
{% endhint %}

### Get an embeddable link

Follow these steps to get the embeddable link:

1. Navigate to **Automations > Workflows**.
2. Click on the Workflow that includes the form trigger to open it in the Workflow Builder.
3. Click on the trigger to open its settings in the right side menu.
4. Click **Copy URL**.
5. Click **<>** **Copy Embeddable iFrame code**. This copies the embeddable Iframe code. Paste the code into your compatible webpage editor.

<figure><img src="/files/sqXKbtvHN8G8jdePpSJt" alt=""><figcaption></figcaption></figure>


# Clone an existing form

There may be times when you want to take an existing form and make slight modifications to apply it to another use case. For example, you may be using the Client: New Employee workflow to onboard new users, and want to have two different forms:

1. One for when you hire internal users at your organization
2. One for adding users for your customers

### How to clone and edit a form

1. Navigate to **Automations > Assets > Forms**.
2. Click **⋮** and select the **Clone** option on the form you want to clone.<br>

   <figure><img src="/files/7TPrp6ZaEaHFHL3HgN8f" alt=""><figcaption></figcaption></figure>
3. Rename your form to something unique and define a few other fields:
   * **New Name**: the new name of the cloned form, make sure this is something unique and describes the use case for the form.
   * **Organization**: the organization that the form will reside under.
     * This doesn’t necessarily mean that you want to select the customer that the form will be for. The best practice is to have the form live at the top-level organization. The customers are tied to the relevant form by a trigger in the workflow. More information can be found in the Intro to Triggers article.
4. Click the **Clone** button to see your cloned form.

<figure><img src="/files/0o7oGuYdKQS6Ys64mpW3" alt="" width="375"><figcaption></figcaption></figure>

## Shallow clone a form

*Shallow cloning* is a feature of the Rewst platform that allows you to create a copy of an existing workflow or form. This is useful if you have a workflow that is very similar to another workflow, but which requires a few small changes.

Standard cloning copies the entire resource *pack—* workflow, forms, templates, triggers, etc— and when cloning into your own org, you end up with multiple duplicates of the same resource. Shallow cloning copies that single selected resource, but re-uses all of the dependencies that it has. If you have a sub-workflow that's part of a main workflow, and you shallow clone that sub-workflow, you will end up with a copy of the sub-workflow. This lets you make changes to the sub-workflow without affecting the original workflow.

There is no difference between the steps to clone or shallow clone a resource. Rewst will automatically detect if you are cloning something into your own org. If so, the platform will shallow clone it instead. Note that this removes the **Synchronize** button on the dialog, and instead shows a text to explain.


# Conditional fields

You'll often have forms that you want to use across a multitude of clients, but sometimes fields may not be relevant to them all. Rewst has *conditional fields* that can be used to determine whether you show another field.

## Conditional field example

In our example, we will look at the **Supervisor** field when creating a new user. In the image below, no Supervisor is set, and therefore the following field is another drop-down for further information.

<figure><img src="/files/9bARmdCnRBUYsyU5fo1e" alt=""><figcaption></figcaption></figure>

You can then see that if we add content to that supervisor drop-down, which is a list of users pulled dynamically from Microsoft365, a new field appears.

<figure><img src="/files/NRaLNrOvg22IEZA5owGe" alt=""><figcaption></figcaption></figure>

This boolean field is then checked on, which gives access to another relevant field.

<figure><img src="/files/sPypEDijRgDg2xDUr6jB" alt=""><figcaption></figcaption></figure>

Rather than giving fields to a user that bear no relevance, you only give them fields they must fill in.

These conditional fields are set by clicking the field on the form and clicking **Set Conditional Field**, which presents you with the below.

<figure><img src="/files/vrfIAZMBnFeWjbKfZbNg" alt=""><figcaption></figcaption></figure>

## Jinja for field conditions in forms

There are times where you may need to use criteria for a form condition that is not accounted for by the available drop-down selections, such as when organization information or organization variables are part of the criteria. At these times, you might instead opt to use a Jinja condition, such as `{{ ORG.VARIABLES.variable_name == "value" }}`.

Another case where the use of Jinja may be required is when multiple conditions need to be met, even if those conditions are normally available in the drop-down selections. An example of this would be `{{ (CTX.field_name_1 == "value_1") and (CTX.last_name != "value_2") }}` .


# Troubleshoot unpacked Crate forms

{% hint style="info" %}
For more information on unpacking Crates, see our Crate documentation [here](https://docs.rewst.help/prebuilt-automations/crates#unpack-a-crate).
{% endhint %}

If a form field of a form unpacked from a Crate isn't populating with information, you have two options.

1. Identify the issue by digging into the form.
2. Open a support ticket with Rewst's support team and have them troubleshoot the issue for you.

Either option will require you to collect information from the form by completing the following steps. As an example, we're using the **\[Rewst Master v3] User Onboarding Minimalistic** form.

1. Navigate to **Automations > Assets > Forms**.
2. Open the form in question.
3. Scroll down in the right side menu. Click on any field that's further down in the field list.
4. Click on the field. This will open its information in the right side menu.

<figure><img src="/files/QxoDAW8VpnvdhqwR0WYW" alt=""><figcaption><p>The view of an expanded form field, open for editing</p></figcaption></figure>

5. Scroll down to see if the field is a dynamic field. If it is, **Dynamic Options** will be toggled **on**.
6. Confirm if the field has **Workflow Generated** toggled **on**. If so, look at the options generator in the **Workflow** field beneath it.
7. Open the options generator by clicking ![](/files/klgauGlRlsON2g7gZPtW).
8. Click **View results for workflow**.\
   \ <img src="/files/pUiICZd5nUerMmmFtE4v" alt="" data-size="original">
9. View the list of all times the workflow has run. Errors will be denoted by **Failed**.\ <img src="/files/gpaZxC1irWmseGjBksEL" alt="" data-size="original">
10. Click on failed execution rows to see more information.
11. Click on any of the failed actions in the list at the bottom of the page to examine its **Workflow Execution** log.

    1. If troubleshooting the issue yourself, find the errors in the workflow execution and correct them.
    2. If creating a ticket for Rewst support, copy the URL of your browser while viewing this information, and paste it into your support ticket.
    3. You can also ask [RoboRewsty](/documentation/roborewsty) to help you troubleshoot your execution results.

    <figure><img src="/files/TDqqogolT8KLmGIVqliQ" alt=""><figcaption><p>Click on ... under errors to expand error information</p></figcaption></figure>


# Form organization variables

Form [organization variables](/documentation/integrations/organization-variables) are implemented with specific forms that come from Crates. They can be used to set form\_org\_vars so that you can have specific default values for fields on a form.

<table data-full-width="true"><thead><tr><th width="304">Variable Name</th><th width="551">Description</th><th width="100">Valid Values</th></tr></thead><tbody><tr><td>form_default_supervisor</td><td>Used so that if the form forces a default, this is the value supplied in the if statement</td><td>string</td></tr><tr><td>form_default_orgunit</td><td>Used so that if the form forces a default, this is the value supplied in the if statement. Example is [{"id": "fb53fb9f-208f-451c-9391-6092eb7c4e1b","label":"OU=Disabled Users,OU=Pedro Users,OU=Pedro Ltd,DC=ad2,DC=pedroaviary,DC=com"}]</td><td>list</td></tr><tr><td>form_default_location</td><td>Used so that if the form forces a default, this is the value supplied in the if statement</td><td>string</td></tr><tr><td>form_default_email_domain</td><td>Used so that if the form forces a default via workflow input, this is the value supplied in the if statement</td><td>string</td></tr><tr><td>form_default_selection_email_domain</td><td>Will return the domain specified as the default selection for the workflow [Rewst Master v2] M365: List Email Domains-Actual</td><td>string</td></tr><tr><td>form_default_licence_sku</td><td>Used so that if the form forces a default, this is the value supplied in the if statement</td><td>list</td></tr><tr><td>form_default_aad_groups</td><td>Used so that if the form forces a default, this is the value supplied in the if statement. Example is [{"id": "68c2878a-6739-438c-bf5a-d8c2bea39573","label": "AAD Group One"},{"id": "936eb764-36c4-4ac6-b264-c532caeb217c","label": "Group Me Up Buttercup - Group"}]</td><td>list</td></tr><tr><td>form_default_distribution_aad_groups</td><td>Used so that if the form forces a default, this is the value supplied in the if statement. Example is [{"id": "68c2878a-6739-438c-bf5a-d8c2bea39573","label": "Dist Group Two"},{"id": "936eb764-36c4-4ac6-b264-c532caeb217c","label": "Group Me Up Buttercup - Distribution"}]</td><td>list</td></tr><tr><td>form_default_onprem_groups</td><td>Used so that if the form forces a default, this is the value supplied in the if statement. Example is [{"id": "68c2878a-6739-438c-bf5a-d8c2bea39573","label": "Local AD Group One"},{"id": "936eb764-36c4-4ac6-b264-c532caeb217c","label": "Another Local AD Group"}]</td><td>list</td></tr><tr><td>form_default_security_aad_groups</td><td>Used so that if the form forces a default, this is the value supplied in the if statement. Example is [{"id": "68c2878a-6739-438c-bf5a-d8c2bea39573","label": "Security Group One"},{"id": "936eb764-36c4-4ac6-b264-c532caeb217c","label": "Security Group Two"}]</td><td>list</td></tr><tr><td>form_default_department</td><td>Used so that if the form forces a default, this is the value supplied in the if statement. Example is [{"department": "HR"},{"department": "Finance"}]</td><td>list</td></tr><tr><td>form_default_phone_number</td><td>Used in the workflow itself that if the org var is specified, it'll use it if none on the form</td><td>string</td></tr></tbody></table>


# Templates and scripts

{% hint style="info" %}
Templates and scripts are similar features in Rewst, though each is intended for a different purpose. Once created, they're separated by type into two sections in the platform for ease of organization and sorting. Both can be referenced in workflows.
{% endhint %}

## What is a template?

*Templates* are used to create a standardized set of text used in several places in Rewst. For example, if you want to create a ticket and always use the same HTML for the ticket description, you would create a template. In the input, you would reference the template instead of having to type that same text each time.

To access templates, navigate to **Automations > Assets > Templates** in the left side menu of your Rewst platform.

Write templates in either Markdown or HTML language. Common examples of templates include:

Jinja templates

* Data transformations - Manipulating and formatting data between workflow tasks
* Dynamic field values - Creating dynamic inputs for action parameters
* Conditional logic - Building expressions for transitions and decision-making
* Text/message generation - Formatting emails, tickets, notifications, etc.
* List/dictionary comprehensions - Processing collections of data

Workflow templates

* Task configurations and parameters
* Transition logic between tasks
* Error handling patterns
* Sub-workflow integration
* With-items (loop) configurations

Trigger configuration templates

* Webhook triggers
* Scheduled/cron triggers
* Integration-specific triggers - e.g., ticket creation, form submission

App Builder templates

* Component configurations
* Data binding expressions
* Workflow integrations for apps

<figure><img src="/files/bJmjvT431vrBilSrf7db" alt="Screenshot of the Templates list view in the Rewst Automations section, showing a dark-themed interface with a left navigation menu, a top search bar and Create Template button, and a table of templates with names, descriptions, dates, attributes, and action icons."><figcaption></figcaption></figure>

Write templates in either Markdown or HTML language.

### Create a template

1. Click **+ Create**.
2. Fill in the relevant fields with the information for your template.
   1. **Name**
   2. **Description**
   3. **Tags**
3. Select the language you want to write your template in from the **Language** drop-down selector.
4. Click into your **Editor** panel on the left side of the screen to begin writing. View your progress in the **Preview** panel.
5. Scroll down and click **Submit** when finished.

<figure><img src="/files/vuKjrY14hxdXQd636px5" alt=""><figcaption><p>An example of an in-progress template, written in Markdown</p></figcaption></figure>

## What is a script?

*Scripts* in Rewst enable you to write scripts in a straightforward and accessible manner compared to traditional programming languages. Scripting tasks can range from batch processes on a local computer to generating dynamic web pages on a web server. Scripts can be written, edited, and executed more quickly and easily than software programs.

To access scripts, navigate to **Automations > Scripts** in the left side menu of your Rewst platform.

Write Rewst scripts in any of the following languages: PowerShell, Python, YALM, Jinja. All scripts are assigned a unique URL (GUID).

<figure><img src="/files/RZSsmE9XoD7W8FAkFVG5" alt="Screenshot of the Scripts list view in the Rewst Automations section, showing a dark-themed interface with a left navigation menu, a top search bar and Create Template button, and a table of scripts with names, descriptions, dates, attributes, and action icons."><figcaption></figcaption></figure>

Write Rewst scripts in any of the following languages: PowerShell, Python, YALM, Jinja.

### Create a script

1. Click **+ Create**.
2. Fill in the relevant fields with the information for your script.
   1. **Name**
   2. **Description**
   3. **Tags**
3. Select the language you want to write your script in from the **Language** drop-down selector.
4. Click into your **Text** panel to begin writing.
5. Scroll down and click **Submit** when finished.

<figure><img src="/files/jWvK3IL1Gvn7eFlhmsgo" alt=""><figcaption></figcaption></figure>

## Jinja: Use templates and scripts within workflows

While templates and scripts are written in HTML or Markdown, they can accept small elements of Jinja to set up their elsewhere in Rewst. They allow for context variables to be set within them, which can then be referenced in workflows to allow the eventual sent message to populate with dynamic information.

In the example below, you're sending an e-mail to a new user that has been created.

```django
Hi {{ CTX.first_name }},

Welcome to Rewst!

Your email account has been provisioned and you should be able to access it at:
https://outlook.office.com/mail/

username: {{ CTX.email }}
password: {{ CTX.password }}

We're excited to have you on the team!
```

In the input for the `Send Mail` action, you would enter `{{ template("<template-id>")}}` into the action's **Message** field instead of typing out the intended message manually. This would pull your pre-written template into the body of the email when it is sent.

<figure><img src="/files/3d7076UjayZ7yGZHSuBX" alt=""><figcaption></figcaption></figure>

The template ID or script ID can be taken from the URL, when editing. As an example, let's look at the URL below.

<figure><img src="/files/FXe44B00fkYzYt8hh7Ys" alt=""><figcaption></figcaption></figure>

The part of the URL underlined in yellow is the template ID. For this particular ID, your Jinja would read as `{{ template("768f5d45-5fe7-4c1f-b2c1-932dcbdcb1d7") }}`.

## Export and import templates and scripts

You can export a template or script to share with other Rewst customers, or create your own hard copies of template and script backups. To export a template or script as a JSON bundle, ![](/files/6iNRi02bpc2y30rldVl1)next to your relevant template or script in its total list.

To import a template or script bundled as a JSON file, click ![](/files/pSRxSYvjj8rtjxgRxLTC) in the top right navigation bar of the list page. Then, drag and drop your file into the upload dialog that appears.


# Actions

## What is an action?

*Actions* are the operations available for creating and automating, which live inside of a [workflow](/documentation/automations/workflows). You grab these actions from the left side library menu of the workflow builder, and drag them onto the Workflow Builder Canvas. When you run a workflow, Rewst is completing a series of actions specified within that workflow.

Once you've set up an [integration](https://docs.rewst.help/documentation/integrations), Rewst offers you a number of actions related to that integration to build your workflows. They're accessible from the accordion menus in the left side library menu of the Workflow Builder, and sorted based on their respective sources, including integrations by brand, Core, Rewst, Transform, and Workflow. Expand any accordion to see the related actions it contains.

<figure><img src="/files/gNbaEwVgSfEH23SjRJWm" alt=""><figcaption><p>The actions menu of the Workflow Builder</p></figcaption></figure>

Each action serves a unique purpose and comes with a brief description to aid in understanding its functionality. Click on any action to begin dragging and dropping it onto your Workflow Builder Canvas. For more on our Workflow Builder and how workflows are essential to Rewst, see our workflow documentation [here](https://docs.rewst.help/documentation/workflows).

{% hint style="success" %}
Click through to any of the related action type pages to learn more.
{% endhint %}

Each action has a set of configuration options within it, editable in its right side menu of the Workflow Builder once dragged onto the Canvas. Learn more about settings for tasks [here](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow#configure-tasks) in our workflow documentation.

### Core actions

These are the essential platform components like webhooks, email dispatching, and [noops](https://docs.rewst.help/documentation/workflows/actions-in-rewst/core-actions#no-operation-noop).

{% content-ref url="/pages/ItLAL7BSFZkafcQPS6S6" %}
[Core actions](/documentation/automations/actions-in-rewst/core-actions)
{% endcontent-ref %}

### Integrations actions

When you set up an integration in Rewst, it comes with a predefined set of actions, which will appear in your workflow builder action menu. These actions allow you to work with various parts of the integrated product as per its API. Rewst's integrations pull in the most useful and most commonly used actions, but not all available actions. See our [individual integration setup pages](/documentation/integrations) for more information on available actions.

{% content-ref url="/pages/OSnkx0SEHcbueeC19adV" %}
[Integrations](/documentation/integrations)
{% endcontent-ref %}

### Rewst actions

These actions are for interacting with your Rewst environment. You can perform tasks such as creating organizations and users, associating with multi-tenanted objects, and setting organization variables.

{% content-ref url="/pages/5tKhys9AyA11Caej1cal" %}
[Rewst actions](/documentation/automations/actions-in-rewst/rewst-actions)
{% endcontent-ref %}

### Transform actions

These actions help you shape and modify your data for efficient workflow execution, replacing the need for complex Jinja statements.

{% content-ref url="/pages/wzApPvhqXx0qV57qBEbb" %}
[Transform actions](/documentation/automations/actions-in-rewst/transform-actions)
{% endcontent-ref %}

### Workflows actions

These actions allow you to call other workflows within your environment. They enable you to feed information from the parent workflow as inputs and return the results upon completion.

{% content-ref url="/pages/vIgZWGeoD6JWH1YqyITR" %}
[Workflows actions](/documentation/automations/actions-in-rewst/workflows-actions)
{% endcontent-ref %}

### Generic actions

For each integration, Rewst provides a single action that isn't predefined like the other integration-related actions, but which can be used to define a URL path. Using that path for the endpoint you wish to reach in the partner's API allows you to specify data, cookies, headers, etc., for custom targeting beyond what Rewst's other predefined actions allow.

Generic actions rely heavily on your reading the integration's API documentation and researching the endpoints yourself. Most frequently, we suggest this as a feature for more advanced users, though customers with specific goals might be required to use it early on in their onboarding process.

Generic actions are typically named after the integration in the format of `[integration] API Request`. For example, for HaloPSA the action is called `HaloPSA API Request` .

<figure><img src="/files/mKgt4WPErVfyrr8gBJop" alt=""><figcaption><p>The HaloPSA generic action</p></figcaption></figure>

{% hint style="warning" %}
Note that the paginate request option in any generic action modifies how the request is formed. This can cause issues on the API's side, causing them to behave unexpectedly and return error messages.

If your integration is missing a generic action and you'd like to see us develop one, add that feedback to our [Canny feedback collector.](https://rewst.canny.io/integrations)
{% endhint %}

## Action version updates

{% hint style="info" %}
Note that this action version functionality won't appear for any actions related to your custom integrations.
{% endhint %}

From time to time, Rewst will make updates to existing actions. These updates may require customers who are using those actions in their workflows to make modifications or adjustments. View the changelog of an action's version history in the left side action list of the [Workflow Builder.](/documentation/automations/workflows/workflow-builder-how-to-set-up-a-workflow) If the action in the action list has logged changes, an icon will appear to the right of its name in the list. Click on that icon to expand the version history log.

<figure><img src="/files/GQ6P9T0C0vgIkyi0ekd9" alt="" width="375"><figcaption></figcaption></figure>

### Action version log status and alert meanings

| Label            | Color  | Meaning                                                                          |
| ---------------- | ------ | -------------------------------------------------------------------------------- |
| Action Required  | Red    | One or more actions have breaking changes                                        |
| Attention Needed | Yellow | Actions need review, but aren't breaking                                         |
| Updated          | Blue   | Actions have been updated - no action is required and the alert is informational |

<figure><img src="/files/lRT7XYHV2gK77nKDtovo" alt="" width="375"><figcaption><p>Click links in the action changelog to view additional<br>documentation or guides.</p></figcaption></figure>

You'll see a red pulsing dot to the right of the **Workflows** section of your left side menu when there are unread breaking changes.\
![](/files/yORL9vVaUAicn7BiuDwJ)

When workflows in your current organization are affected by version changes, a toolbar will appear in your workflows list page with up to three buttons, each containing the total count of actions in the organization that fall into each alert category. A red pulsing dot will be present next to the Attention Needed category when unread breaking changes exist. Click on any of the categories in the toolbar to filter your workflows list to just that group of workflows. These statuses also apply to the **Attributes** column's filtering capabilities.

<figure><img src="/files/06nihOj5fFFFhzVeUEm3" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/R0hlaZQkX6GG6C4BKOPv" alt=""><figcaption></figcaption></figure>

## Known actions issues and errors

This collection of issues related to actions have been reported to Rewst by our customers. If you experience an issue with actions that is not in this list, contact us in your dedicated Discord support channel.

{% hint style="success" %}
Click on any of the issues below to expand and see its solution or information.
{% endhint %}

<details>

<summary>Brave browser</summary>

Brave browsers will block the click event on Rewst actions. This is due to the way that Brave handles the click event. To fix this, you can either [disable the Brave shield for the page](https://support.brave.com/hc/en-us/articles/360023646212-How-do-I-configure-global-and-site-specific-Shields-settings), or use a different browser.

</details>

<details>

<summary>ThreatLocker</summary>

We have received reports that ThreatLocker may block certain Rewst actions. Threatlocker has a built-in application for Rewst IP addresses that can be added to your Ringfence policy.

To set this up in ThreatLocker:

1. Navigate to **Modules > Application Control**.
2. Click **Policies**.
3. Select **PowerShell Ringfencing Policy**.
4. In the **Actions** section, click **Tags**.
5. Add **Rewst**.

This process may not be necessary if you have already [whitelisted our outgoing IP addresses](https://docs.rewst.help/security/security-policy), but it's something to consider if you run into any issues. Additional steps for whitelisting in ThreatLocker are outlined in this linked document.

</details>

<details>

<summary>UnreachableJoinError: The join task|route "XXXXXXX" is partially satisfied but unreachable.</summary>

This error is related to having multiple transitions going to a single action.

1. Click the **Advanced** tab within the action that has multiple transitions going to it.
2. Under the field **Task Transition Criteria***,* you'll likely have a 0. This means that all actions previously have to be complete before that action will run.
3. Change this to the relevant number. For example, change to a 1 so that only one of the previous actions must complete before that action runs.\
   \
   ![](/files/QLjIa4WtEswk7o8wEdLH)

{% hint style="info" %}
In the image above, the workflow chooses the RMM of the client. Then, depending on the result, it runs a script on that system. The client likely isn't going to have multiple RMMs, so only one of the script tasks is going to run.

However, they all merge into the final **compile\_results** task at the bottom. By default, this workflow will fail, as it is expecting each script task to complete before hitting that final task.

This is where you would change the **Task Transition Criteria Sensitivity** to a `1`. This states that only one of the tasks that come into it must have been completed.

If there was a workflow where you wanted to run on two instances then you would enter `2`, for 2 tasks to be completed.
{% endhint %}

</details>


# Core actions

*Core actions* in Rewst are your gateway to the platform's vast array of intrinsic functionalities. These actions, usable right out of the box, offer features ranging from ad-hoc HTTP requests to document parsing.

Core actions are used in the same way as regular actions within workflows. They are selected from the list of available actions, configured based on their parameters, and then added to the workflow at the appropriate place.

{% hint style="info" %}
Expand each of the action types below to see their individual information. Actions are listed alphabetically in both this doc and the Rewst platform.
{% endhint %}

<details>

<summary>Await Webhook Request action</summary>

Waits for a request to a created one-off webhook. Once a request is received, the workflow continues.

* **Parameters**: This action only requires the ID of the webhook created from the `Create Webhook` action.
* **Output**: The output includes the HTTP method, query params, headers, JSON or form/multipart data in the body of the request, and the timestamp when the request was received.
* To access the results of a webhook, publish a [data alias](/documentation/automations/workflows/data-aliases) with a value of `{/{ RESULT }/}.` You cannot merely publish the results as or use task.

</details>

<details>

<summary>Compare Strings Set Ratio action</summary>

This action calculates the ratio of how many words from the smaller string are found in the larger string. It's designed for measuring string similarity based on word overlap rather than character-by-character comparison. This action is particularly useful when you need to determine how similar two text strings are based on shared words, making it ideal for scenarios where exact string matching is too strict but you still need to measure content similarity.

**Use Cases**:

* Fuzzy matching between text strings
* Duplicate detection in datasets
* Content similarity analysis
* Partial string matching scenarios

**Parameters**:

* **original\_string** (required): The original string to compare
* **comparison\_string** (required): The comparison string that is being compared to

**Output**: Returns an integer representing the ratio of word overlap between the two strings. Higher values indicate greater similarity.

</details>

<details>

<summary>Confirmation Email action</summary>

Send a confirmation email with reply options to a specified recipient.\
This action pauses the workflow and places it in an `Awaiting-User-Input` state. The workflow will not proceed until the confirmation email is interacted with via buttons, or the task times out. You can configure task timeout on the **Advanced** tab of the action. Task time out means that the action fails. Note that this setup means that buttons are required for the workflow to proceed.\
\
![](/files/01UmlKilcZMFQ7QNBFf5)

* **Parameters:** This action requires the recipient's email address (`to`), the subject of the email (`subject`), the title of the email (`title`), and the message body (`message`). It also offers user interaction buttons (`buttons`) and has the option to render markdown as HTML (`render_markdown`).
  * The parameters have several optional settings:
    * Custom Button CSS - Custom CSS to be applied to the buttons
    * Custom Footer - Custom footer to be displayed in the email. If not provided, this will default to the Rewst footer unless the footer is set to be removed.
    * Custom Title CSS - Custom CSS to be applied to the title
    * Logo Link - URL to go to if the logo is clicked. If not provided, this will default to [https://rewst.io](https://rewst.io/)
    * Logo URI - String value URI of the logo to be displayed in the email. If not provided, this will default to the Rewst logo image. This is essentially providing a value for the src param of a img tag. You could also provide a base64 encoded value. The file format for your hosted file will need to follow the guidance for your particular email client, which is independent of Rewst. For example, Outlook does not accept PNG formatted files. For broader guidance for all email clients, we recommend using this resource called [caniemail](https://www.caniemail.com/features/).
    * Remove Footer - Removes the Rewst footer from the email
    * Render Markdown - Renders markdown as HTML when set to **True**
* **Output:** If the action is correctly executed, a confirmation email will be sent. Output variable `inquiry_result` is an output of the task and can be used to route the workflow in a specific path. `Inquiry_result` 's value is that of the button clicked, and is configured as a string value on the action itself in the workflow builder.

<figure><img src="/files/8bMD2NChrCFgOUlMelnG" alt=""><figcaption></figcaption></figure>

* **Confirmation email class and confirmation examples**
  * Button classes:
    * Primary; primary
    * Default; default
    * Danger; danger
  * Title class:
    * Title; title
* **Example custom button CSS**

```css
a,

a:visited,

a:hover,

a:active {

color: inherit !important;

}

table, td, div, h1, p {

font-family: "Times New Roman", Times, serif;

}

.primary {

background: #4d7c0f;

}

.default {

background: #365314;

}

.danger {

background: #dc2626;

}
```

* **Example custom footer**

  ```
  <tr>

  <td

  style="text-align:center;padding:30px 0 30px 0;background-color:#1a2e05;color:#ffffff;">

  <p style="display:inline-block;margin-right:10px;">&copy; The Dougnut {% now 'local', '%Y' %}</p>

  <p style="display:inline-block;margin-right:10px;"><a

  href="https://rewst.io/terms-of-service/">Order</a></p>

  <p style="display:inline-block;margin-right:10px;"><a href="https://rewst.io/privacy-policy/">Contact Us</a></p>

    

  <p style="display:inline-block;margin-right:10px;color:#84cc16"><a href="mailto:support@rewst.io">Need

  Delivery?</a></p>

    

  <p style="display:inline-block;margin:0px 4px 0 4px;vertical-align:middle;"><a href="https://www.linkedin.com/company/rewst"><img

  src="https://rewst-splash.s3.us-east-2.amazonaws.com/linkedin.png" width="24" height="24"

  alt="linkedin"></a></p>

    

  <p style="display:inline-block;margin:0px 4px 0 4px;vertical-align:middle;"><a href="https://twitter.com/rewst_dot_io"><img

  src="https://rewst-splash.s3.us-east-2.amazonaws.com/twitter.png" width="24" height="24" alt="twitter"></a>

  </p>

    

  </td>

  </tr>
  ```
* **Example custom title CSS**

```
.title {

font-size: 20px;

line-height: 16px;

font-weight: 700;

font-style: normal;

color: #0c0a09;

text-decoration: none;

letter-spacing: 0px;

padding: 25px 30px 0 30px;

}
```

* **Example logo link**

```
https://google.com
```

* **Example logo URI**

```
https://www.svgrepo.com/download/533811/donuts-cake.svg
```

</details>

<details>

<summary>Create Pending Task action</summary>

This action creates a pending task that pauses workflow execution and requires manual intervention through the Rewst UI. It's designed for scenarios where human approval, confirmation, or decision-making is needed within an automated workflow.

**Use Cases**:

* Manual approval workflows
* User confirmation before critical actions
* Decision points requiring human judgment
* Interactive workflow processes
* Quality control checkpoints

**Parameters**:

* **message** (required): The message to display in the pending task that explains what action is needed from the user
* **buttons** (required): An array of button objects that users can click to respond. Each button has:
  * **label**: The text displayed on the button
  * **style**: Visual style (`default`, `primary`, `danger`)
  * **value**: The value returned when the button is clicked

**Output**: The workflow pauses at this task until a user interacts with it via the Rewst UI. When a button is clicked, the action returns the corresponding button value, allowing the workflow to continue based on the user's choice.

This action is essential for creating interactive workflows that require human oversight or decision-making at specific points in the automation process.

</details>

<details>

<summary>Create Webhook action</summary>

Allows for the creation of a one-off webhook for which can then be used by the `Await Webhook` action.

**Parameters**: This action requires the methods allowed to access the webhook, the response status, response headers, response body, and an expiration timeout.

**Output**: The output of this action is the webhook ID and the full URL of the webhook.

</details>

<details>

<summary>Debug action</summary>

The `Debug` action is a utility feature in our workflow system, specifically designed to assist with debugging and logging purposes. This action can help in understanding the flow of data within your workflows, troubleshoot problems, and generally help you understand what's happening at a certain point in the workflow execution. It logs the input parameters it receives and returns the same as its output.

**Use cases**

You might want to use the `Debug` action in the following scenarios:

* When developing workflows, to see how data is flowing between tasks and actions.
* If you're troubleshooting an issue, to inspect the data that's being passed around.
* When you want to log specific information for auditing or reporting purposes.

**Input Parameters**

The `Debug` action accepts the following parameters:

* **text:** This is a general-purpose text field that will be logged and returned by the `Debug` action.
* **template:** This field takes a reference to a template in your environment that will be rendered and used as part of the action's input. The system will replace any variables in the template with its actual value at the time of template rendering.

**Example Usage**

Let's say we have a template named "Greeting Message" with content `# Hey there {{ CTX.name }}`.

We can use this template in the `Debug` action with the following parameters:

```yaml
text: Testing Debug Action
template: Greeting Message
```

Assuming `CTX.name` is set to `Rewsty`, the rendered template would be `# Hey there Rewsty`.

The `Debug` action will log these parameters and also return them as its output. The results of the action on the workflow results page would look like this:

**Output:**

```json
{
  "template": "# Hey there Rewsty",
  "text": "Testing Debug Action"
}
```

This tells us that `CTX.name` was set to`Rewsty`, and the text provided with this action was `Testing Debug Action`. Using this, you can better understand the state of your workflow at the point this `Debug` action was executed.

</details>

<details>

<summary>DNS Query action</summary>

Queries a nameserver for DNS records associated with a given URL.

* **Parameters:** The URL to query the Nameserver for, the field to query from the nameserver, timeout for the DNS Query (optional, default 60), and the nameserver to use for the query (several options available including Google, Cloudflare, OpenDNS).
* **Output:** The specified DNS records associated with the given URL from the queried nameserver.

</details>

<details>

<summary>Generate Password V2 action</summary>

An upgrade from the deprecated password generation action. It crafts a cryptographically secure password with user-specified values. (*This is recommended for use over the deprecated Password Action due to its upgraded structure.)*

* **Parameters:** length, minimum counts of numeric and capital letter characters, and optional punctuation characters.
* **Output:** the generated password is presented under the "password" key in the output.

</details>

<details>

<summary>HTTP Request action</summary>

Performs an HTTP request to a specified URL, supporting a variety of methods, body content types, and configurations. This is useful for interacting with APIs or other web services within a workflow, or for performing any other tasks that involve HTTP requests.

{% hint style="info" %}
*In most cases, we recommend that you use a* [*Custom Integration*](/documentation/integrations/custom-integrations) *instead of this HTTP Request action. This allows for enhanced security and customization when interacting with your external APIs. The* HTTP Request action will require building out all endpoints as individual actions/subworkflows. It is only recommended for when Custom Integration is not possible or repeatedly fails.
{% endhint %}

**Parameters**

* **URL**: The URL to which the HTTP request is sent.
* **Request Method**: The HTTP method to use for the request. You can select from the dropdown options (`HEAD`, `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS`, `TRACE`, `PATCH`, `PURGE`).
* **Auth Username**: The username for basic HTTP Authentication, if needed.
* **Auth Password**: The password for basic HTTP Authentication, if needed. *(This parameter is secret to ensure security.)*
* **Allow Redirects**: Specifies whether the HTTP request will follow redirects. By default, it's set to `true`.
* **Body**: The body to send with the request. This parameter is not required if `JSON` or `Files` is provided.
* **JSON**: The JSON body to send with the request. This field is not required if `Body` or `Files` is provided.
* **Files**: Here, you can add files to be uploaded with the HTTP request using `multipart/form-data`. Each file requires the following information:
  * **Field Name**: The name of the form field (not the filename).
  * **File Name**: The name of the file.
  * **File Contents**: Contents of the file to upload.
  * **File URL**: A publicly-accessible URL to the file contents to upload.
  * **Content Type**: The MIME type of the file to include in the multipart field.
* **Cookies**: Input the cookies to send with the request. You can add more than one cookie by clicking on the `+` icon.
* **Headers**: Specify the custom HTTP headers to be sent with the request. You can add more than one header by clicking on the `+` icon.
* **Params**: Enter the query parameters to be used with the HTTP request. You can add more than one parameter by clicking on the `+` icon.
* **Timeout**: Enter the timeout for the HTTP request in seconds. The default value is `5`.
* **Require Success Status**: If you check this box, the task will fail if a non-2xx HTTP status code is returned. This is useful for identifying and handling HTTP errors during the task's execution.

**Output**: The action returns the content returned by the server in response to the HTTP request. This could be a success message, a failure message, a data object, or any other content that the server sends as a response.

</details>

<details>

<summary>Delay Workflow For Period action</summary>

Pauses the workflow for a specified duration.

* **Parameters:** The number of days, hours, minutes or seconds to delay the workflow.
* **Output:** No specific output, the workflow resumes after the specified delay.

</details>

<details>

<summary>Delay Workflow Until Date/Time action</summary>

Pauses the workflow until a specified date and time.

* **Parameters:** The date and time when the workflow should resume.
* **Output:** No specific output, the workflow resumes at the specified date and time.

</details>

<details>

<summary>Mock action</summary>

The `Mock` action is designed to provide you with the capability to simulate the result of a not yet implemented action. This is particularly useful during workflow development and testing phases as it allows you to simulate responses from services that are not yet available or are impractical to call during the development process.

**Use cases**

The `Mock` action comes in handy in scenarios such as:

* When designing new workflows where certain steps are not fully implemented.
* In testing stages, to simulate conditions without making actual calls to the services.
* To create controlled conditions in your workflow for troubleshooting issues.

**Input Parameters**

The `Mock` action accepts the following parameter:

* **Mock Result:** This parameter should contain the key / value pairs that you want to be returned by this action. You can press the `+` to add as many objects as necessary.

**Example Usage**

You are developing a workflow that is expected to interact with a service which is not yet implemented. You know the expected format of the response, and you want to build and test your workflow logic based on that response.

Let's say you know the response will look something like this:

```json
{
  "name": "Rewsty",
  "valid": true,
  "message": "Successfully completed the task."
}
```

You can simulate this response using the `Mock` action as follows:

```yaml
mock_result:
  name: {{ CTX.name }}
  valid: true
  message: Successfully completed the task.
```

While using the `Mock` action, the values can be literal Jinja expressions like `{{ CTX.name }}`above. The action will return this exact input structure wrapped inside a `data` object, and the Jinja expressions will not be evaluated but returned as is. The result of the action on the workflow results page would look like:

**Output:**

```json
{
  "data": {
    "name": "{{ CTX.name }}",
    "valid": true,
    "message": "Successfully completed the task."
  }
}
```

This can be useful for catching issues early in the development phase such as incorrect Jinja expression usage, understanding how the workflow will handle dynamic data, or verifying that your workflow is properly constructed to handle the expected responses from services. It's a way to ensure that your workflow behaves as expected when it starts receiving actual dynamic data.

</details>

<details>

<summary>No-Operation (Noop) action</summary>

A noop action does nothing. It's often used for logic or as a placeholder in the workflow.

* **Parameters:** None.
* **Output:** None

</details>

<details>

<summary>Parse HTML action</summary>

The Parse HTML action is a versatile tool within Rewst, geared to pinpoint and extract specific elements or data from HTML documents. It leverages the power of BeautifulSoup, a Python library recognized for extracting data from HTML and XML files effectively.

**Use cases**

This action is particularly beneficial in these situations:

* **Data Extraction**: capturing specific information from the response of an HTTP request.
* **Content Clean-Up**: sieving out only the necessary data from complex HTML content.
* **Web Scraping**: automating the extraction of specific information from various web pages using defined tags, classes, or identifiers.

**Action Parameters**

The `Parse HTML` action accepts the following parameters:

* **HTML**: The HTML content to be parsed. This could be HTML content from a webpage, obtained using the `HTTP Request` Core Action.
* **Class**: Optionally finds HTML elements based on their `class` attribute.
* **ID**: Optionally searches for HTML elements based on their `ID` attribute.
* **Query**: Employs [BeautifulSoup filters](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#kinds-of-filters) to specify the operation type:
  * `find_all` returns all instances of the defined HTML tag.
  * `find` returns only the first instance of the defined HTML tag.
  * `select` enables the use of CSS selectors for nested HTML tags.
* **String**: Optionally searches for specific text within the HTML content.
* **Value**: Identifies the tag or selector to search for in the HTML content. For example, `a` would find all anchor (`<a>`) tags in the HTML content.

**Practical Use Case: Extracting Links from 'Hacker News'**

This example involves making a `GET` request to the `Hacker News` website and parsing the returned HTML to extract all `<a>` links.

The first step uses the Core `HTTP Request` action to fetch the HTML content:

```yaml
publish_result_as: news
request_method: GET
URL: https://news.ycombinator.com
```

You can then use the `Parse HTML` action to extract all `<a>` links. The parameters for this action would be set as follows:

```yaml
html: {{ CTX.news }}
style: find_all
value: a
```

**Example Workflow Results**

Here's an example of how the `Parse HTML` action's input and output might look like on the workflow results page:

**Input from the HTTP Request:**

```json
html: {
  cookies: {},
  data: "<html>...</html>",
  headers: {...},
  status_code: 200
},
query: {
  style: "find_all",
  value: "a"
}
```

**Result:**

```yaml
[
  "<a href=\"https://news.ycombinator.com\"><img height=\"18\" src=\"y18.svg\" style=\"border:1px white solid; display:block\" width=\"18\"/></a>",
  "<a href=\"news\">Hacker News</a>",
  "<a href=\"newest\">new</a>",
  "<a href=\"front\">past</a>",
  "<a href=\"newcomments\">comments</a>",
  "<a href=\"ask\">ask</a>",
  "<a href=\"show\">show</a>",
  "<a href=\"jobs\">jobs</a>",
  "<a href=\"submit\">submit</a>",
  "<a href=\"login?goto=news\">login</a>"
]
```

This result contains all `<a>` tags found in the HTML content.

To further refine this output, returning only links for externally referenced pages, use the `select` query style, along with advanced CSS filters:

```yaml
html: {{ CTX.news }},
style: select
value: .titleline a[href^='https://']
```

The result is a list of strings containing all `<a>` tags that meet the newly specified criteria:

```json
[
  "<a href=\"https://arxiv.org/abs/2308.00676\" rel=\"noreferrer\">Electronic Structure of LK-99</a>",
  "<a href=\"https://www.science.org/content/blog-post/room-temperature-superconductor-new-developments\" rel=\"noreferrer\">A room-temperature superconductor? New developments</a>",
  "<a href=\"https://sophiehoulden.com/randomstuff/epitime/?revised\" rel=\"noreferrer\">Epicycle Clock</a>",
  "<a href=\"https://howardism.org/Technical/Emacs/new-window-manager.html\" rel=\"noreferrer\">Emacs is my new window manager</a>",
  "<a href=\"https://ploum.net/2023-08-01-splitting-the-web.html\" rel=\"noreferrer\">Splitting the Web</a>",
  "<a href=\"https://twitter.com/zebulgar/status/1686498517227814912\" rel=\"noreferrer\">Unconfirmed video showing potential LK-99 sample exhibiting the Meissner effect</a>",
  "<a href=\"https://magicloops.dev\" rel=\"noreferrer\">Show HN: Magic Loops – Combine LLMs and code to create simple automations</a>",
  "<a href=\"https://arxiv.org/abs/2307.08378\" rel=\"noreferrer\">eGPU: A 750 MHz Class Soft GPGPU for FPGA</a>"
]
```

To further understand CSS selectors, you can refer to this [w3schools article](https://www.w3schools.com/cssref/css_selectors.php).

***Tip**: Parse HTML's functionalities include finding elements by tags (`<h1>`), class (`class_="abc"`), text (`string="The content"`), or id (`{"id": "abc"}`). When `string` is the sole argument, only the text is returned, not the whole element, which can help you fine-tune data extraction.*

</details>

<details>

<summary>Parse XML action</summary>

The Core Parse XML action in Rewst is designed to locate and extract specific elements or data from XML documents. This powerful tool, backed by an efficient Python library, facilitates precise data extraction from XML files, simplifying the process of parsing complex data structures. For additional understanding on XPath expressions, refer to this [w3schools article](https://www.w3schools.com/xml/xpath_intro.asp).

**Use cases**

Consider using the Parse XML action in these scenarios:

* **Data Extraction and Content Clean-Up:** Capture specific information or filter out necessary data from XML-formatted content. This is particularly useful in processing responses from HTTP requests or handling complex XML documents.
* **Web Scraping:** Automate the extraction of specific information from various XML sources using defined tags, attributes, or identifiers. It enables you to precisely target the data you need from web resources.

**Action parameters**

The Core Parse XML action requires the following parameters:

* **XML**: The XML content that needs to be parsed. This could be XML content from an API response, obtained using the HTTP Request Core Action.
* **Attributes**: (Optional) Allows you to find XML elements based on their attribute key.
* **ID**: (Optional) Permits searching for XML elements based on their ID attribute.
* **Selector**: Determines the operation type. Options include:
  * `find`: Returns only the first instance of the defined XML tag.
  * `find_all`: Returns all instances of the defined XML tag.
  * `select`: Enables the use of XPath expressions for nested XML tags or conditional searches.
* **String**: (Optional) Allows you to search for specific text within the XML content.
* **Value**: Specifies the tag or selector to search for in the XML content.

**Practical Use Case: Extracting Books from a Bookstore's XML Data**

Before diving into parsing XML data, you'll need to fetch the XML file. In this use case, the XML file is fetched from a public URL which contains bookstore data in XML format. The first task in the workflow, called `get_books`, uses the Core `HTTP Request` action to fetch this XML content:

**Input parameters:**

```yaml
url: http://books.toscrape.com/catalogue/category/books_1/index.html
request_method: GET
publish_result_as: get_books
```

The result from this task will look something like this:

```json
{
  "cookies": {},
  "data": "<bookstore>...</bookstore>",
  "headers": {...},
  "status_code": 200
}
```

The `data` field contains the XML content, which is the input for the `Parse XML` action. The XML content is passed using the Context (`CTX`) object as `CTX.books.data`.

**Finding the first book**

In this scenario, we are using the `find` operation to return the first `book` element in the XML:

**Input parameters:**

```yaml
input:
  xml: {{CTX.books.data}}
  selector: find
  value: book
```

The result from this task will look something like this:

```json
{
  "value": "<book category=\"cooking\"><title lang=\"en\">Everyday Italian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price></book>"
}
```

The output includes the first `book` element in the XML content.

**Selecting all 'Children' category books**

For a more complex operation, we can use the `select` operation with an XPath expression to extract all `book` tags where the `category` attribute is `children`.

**Input parameters:**

```yaml
xml: {{CTX.books.data}}
selector: select
value: book[category='children']
```

**Result:**

```json
{
  "value": "<book category=\"children\"><title lang=\"en\">Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></book>"
}
```

The result includes all `book` tags where the `category` attribute is `children`.

</details>

<details>

<summary>Send Mail action</summary>

Allows for the sending of an email.

* **Parameters:** This action requires a sender prefix (`sender`), with multiple options available, the recipient's email address (`to`), the subject of the email (`subject`), the title of the email (`title`), and the message body (`message`). It also has the option to render markdown as HTML (`render_markdown`). You can also fully control the HTML of the email with `(Custom HTML)`. This can also reference a template using the `{{ template(“guid”) }}` function.
  * Note that if you're using the `Custom HTML` field, the message and title fields will be ignored.\
    ![](/files/ccHxROlrGVVulBJRudAN)
  * You cannot upload images to Rewst, so any image will need to be externally referenced via URL. The file format will need to follow the guidance for your particular email client, which is independent of Rewst. For example, Outlook does not accept PNG formatted files. For broader guidance for all email clients, we recommend using this resource called [caniemail](https://www.caniemail.com/features/).
  * Emails will still be sent from the rewst.io domain.
* **Output:** The task doesn't yield an output upon success. It will fail if there are any errors during the process of sending the email.

</details>

<details>

<summary>Send SMS action</summary>

Allows you to send a text message to a specified phone number.

* **Parameters**: This action requires the recipient's phone number (`phone_number`) and the text message (`message`) to be sent. All phone numbers must be provided using the E.164 international format, which includes the country code. Improperly formatted numbers may result in validation errors or delivery failures.

  Example: `+14155552671`
* **Output**: The output of this action will depend on the implementation details. Usually, it will return a confirmation message or an error message.

**Sending number origin**

The `core_send_sms` action sends messages from a US-based phone number owned and managed by Rewst.

Due to this setup:

* SMS delivery is most reliable for United States phone numbers
* Some international carriers restrict or block messages originating from US long-code numbers
* Certain countries require locally registered sender IDs or approved messaging routes

These limitations are imposed by telecommunications carriers and regional messaging regulations.

**When to use your own messaging account**

If you need to send SMS messages to a region that is not supported by the shared Rewst sending number, you can set up your own messaging account and use it through Rewst’s [Twilio integration](/documentation/integrations/integration-guides/twilio-integration-setup).

Using your own account allows you to:

* Purchase local phone numbers in supported countries
* Configure which countries your numbers can send messages to
* Register country-specific sender IDs
* Meet regional compliance requirements

**Delivery behavior**

When the `core_send_sms` action is executed, it returns the **current delivery status** for the message. This status reflects the system's understanding of the message state after it has been sent to the carrier networks. Even when a message is reported as sent, final delivery still depends on external telecom carrier networks and the recipient device.

Because SMS delivery involves multiple third-party carriers, failures may still occur due to:

* Carrier filtering
* Regional messaging restrictions
* Unreachable devices
* Network congestion
* Recipient opt-outs

**Common SMS error responses**

* SMS service is temporarily unavailable, please try again later
* Invalid phone number format
* SMS cannot be sent to this region - geographic permissions not enabled
* This recipient has opted out of receiving messages
* SMS cannot be delivered to this number due to carrier or regional restrictions
* This number is a landline and cannot receive SMS messages
* The phone is currently unreachable (switched off or no signal)
* This phone number is unknown or may no longer exist
* This number cannot receive SMS messages (likely a landline or unsupported carrier)
* Network congestion - please try again in a few minutes

**Error scenario: Carrier or regional restrictions**

This situation occurs when the destination carrier or region doesn't allow messages from the sending number.

Possible causes include:

* Sender ID restrictions in the destination country – Some countries limit which numbers, shortcodes, or alphanumeric sender IDs can be used.
* Sender ID restrictions on the destination network – Certain networks may block messages from shortcodes or restrict MMS messages from longcodes that originate outside the country.
* Alphanumeric sender IDs – If you are using an alphanumeric sender ID, the destination country must support it, and some countries may require pre-registration.
* Number formatting – The “To” or “From” number may not be in the proper international format (E.164). Check that numbers are correctly formatted.
* Destinations with no connectivity – Some carriers or regions may not have messaging routes available for your sending number.
  * This error is more common when sending international messages from a US-based number. If you need to reliably reach a destination with restrictions, consider using your own messaging account via the Twilio integration, where you can configure allowed countries, local numbers, and sender IDs.

**Error scenario: Messaging geo-permissions disabled**

This situation occurs when an SMS or MMS message is sent to a country or region that the Rewst-managed sending number is not authorized to send messages to.

Possible causes:

* The destination country is not included in the allowed countries for the Rewst sending number
* The region is not supported for SMS delivery from the Rewst-managed sending number
* Messaging to that region is restricted by telecom regulations
  * If you need to send messages to a country that is not supported, consider using your own Twilio account via the Twilio integration, where you can configure allowed countries and sender IDs.

**Error scenario: Recipient has opted out**

The recipient has opted out of receiving messages from the sending number.

**Error scenario: Landline number**

The destination phone number is a landline and cannot receive SMS messages.

**Error scenario: Phone unreachable**

The destination device cannot currently be reached. Retrying later may resolve the issue.

Possible causes:

* Device powered off
* No cellular signal
* Temporary carrier network issues

**Error scenario: Unknown or unreachable numbers**

The destination number may not exist, cannot receive SMS, or is otherwise unreachable due to carrier restrictions.

**Error scenario: Network congestion**

The carrier network is currently congested. Retrying the message later may resolve the issue.

</details>

<details>

<summary>Test All Parameter Types action</summary>

This action serves as a comprehensive example and testing tool that showcases all the different input field types that can be used in Rewst actions. It's primarily used for:

* UI testing and validation
* Demonstrating parameter field capabilities
* Training and educational purposes
* Testing form rendering and validation

**Inputs**

The task accepts a wide variety of input parameters representing every field type available in Rewst:

**Basic fields:**

* `simple_string` (required) - Basic text input
* `optional_string` - Optional text field
* `string_with_default` - Text with default value "default\_value"
* `simple_integer` (required) - Whole number (default: 42)
* `simple_number` - Decimal number (default: 3.14)
* `simple_boolean` - Toggle switch (default: false)
* `required_boolean` (required) - Required toggle

**Advanced string fields:**

* `string_enum` (required) - Dropdown with options (option\_1, option\_2, option\_3)
* `string_enum_objects` - Dropdown with custom labels and descriptions
* `radio_selection` (required) - Radio button group
* `secret_string` - Password/masked field
* `multiline_text` - Large text area
* `textarea_content` - Code editor area

**Date/Time fields:**

* `date_field` - Date picker
* `time_field` - Time picker
* `datetime_field` - Date and time picker

**Array fields:**

* `simple_array` - Array of strings
* `array_with_enum` - Multi-select dropdown
* `array_of_objects` - List of complex objects with name, enabled, and quantity fields

**Object fields:**

* `simple_object` - JSON object field
* `nested_object` - Complex nested object with host, port, SSL settings, and credentials

**Special fields:**

* `number_with_range` - Integer between 1-100 (default: 50)
* `local_reference_template` - Reference to local templates
* `remote_reference_example` - Reference to remote API options
* `remote_reference_with_dependency` - Dependent reference field

**UI state fields:**

* `tooltip_field` - Field with helpful tooltip
* `hidden_field` - Hidden from UI
* `disabled_field` - Cannot be edited
* `readonly_field` - Read-only display
* `deprecated_field` - Marked as deprecated
* `staff_only_field` - Only visible to staff users

**Outputs**

The action returns a simple object with two properties:

* `message` (string) - A test result message describing the outcome
* `success` (boolean) - Whether the test execution was successful

</details>

<details>

<summary>UUID action</summary>

Generates a new UUID (Universally Unique Identifier).

* **Parameters:** UUID type (options include `uuid1` and `uuid4`, defaults to `uuid4`).
* **Output:** The generated UUID.

</details>


# Rewst actions

## Available Rewst actions

*Rewst actions* provide you the tools to effectively manage and customize your environment. From setting up organizations and users to associating with multi-tenanted objects, these actions form the foundation of your interaction with the platform. This guide explores each of the available actions in detail, providing you a clear path to maximize the potential of your Rewst functionality.

{% hint style="info" %}
Click to expand each of the Rewst action accordions below to see its documentation.
{% endhint %}

<details>

<summary>Associate External Object action</summary>

Linking external resources, like tickets from a PSA system, to your workflow executions can streamline management and enhance traceability. This action connects an external system's resource to your workflow. It optionally fails if a pre-existing link is detected, and runs under specified user or default user.

**Parameters:**

* **identifier:** Unique identifier of the external resource you'd like to associate.
* **reference\_id:** Reference for the external resource that you will be able to call back on.
* **run\_as\_user (optional):** Defined user's ID or default user's ID (if blank) for running the task.
* **fail\_on\_conflict (optional):** Set this option to true if you don't want to overwrite any existing `reference_id`/`identifier` pair already exists.

**Output:**

The resulting task's output returns the verified information about the associated external object.

</details>

<details>

<summary>Bulk Create Organizations action</summary>

Create multiple organizations at once within Rewst.

**Parameters:**

* Managing **Organization ID:** The ID of the managing organization. If not provided, the organization that initiated the operation will be set as the managing organization.
* Organizations (Required): List of organization details to be created. Each entry in the list should contain the following parameters:
  * Is Enabled: Boolean indicating if the organization should be enabled.
  * Name: The name of the organization in Rewst. The name must be unique.
  * Domain: The domain name of the organization's website, excluding protocol.

**Output:** Outputs a list of newly created organizations, each with its corresponding Organization ID, Domain, Name, Managing Organization ID, and Enabled Status.

</details>

<details>

<summary>Bulk Upsert Organization Variables action</summary>

Performs a bulk operation to create or update organization variables.

**Parameters:**

* **Organization Variables:** A list of objects where each object represents an organization variable to be created or updated. Each object must include:
  * **Name:** The name of the organization variable.
  * **Value:** The value of the organization variable.
  * **Category:** The category used to define the organization variable. Options include: `general`, `contact`, `system`, `secret`.
  * **Use as default:** If true, this variable's value will be used as the default value for any managed organizations without a defined value.
  * **Organization ID:** (Optional) The ID of the organization.

**Output:** Returns a list of objects. Each object represents an upserted organization variable and includes properties such as ID, name, value, organization ID, category, timestamps, associated organization, and more.

</details>

<details>

<summary>Create Organization action</summary>

Create a single organization within Rewst.

**Parameters:**

* Name (Required): The name of the organization to be created. This name must be unique within Rewst.
* Domain (Optional): The domain of the new organization, excluding protocol.
* Managing **Organization ID:** Identifier of the managing organization. If not provided, the organization that initiated the operation will be set as the managing organization.
* Is Enabled (Optional, default is true): A boolean indicating whether the new organization is enabled or not.

**Output:** Outputs the details of the newly created organization, which includes the Organization ID, Domain, Name, Managing Organization ID, and Enabled Status.

</details>

<details>

<summary>Create Organization Variable action</summary>

Creates a new organization variable that's available for use within an organization's workflow context.

**Parameters:**

* **Name:** The name of the organization variable.
* **Value:** The value of the organization variable.
* **Category:** The category used to define the organization variable. Options include: `general`, `contact`, `system`, `secret`.
* **Use as default:** If true, this variable's value will be used as the default value for any managed organizations without a defined value.
* **Organization ID:** (Optional) The ID of the organization.

**Output:** Returns an object containing the new variable details including the ID, name, value, organization ID, category, timestamps, associated organization, and more.

</details>

<details>

<summary>Create Template action</summary>

Lets you create a new template. Template actions are used to manage templates that exist at the organization level of the workflow in which you are building. This action won't work for child orgs of the workflow's organization.

**Parameters:**

* **Name:** The name of the template.
* **Description:** A brief description of the template.
* **Body:** The actual template content.
* **Content Type:** The type of content used in the template.
* **Language:** The language used in the template. Options include: `html`, `markdown`, `powershell`, `python`, `yaml`.

**Output:** The action returns the newly created template's information, including its `id`.

</details>

<details>

<summary>Delete Organization Variable action</summary>

Deletes a specific organization variable for a selected organization using the variable's name.

**Parameters:**

* **Organization ID:** The ID of an organization.
* **Name:** The name of the organization variable to be deleted.

**Output:** Returns an object indicating the success of the operation, including the name of the deleted variable and the ID of the organization from which it was deleted.

</details>

<details>

<summary>Delete Template action</summary>

This action lets you delete an existing template. Template actions are used to manage templates that exist at the organization level of the workflow in which you are building. This action won't work for child orgs of the workflow's organization.

**Parameters:**

* **Template ID**: The ID of the template you wish to delete.

**Output:** The action does not return any specific output, but its execution status indicates whether the deletion was successful.

</details>

<details>

<summary>Delete User Invite action</summary>

Delete a user invite from your organization in Rewst.

**Parameters:**

* **Email:** Email address of the user invite to delete.

**Output:** The returned object shows the number of invites deleted.

</details>

<details>

<summary>Export Object action</summary>

The `rewst_export_object` task is a Rewst platform action that exports Rewst objects— workflows, triggers, forms, templates, sites, or pages— into a portable bundle format that can be shared, backed up, or imported into other Rewst environments. The exported bundle includes cryptographic signing to ensure the integrity and authenticity of the exported data.

**Parameters:**

* **object\_type** - required: The type of object to export
  * Options: workflow, trigger, form, template, site, page
* **object\_id** - required: The unique ID of the specific object to export
  * Uses a dynamic reference that populates available objects based on the selected object type

**Outputs:**

The action returns a bundle object containing:

* objects: A mapping of serializable keys to their serialized objects (the actual exported data)
* signing: Security verification details including:
  * cert: PEM-encoded X.509 public certificate for signature verification
  * hash: HMAC hashing algorithm name used for the signature
  * signature: base64-encoded signature for integrity verification
* version: Version number of the export bundle format
* exported\_at: Timestamp of when the bundle was created

**Use Cases:**

* Create portable backups of important workflows or other objects
* Move objects between different Rewst environments
* Share workflows or templates with other organizations
* Create snapshots of objects at specific points in time

</details>

<details>

<summary>Generic GraphQL request action</summary>

This action has its own separate documentation page [here](/documentation/automations/actions-in-rewst/generic-graphql-request-action).

</details>

<details>

<summary>Get External Reference action</summary>

This action facilitates the retrieval of details about the any external integration or manually set references. You can use it to fetch all external integration references associated with a specific organization in Rewst or to find the organization and workflow execution associated with a specific external reference ID. It runs under specified user credentials or default user, but requires organization ID for context.

**Parameters:**

* **org\_id:** ID of the organization in Rewst.
* **identifier:** Unique identifier of the external resource.
* **reference\_id:** Reference ID of the external resource.
* **run\_as\_user (optional):** Specify user credentials.

**Output:**

Returns detailed information about the external reference(s), such as the `org_id` in Rewst linked to it, the type of `identifier`, and the external `reference_id`. This information is helpful for cross-system data synchronization and management.

***

</details>

<details>

<summary>Get Form action</summary>

Retrieves details about a specific form in the system.

**Parameters:**

* **Name:** The name of the form.
* **ID:** The ID of the form.

**Output:** The action returns information about the specified form.

</details>

<details>

<summary>Get Microsoft CSP Customer action</summary>

Get data for a single Microsoft CSP customer in Rewst.

**Parameters:**

* **CSP Integration Configuration ID**: The ID of a Microsoft integration configuration in Rewst.

</details>

<details>

<summary>Get Organization action</summary>

Retrieve data for a single organization in Rewst.

**Parameters:**

* **Organization ID:** Identifier of the organization to fetch data for. This ID is unique for each organization within Rewst.

**Output:** Outputs the details of the organization, which includes the Organization ID, Domain, Name, Managing Organization ID, and Enabled Status.

</details>

<details>

<summary>Get Organization Variable action</summary>

Retrieves a specific organization variable for a selected organization using the variable's name or value.

**Parameters:**

* **Name:** (Optional) The name of the organization variable.
* **Organization ID:** (Optional) A dropdown list of the labels that correlate with the ID of an organization you'd like to retrieve.
* **Value:** (Optional) The value of the organization variable.

**Output:** Returns an object (or list of objects) representing the organization variable, including the ID, name, value, organization ID, category, timestamps, associated organization, and more.

</details>

<details>

<summary>Get Template action</summary>

Lets you retrieve the details of an existing template. Template actions are used to manage templates that exist at the organization level of the workflow in which you are building. This action won't work for child orgs of the workflow's organization.

**Parameters:**

* **Template ID**: The ID of the template you wish to retrieve.

**Output:** The action returns the requested template's information, including its `name`, `description`, `body`, `content_type`, and `language`.

</details>

<details>

<summary>Get Trigger action</summary>

Retrieves details about a specific trigger in the system.

**Parameters:**

* **Name:** The name of the trigger.
* **ID:** The ID of the trigger.
* **Enabled:** A boolean value that indicates whether the trigger is enabled or not.

**Output:** The action returns information about the specified trigger.

</details>

<details>

<summary>Get User action</summary>

Get user by email or ID in Rewst.

**Parameters:**

* **ID:** The ID of a user in Rewst.
* **Organization ID:** The ID of an organization in Rewst.
* **Email address:** The email of a user in Rewst.

**Output:** The returned object includes the user's details like ID, role, organization ID, assigned role IDs, username, and a boolean indicating superuser status.

</details>

<details>

<summary>Invite User to Rewst action</summary>

Invite a user to your organization in Rewst.

**Parameters:**

* **Email:** Email address of the user to invite.
* **Roles:** Role IDs to assign to user.

**Output:** The returned object includes the invite details such as ID, email, organization ID, assigned role IDs, a boolean indicating acceptance status, and the ID of the inviter.

</details>

<details>

<summary>Link Microsoft CSP Customer action</summary>

Link one or more Rewst organizations to a microsoft CSP customer in Microsoft

**Parameters:**

* **CSP Integration Configuration ID**: The ID of a Microsoft CSP integration configuration in Rewst.
* **Microsoft CSP Customer ID**: The ID of the Microsoft CSP Customer in Rewst that you want to link your organization or organizations to.
* **Organization IDs**: The list of Rewst organization IDs to link.

**Output:** The returned object lists a confirmation of the linked organizations

</details>

<details>

<summary>List Apps action</summary>

Lists all apps, also known as sites, associated with the current organization in Rewst.

**Parameters:**

* **Run as user - optional:** The ID of the user to run the query as. If omitted, defaults to the workflow's context user.

**Output:** Returns a list of apps, including details such as ID, name, and organization association.

</details>

<details>

<summary>List Forms action</summary>

Retrieves a list of all forms in the system.

**Parameters:** No parameters are required for this action.

**Output:** The action returns a list of all forms, each item including information about a form.

</details>

<details>

<summary>List Forms With Granular Permissions</summary>

The rewst\_list\_forms\_with\_granular\_permissions task retrieves a list of all forms in your Rewst organization that the specified user has permission to access, taking into account granular permission settings. If run\_as\_user is set to null, it will use the default organization user. This action is useful for building dynamic interfaces or workflows that need to work with forms based on user permissions, ensuring users only see forms they have access to.

**Parameters:**

run\_as\_user - required: The user ID that the action will run as. If not specified, the default user for your organization will be used.

**Outputs:**

The task returns an array of form objects, where each form contains:

| Field                | Type    | Description                                                                                  |
| -------------------- | ------- | -------------------------------------------------------------------------------------------- |
| **id**               | String  | Unique identifier for the form                                                               |
| **name**             | String  | Display name of the form                                                                     |
| **description**      | String  | Form description                                                                             |
| **org\_id**          | String  | Organization ID that owns the form                                                           |
| **created\_at**      | String  | Timestamp when the form was created                                                          |
| **updated\_at**      | String  | Timestamp when the form was last modified                                                    |
| **is\_synchronized** | Boolean | Whether the form is synchronized                                                             |
| **tags**             | Array   | List of tags associated with the form (each tag has `id` and `name`)                         |
| **triggers**         | Array   | List of triggers associated with the form (each trigger has `id`, `name`, and `workflow_id`) |

</details>

<details>

<summary>List Integrations For Organization action</summary>

This action retrieves a comprehensive list of integrations installed for a specific organization in Rewst, providing a detailed overview of each integration's attributes.

**Parameters:**

* **Organization ID:** The unique identifier for an organization in Rewst. This parameter is required to fetch the specific integration details pertinent to the organization.

**Output:**

The action generates a detailed list of integrations, including:

* **Integration ID, Name, and Reference:** Basic identifiers providing clarity on each integration.
* **Pack Configurations:** In-depth details of configurations applied to each integration, offering insights into their setup and customization.
* **Applied Triggers:** Information on workflow triggers linked to each integration, useful for understanding operational dynamics.
* **Foreign Object References:** Crucial data points that link integrations to external references, enhancing cross-platform data synchronization and management.

</details>

<details>

<summary>List Microsoft CSP Customer action</summary>

Get a list of Microsoft CSP customers in Rewst.

**Parameters:**

* **CSP Integration Configuration ID**: The ID of a Microsoft integration configuration in Rewst.
* **Microsoft CSP Customer ID**: The ID of the Microsoft CSP Customer in Rewst that you want to link your organization or organizations to.
* **Organization IDs**: The list of Rewst organization IDs to link.

</details>

<details>

<summary>List Organizations action</summary>

Fetch a list of all organizations in Rewst.

**Parameters:**

* Managing **Organization ID:** Identifier of the managing organization to fetch organizations for. This ID is unique for each organization within Rewst.
* Name (Optional): Name of the organization to search for. The name must be unique within Rewst.

**Output:** Outputs a list of organizations, each with its corresponding Organization ID, Domain, Name, Managing Organization ID, and Enabled Status.

</details>

<details>

<summary>List Organization Variables action</summary>

Lists all organization variables visible to the selected organization.

**Parameters:**

* **Organization ID:** (Optional) A dropdown list of the labels that correlate with the ID (visible in the code editor window) of an organization you'd like to retrieve.

**Output:** Returns a list of objects. Each object represents an organization variable and includes the ID, name, value, organization ID, category, timestamps, associated organization, and more.

</details>

<details>

<summary>List Templates action</summary>

Lets you retrieve a list of all existing templates. Template actions are used to manage templates that exist at the organization level of the workflow in which you are building. This action won't work for child orgs of the workflow's organization.

**Parameters:** *No parameters are required for this action.*

**Output:** The action returns a list of all templates, with each entry including information about a template, such as its `id`, `name`, `description`, `body`, `content_type`, and `language`.

</details>

<details>

<summary>List Triggers action</summary>

Retrieves a list of all triggers in the system.

**Parameters:** No parameters are required for this action.

**Output:** The action returns a list of all triggers, each item including information about a trigger.

</details>

<details>

<summary>List User Invites to Rewst action</summary>

Get user invite list by your organization in Rewst.

**Parameters:** *No parameters needed for this action.*

**Output:** The returned list includes a list of user invite objects. Each object contains the invite's ID, email, organization ID, assigned role IDs, a boolean indicating acceptance status, and the ID of the inviter.

</details>

<details>

<summary>List Users by Organization action</summary>

Get user list and optionally invited users by your organization in Rewst.

**Parameters**:

* **Include User Invites?:** Whether or not to include user invites in the results.
* **Which Invites:** Which invitees to include. Can be `all`, `accepted`, or `pending`.

**Output**: A list of users with details like ID, role, organization ID, assigned role IDs, username, and a boolean indicating superuser status.

</details>

<details>

<summary>List Workflows actions</summary>

This action retrieves a comprehensive list of all workflows in your Rewst organization, giving you visibility into your automation library. This action is particularly useful for workflow management tasks, reporting, and as a starting point for more complex workflow operations that require workflow IDs.

**Parameters:**

* `run_as_user` (optional): Specifies which user the action should run as. If not provided, it uses your organization's default user.

**Output:**

The action returns detailed information for each workflow:

* `id`: Unique workflow identifier
* `name`: The workflow's display name
* `tags`: Array of tags assigned to the workflow
* `org_id`: Organization ID where the workflow belongs
* `triggers`: Array of associated triggers for the workflow
* `created_at`: Timestamp when the workflow was created
* `updated_at`: Timestamp of the last modification
* `organization`: Detailed organization information
* `unpacked_from`: Template source information (if the workflow was created from a template)
* `cloned_from_id`: Source workflow ID (if the workflow was cloned from another)

**Common use cases:**

* Workflow Inventory: Get a complete overview of all workflows in your organization
* Trigger Analysis: Identify which workflows have active triggers
* Workflow Management: Use the returned workflow IDs for subsequent operations on specific workflows
* Organizational Reporting: Generate reports on workflow usage and organization

{% hint style="info" %}
Note that this action won't return workflow notes. To retrieve that information, use the [Rewst - Generic GraphQL Request](#generic-graphql-request-action) action to query `workflowNotes` .
{% endhint %}

</details>

<details>

<summary>List Workflow Executions With Time Savings action</summary>

The `rewst_list_workflow_executions_with_time_savings` task is an action from the Rewst integration that lists workflow executions with calculated time savings data. This action retrieves execution data and calculates how much time has been saved through automation. It provides comprehensive analytics about workflow performance and efficiency.

* Retrieves execution data including total executions, seconds saved, workflow names, and organization information
* Calculates time savings for automated workflows
* Filters executions by date, status, and organization
* Groups results either by individual workflow or by sub-organization

**Parameters:**

* **`updated_at`** (required): Include any executions updated after this date (datetime format)
* **`workflow_status`** (optional): Filter by execution status (`succeeded`, `failed`, or `running`)
* **`group_by_sub_org`** (optional): Choose whether to group results by sub-organization (default: false, groups by workflow)
* **`run_as_user`** (optional): The user that the action will run as

**Output:**

The action returns data including:

* `ran_for_org`: Organization identifier
* `workflow_id`: Unique workflow identifier
* `seconds_saved`: Calculated time savings in seconds
* `workflow_name`: Name of the workflow
* `total_executions`: Total number of executions

</details>

<details>

<summary>Unlink Microsoft CSP Customer action</summary>

Unlink one or more Rewst organizations from a Microsoft CSP customer in Rewst.

**Parameters:**

* **CSP Integration Configuration ID**: The ID of a Microsoft integration configuration in Rewst.
* **Microsoft CSP Customer ID**: The ID of the Microsoft CSP Customer in Rewst that you want to link your organization or organizations to.
* **Organization IDs**: The list of Rewst organization IDs to link.

**Output:** The returned object lists a status for the unlink action

***

</details>

<details>

<summary>Update Organization action</summary>

Update details of an existing organization within Rewst.

**Parameters:**

* **Organization ID:** Identifier of the organization to be updated. This ID is unique for each organization within Rewst.
* Name (Optional): New name for the organization. This name must be unique within Rewst.
* Domain (Optional): New domain for the organization, excluding protocol.
* Is Enabled (Optional): Updated enabled status for the organization. It is a boolean value.

**Output:** Outputs the updated details of the organization, which includes the Organization ID, Domain, Name, Managing Organization ID, and Enabled Status.

</details>

<details>

<summary>Update Template action</summary>

This action lets you update the details of an existing template. Template actions are used to manage templates that exist at the organization level of the workflow in which you are building. This action won't work for child orgs of the workflow's organization.

**Parameters:**

* **Template ID:** The ID of the template you wish to update, it is a required field.
* **Body:** The new content of the template.
* **Content Type:** The new type of content used in the template. The options are `message` and `script`.
* **Description:** A brief description of the template.
* **Language:** The new language used in the template. The options include: `html`, `markdown`, `powershell`, `python`, `yaml`.

**Output:** The action returns the updated template's information, including its `id`.

</details>

<details>

<summary>Update Trigger action</summary>

The rewst\_update\_trigger task is used to modify existing workflow triggers within the Rewst platform. This action allows you to update properties of a trigger such as its name, enabled status, description, and the user it runs as. This task is particularly useful for dynamically managing trigger states within workflows, such as enabling ordisabling triggers based on certain conditions or updating trigger configurations programmatically.

**Parameters:**

* Trigger\_id - required: The ID of the trigger to be updated
* Name: New name for the trigger
* Enabled: Whether the trigger should be enabled or disabled
* Description: New description for the trigger
* Run\_as\_user: The user ID that the trigger will run as (defaults to organization default user if not specified)

**Outputs:**

The action returns an object containing the updated trigger information:

* ID: The trigger ID
* Name: The trigger name
* Enabled: Whether the trigger is enabled or not
* Description: The trigger description
* Criteria: The trigger criteria
* Parameters: The trigger parameters
* Workflow\_ID: The associated workflow ID
* Form: Form configuration objects
* TriggerType: Trigger type information
* Organization: Organization information
* ActivatedForOrgs: Organizations where the trigger is activated

</details>

## App Builder-specific Rewst actions

{% hint style="info" %}
These Rewst actions are for use with [App Builder](/documentation/app-builder) only. Don't use them for general workflow building on the Workflow Builder canvas.
{% endhint %}

<details>

<summary>List Pages action</summary>

Lists all pages for a specified app in Rewst.

**Parameters:**

* **App ID:** The ID of the app for which to fetch pages.
* **Run as user - optional:** The ID of the user to run the query as.

**Output:** Returns a list of pages within the specified app, including each page's ID, name, and metadata.

</details>

<details>

<summary>List Page Elements action</summary>

Lists all elements within a specific page in an app, including their Element IDs and key properties.

**Parameters:**

* **Page ID:** The ID of the page whose elements you want to retrieve.
* **Run as user - optional:** The ID of the user to run the query as.

**Output:** Returns a dictionary mapping element IDs to their properties, including type, Craft ID, and other element-specific details.

</details>

<details>

<summary>Update Text Element Content action</summary>

Updates the text-based content of a page element— such as a text block, button, link, HTML container, markdown block, or accordion— within a specified page.

**Parameters:**

* **Content:** The new text content to set for the element.
* **Page ID:** The ID of the page containing the element to update.
* **Element ID:** The ID of the page element whose text content you want to update.
* **Run as user - optional:** The ID of the user to run the query as.

**Output:** Returns the updated element's details, including confirmation of the new text content.

</details>


# Generic GraphQL request action

## What is GraphQL?

{% hint style="info" %}
Learn more about GraphQL in its official documentation [here](https://graphql.org/learn/introduction/).
{% endhint %}

GraphQL is an open-source query language for APIs and a server-side runtime for fulfilling those queries. It enables clients to interact with a single endpoint to get the exact data they need, without chaining requests together. Unlike traditional REST APIs that return fixed datasets, GraphQL allows clients to request specific data, eliminating over-fetching or under-fetching of data and offering improved efficiency. The [GraphQL Schema](https://graphql.org/learn/schema/) defines the structure of the data and available operations, serving as a clear contract between the frontend and backend. Like REST APIs, GraphQL is composed of a basic request and response for each call. While REST APIs rely on multiple endpoints for this process, GraphQL shifts the responsibility of defining what should be called back to the user.

GraphQL in Rewst works off of two *operation types*:

1. Query: Used for reading or fetching data
2. Mutation: Used for writing, updating, or deleting data

{% hint style="info" %}
GraphQL has a third operation type called subscription. Rewst's generic GraphQL action currently only supports queries and mutations. If there is a subscription you are looking to use in Rewst, please submit a request to our product team for a dedicated action.
{% endhint %}

## What is the Rewst GraphQL generic request action?

{% hint style="warning" %}
Before using the Generic GraphQL request action, we recommend that you have:

* An understanding of GraphQL query structure and syntax
* Familiarity with Rewst's data model and the below available schema documentation
  {% endhint %}

\
The Rewst GraphQL generic request action is used for making authenticated requests against Rewst's GraphQL API. This action is available in the Rewst actions section of the Workflow Builder's actions library, but is open-ended in its capabilities. It enables:

* Direct API access: Execute custom GraphQL queries and mutations against Rewst's backend
* Advanced data retrieval: Access data structures not available through standard actions
* Custom automation: Build sophisticated workflows with precise data control
* Administrative operations: Perform bulk operations and administrative tasks programmatically

<figure><img src="/files/o1kaA56ibM8qBjfz8Gm6" alt=""><figcaption></figcaption></figure>

Make your choices in the **Parameters** tab of the action's settings to set it up in your workflow:

* **Operation type**: Choose the type of GraphQL operation, **query** or **mutation**
* **Graph operation**: The name of the specific GraphQL operation to execute
  * Uses the Graph Operations reference
  * Options in the drop-down list will dynamically populate based on your selected operation type
* **Variable values**: Variables to pass to the GraphQL operation
  * JSON object type, but can be passed via Jinja
  * Contains the input parameters for the selected operation
* **Response fields**: Enter text into this field to specify the fields to include in the GraphQL response
  * Only provide the inner content, as it will be wrapped in curly braces
  * Example, `id orgName email { name }`
* **Raw query**: The complete raw GraphQL query string to execute
  * An advanced alternative to using the other fields and selectors in the Parameters tab
  * Allows for full control over query structure

## Filtering arguments: Where versus search

Every plural list query in the Generic GraphQL Request action accepts up to two filtering arguments: *where* and *search*. They are not interchangeable.

#### Where: Equality only - `field: value` → `WHERE field = value`

`where` accepts a flat object of `field: value` pairs. Each pair is rendered as `WHERE field = value`. There's no way to express greater than, in this list, contains substring, etc. through `where`.

The set of fields exposed in each `<Object>WhereInput` type is hand-curated by Rewst engineering, not auto-derived from the GraphQL model. That is why `Tags` exposes `id`, `name`, `orgId` for filtering but not `color` or `description`, even though those columns exist on the model.

#### Search: Accepts operator wrappers

`search` accepts a `<Object>SearchInput` type whose fields are wrapped in *comparison expressions*. The wrapper type depends on the column type:

| Wrapper                 | Operators supported                                                                                           |
| ----------------------- | ------------------------------------------------------------------------------------------------------------- |
| `id_comparison_exp`     | `_eq`, `_ne`, `_in`, `_nin`                                                                                   |
| `string_comparison_exp` | `_eq`, `_neq`, `_in`, `_nin`, `_like`, `_nlike`, `_ilike`, `_nilike`, `_substr`, `_lt`, `_lte`, `_gt`, `_gte` |
| `int_comparison_exp`    | `_eq`, `_neq`, `_in`, `_nin`, `_lt`, `_lte`, `_gt`, `_gte`                                                    |
| `float_comparison_exp`  | `_eq`, `_neq`, `_in`, `_nin`, `_lt`, `_lte`, `_gt`, `_gte`                                                    |
| `bool_comparison_exp`   | `_eq`, `_ne`                                                                                                  |
| `json_comparison_exp`   | `_eq`, `_ne`, `_contains`                                                                                     |

Use `search` whenever you need anything other than strict equality, or any time the field you want to filter on isn't exposed by `where`.

Example: `isEnabled` is not on `OrganizationWhereInput`, but it **is** on `OrganizationSearchInput`.

## Generic GraphQL request action usage examples

### Basic query example

```yaml
operation_type: "query"
operation: "organizations"
variable_values: 
  limit: 50
  order: [["name"]]
fields: "id, name, domain, isEnabled"
```

### Mutation example

```yaml
operation_type: "mutation"
operation: "createOrgVariable"
variable_values:
  orgVariable:
    name: "custom_setting"
    value: "production"
    orgId: "{{ CTX.organization.id }}"
    category: "general"
fields: "id, name, value, category"
```

### Raw query example

```yaml
raw_query: |
  query GetWorkflowDetails($workflowId: ID!) {
    workflow(where: {id: $workflowId}) {
      id
      name
      description
      tasks {
        id
        name
        action {
          name
          pack {
            name
          }
        }
      }
    }
  }
variable_values:
  workflowId: "{{ CTX.workflow_id }}"
```

### Tag example

```graphql
tags(
  where: TagWhereInput
  search: TagSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
  includeTagsWithNoOwner: Boolean = false
): [Tag!]!  @requiresManagesOwningOrg
```

## Generic GraphQL request action: Allowed operations

{% hint style="info" %}

### Schema reference

Key entity types include:

* Organization: Core organizational data and settings
* Workflow: Automation workflow definitions and execution data
* Action: Available actions and their configurations
* Trigger: Event triggers and their configurations
* Form: Dynamic forms and field definitions
* Template: Reusable templates and scripts
* User: User accounts and permissions
* Pack: Integration packs and their components
  {% endhint %}

{% hint style="success" %}
Each of the query expanders below contains information that includes if where or search are mandatory for use of the query. Be sure to reference this information and use your query accordingly.
{% endhint %}

### Operation type: Queries

#### **Action and configuration queries**

<details>

<summary><strong><code>actionOption</code> -</strong> Retrieves a specific action option configuration.</summary>

**GraphQL schema**

```graphql
actionOption(where: ActionOptionWhereInput): ActionOption

type ActionOption {
  actions: [Action!]
  id: ID
  optionLabel: String
  optionValue: String
  organizationId: ID
  organization: Organization
  packConfigId: ID
  resourceName: String
  packConfig: PackConfig
}
```

**`ActionOptionWhereInput` supported fields**

| Field            | Type                            |
| ---------------- | ------------------------------- |
| `optionLabel`    | `String`                        |
| `optionValue`    | `String`                        |
| `organizationId` | `ID`                            |
| `packConfigId`   | `ID`                            |
| `packConfig`     | `PackConfigWhereInput` (nested) |
| `resourceName`   | `String`                        |

**Is** `where` **or** `search` **mandatory?**

Yes: `where` with enough fields to identify a single row — typically `packConfigId` plus `optionValue` or `optionLabel`. The parent `packConfig` must belong to an organization that you manage. No `search` input is needed.

**Usage example**

```yaml
operation_type: "query"
operation: "actionOption"
variable_values:
  where:
    packConfigId: "{{ CTX.pack_config_id }}"
    optionLabel: "environment"
fields: "id, optionLabel, optionValue, resourceName"
```

</details>

<details>

<summary><strong><code>actionOptions</code></strong>-Retrieves multiple action options with filtering and sorting.</summary>

**GraphQL schema**

```graphql
actionOptions(
  where: ActionOptionWhereInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["optionLabel"]]
): [ActionOption!]!
```

**`ActionOptionWhereInput` supported fields**

| Field            | Type                            |
| ---------------- | ------------------------------- |
| `optionLabel`    | `String`                        |
| `optionValue`    | `String`                        |
| `organizationId` | `ID`                            |
| `packConfigId`   | `ID`                            |
| `packConfig`     | `PackConfigWhereInput` (nested) |
| `resourceName`   | `String`                        |

**Is where or search mandatory?**

Yes: `where: { packConfigId: <id> }` (or `organizationId`) plus `limit`/`offset`. The parent `packConfig` must belong to an organization that you manage.

No `search` input required— only equality filtering via `where`.

**Usage example**

```yaml
operation_type: "query"
operation: "actionOptions"
variable_values:
  where:
    organizationId: "{{ CTX.org_id }}"
  limit: 50
  order: [["optionLabel", "asc"]]
fields: "id, optionLabel, optionValue, organization { name }"
```

</details>

<details>

<summary><strong><code>localReferenceOptions</code></strong>-Gets dropdown options for picking another Rewst object such as a workflow, template or form, inside a parameter</summary>

**GraphQL schema**

```graphql
localReferenceOptions(
  modelName: LocalReferenceModel!
  orgId: ID!
  filterArg: JSON
): [DropdownOption!]!

enum LocalReferenceModel {
  Crate
  CustomDatabase
  Organization
  PackConfig
  Role
  Template
  TemplateExport
  User
  Workflow
  Trigger
  Form
  Site
  Page
}

type DropdownOption {
  label: String
  value: String
}
```

**Is where or search mandatory?**

Yes: required `modelName` and `orgId`

Note: `search` here is a plain string matched against the option label, not a `SearchInput` with operator wrappers.

**Usage example**

```yaml
operation_type: "query"
operation: "localReferenceOptions"
variable_values:
  modelName: "Workflow"
  orgId: "{{ CTX.org_id }}"
  filterArg: {"enabled": true}
fields: "label, value"
```

</details>

<details>

<summary><strong><code>resourceTypesByPack</code></strong>-Gets resource types organized by pack.</summary>

**GraphQL schema**

```graphql
resourceTypesByPack: [PackResourceTypesContainer!]!

type PackResourceTypesContainer {
  id: ID!
  packName: String!
  resourceTypes: [String!]!
}
```

**Is where or search mandatory?**

No - takes no `where`, `search`, or pagination.

</details>

#### **Action management queries**

<details>

<summary><strong><code>action</code></strong>-Retrieves a specific action definition.</summary>

**GraphQL schema**

```graphql
action(where: ActionInput, search: ActionSearch): Action

type Action {
  actionOptions: [ActionOption!]!
  className: String
  defaultHumanSecondsSaved: Int
  deprecated: Boolean
  deprecationMessage: String
  description: String
  enabled: Boolean
  entryPoint: String
  category: String
  hidden: Boolean
  icon: String
  id: ID
  name: String
  organization: Organization
  orgId: ID
  outputSchema: JSON
  pack(where: PackInput): Pack
  packId: ID!
  parameters(populateOptions: Boolean = true): JSON
  ref: String
  runner: Runner
  uid: ID
  visibleForOrganizations: [Organization!]!
  workflow: Workflow
}
```

**`ActionInput` (where) supported fields**

| Field          | Type                 |
| -------------- | -------------------- |
| `runner_type`  | `String`             |
| `deprecated`   | `Boolean`            |
| `description`  | `String`             |
| `enabled`      | `Boolean`            |
| `hidden`       | `Boolean`            |
| `id`           | `ID`                 |
| `name`         | `String`             |
| `category`     | `String`             |
| `outputSchema` | `JSON`               |
| `pack`         | `PackInput` (nested) |
| `packId`       | `ID`                 |
| `parameters`   | `JSON`               |
| `ref`          | `String`             |
| `uid`          | `ID`                 |

**`ActionSearch` supported fields**

| Field          | Wrapper                    |
| -------------- | -------------------------- |
| `deprecated`   | `bool_comparison_exp`      |
| `description`  | `string_comparison_exp`    |
| `enabled`      | `bool_comparison_exp`      |
| `hidden`       | `bool_comparison_exp`      |
| `id`           | `id_comparison_exp`        |
| `name`         | `string_comparison_exp`    |
| `outputSchema` | `json_comparison_exp`      |
| `parameters`   | `json_comparison_exp`      |
| `ref`          | `string_comparison_exp`    |
| `uid`          | `id_comparison_exp`        |
| `category`     | `string_comparison_exp`    |
| `pack`         | `PackSearchInput` (nested) |

**Is** `where` **or** `search` **mandatory?**

`where` or `search` narrow enough to match a single action — typically `id`, or `packId` + `ref`. Note: `ActionInput` is the where-input despite the name. It's reused as the create/update input.

**Usage example**

```yaml
operation_type: "query"
operation: "action"
variable_values:
  where:
    ref: "http_request"
    packId: "core"
fields: "id, name, description, parameters, outputSchema"
```

</details>

<details>

<summary><strong><code>actions</code></strong>-Retrieves multiple actions with filtering.</summary>

**GraphQL schema**

```graphql
actions(
  where: ActionInput
  search: ActionSearch
  limit: Int = 100
  offset: Int
  order: [[String!]!] = [["name"]]
): [Action!]!
```

**`ActionInput` (where) supported fields**

| Field          | Type                 |
| -------------- | -------------------- |
| `runner_type`  | `String`             |
| `deprecated`   | `Boolean`            |
| `description`  | `String`             |
| `enabled`      | `Boolean`            |
| `hidden`       | `Boolean`            |
| `id`           | `ID`                 |
| `name`         | `String`             |
| `category`     | `String`             |
| `outputSchema` | `JSON`               |
| `pack`         | `PackInput` (nested) |
| `packId`       | `ID`                 |
| `parameters`   | `JSON`               |
| `ref`          | `String`             |
| `uid`          | `ID`                 |

**`ActionSearch` supported fields**

| Field          | Wrapper                    |
| -------------- | -------------------------- |
| `deprecated`   | `bool_comparison_exp`      |
| `description`  | `string_comparison_exp`    |
| `enabled`      | `bool_comparison_exp`      |
| `hidden`       | `bool_comparison_exp`      |
| `id`           | `id_comparison_exp`        |
| `name`         | `string_comparison_exp`    |
| `outputSchema` | `json_comparison_exp`      |
| `parameters`   | `json_comparison_exp`      |
| `ref`          | `string_comparison_exp`    |
| `uid`          | `id_comparison_exp`        |
| `category`     | `string_comparison_exp`    |
| `pack`         | `PackSearchInput` (nested) |

**Is** `where` **or** `search` **mandatory?**

`limit` (defaults to 100) and `offset`. Scope by `packId` (`where: { packId: <id> }`) or by `pack` (`search: { pack: { id: { _eq: <id> } } }`) when possible — unscoped calls return every action visible to your managed orgs.

</details>

<details>

<summary><strong><code>actionsForOrg</code></strong>-Gets actions available to a specific organization.</summary>

**GraphQL schema**

```graphql
actionsForOrg(
  where: ActionInput
  search: ActionSearch
  limit: Int = 100
  offset: Int
  order: [[String!]!] = [["name"]]
  orgId: ID
): [Action!]!
```

**`ActionInput` (where) supported fields**

| Field          | Type                 |
| -------------- | -------------------- |
| `runner_type`  | `String`             |
| `deprecated`   | `Boolean`            |
| `description`  | `String`             |
| `enabled`      | `Boolean`            |
| `hidden`       | `Boolean`            |
| `id`           | `ID`                 |
| `name`         | `String`             |
| `category`     | `String`             |
| `outputSchema` | `JSON`               |
| `pack`         | `PackInput` (nested) |
| `packId`       | `ID`                 |
| `parameters`   | `JSON`               |
| `ref`          | `String`             |
| `uid`          | `ID`                 |

**`ActionSearch` supported fields**

| Field          | Wrapper                    |
| -------------- | -------------------------- |
| `deprecated`   | `bool_comparison_exp`      |
| `description`  | `string_comparison_exp`    |
| `enabled`      | `bool_comparison_exp`      |
| `hidden`       | `bool_comparison_exp`      |
| `id`           | `id_comparison_exp`        |
| `name`         | `string_comparison_exp`    |
| `outputSchema` | `json_comparison_exp`      |
| `parameters`   | `json_comparison_exp`      |
| `ref`          | `string_comparison_exp`    |
| `uid`          | `id_comparison_exp`        |
| `category`     | `string_comparison_exp`    |
| `pack`         | `PackSearchInput` (nested) |

**Is** `where` **or** `search` **mandatory?**

`orgId` plus `limit`/`offset`. Use this instead of `actions` when you want the action list as it appears for one specific org.

</details>

#### **System and debug queries**

<details>

<summary><strong><code>announcement</code></strong>-Gets system announcements.</summary>

</details>

<details>

<summary><strong><code>debug-</code></strong>Debug endpoint for system information.</summary>

**GraphQL schema:**

```graphql
debug: Boolean
```

</details>

#### **Component management queries**

<details>

<summary><strong><code>component</code></strong>-Retrieves a specific component definition.</summary>

**GraphQL schema**

```graphql
component(id: ID!): Component

type Component {
  id: ID!
  orgId: ID!
  name: String!
  description: String
  currentVersion: Int
  createdBy: User
  createdById: ID
  createdAt: String
  updatedAt: String
  versions: [ComponentVersion!]
  updatedBy: User
  updatedById: ID
}
```

**Is** `where` **or** `search` **mandatory?**

No - identified directly by `id`.

</details>

<details>

<summary><strong><code>components</code></strong>-Gets multiple components for an organization.</summary>

**GraphQL schema**

```graphql
components(orgId: ID!): [Component]
```

**Is** `where` **or** `search` **mandatory?**

No - scoped solely by `orgId`. Filter client-side or use `componentsByRoots` for specific IDs.

</details>

<details>

<summary><strong><code>componentsByRoots</code></strong>-Gets components by their root IDs.</summary>

**GraphQL schema**

```graphql
componentsByRoots(rootIds: [ID]!): [Component]
```

**Is** `where` **or** `search` **mandatory?**

No - identified by `rootIds` list.

</details>

<details>

<summary><strong><code>componentTree</code></strong>-Gets the component tree structure.</summary>

**GraphQL schema**

```graphql
componentTree(id: ID!): ComponentTree

type ComponentTree {
  encoded: String!
  component: Component!
  orgId: ID!
  versionNumber: Int
  createdAt: String
  updatedAt: String
  updatedBy: User
}
```

**Is** `where` **or** `search` **mandatory?**

No - identified by `id` and returns the latest version's tree.

</details>

#### **Crate management queries**

<details>

<summary><strong><code>crate</code></strong>-Retrieves a specific crate.</summary>

**GraphQL schema**

```graphql
crate(
  where: CrateWhereInput
  search: CrateSearchInput
  selectedOrgId: ID
): Crate

type Crate {
  associatedPacks: [Pack!]
  category: String
  crateTriggers: [CrateTrigger!]
  createdAt: String
  description: String
  id: ID!
  isPublic: Boolean!
  isUnpackedForSelectedOrg: Boolean
  lastPublishedAt: String
  maturity: CrateMaturity
  name: String!
  orgId: ID!
  primaryPack: Pack
  primaryPackId: ID
  providedValue: String
  replicationRegions: [CrateReplicationRegion!]
  requiredOrgVariables: [String!]
  setupAssistance: Boolean
  setupTime: Int
  sourceEnvironment: String
  status: CrateStatus!
  tags: [Tag!]
  tagIds: [ID!]
  tokens: [CrateToken!]!
  triggers: [Trigger!]
  unpackingCount: Int
  unpackedWorkflowId: ID
  updatedAt: String
  workflow: Workflow
  workflowId: ID
  gid: ID
  updatedById: ID
  createdById: ID
}
```

**`CrateWhereInput` supported fields**

| Field             | Type                          |
| ----------------- | ----------------------------- |
| `description`     | `String`                      |
| `id`              | `ID`                          |
| `lastPublishedAt` | `String`                      |
| `name`            | `String`                      |
| `orgId`           | `ID`                          |
| `primaryPack`     | `PackWhereInput` (nested)     |
| `status`          | `String`                      |
| `tokens`          | `JSON`                        |
| `workflow`        | `WorkflowWhereInput` (nested) |
| `workflowId`      | `ID`                          |
| `gid`             | `ID`                          |
| `isPublic`        | `Boolean`                     |

**`CrateSearchInput` supported fields**

| Field             | Wrapper                    |
| ----------------- | -------------------------- |
| `description`     | `string_comparison_exp`    |
| `id`              | `id_comparison_exp`        |
| `lastPublishedAt` | `string_comparison_exp`    |
| `name`            | `string_comparison_exp`    |
| `primaryPack`     | `PackSearchInput` (nested) |
| `tokens`          | `json_comparison_exp`      |
| `workflow`        | `WorkflowSearch` (nested)  |

**Is** `where` **or** `search` **mandatory?**

`where` or `search` narrow enough to match a single Crate — typically `id` or `gid`. Pass `selectedOrgId` to control the per-org `isUnpackedForSelectedOrg` flag.

</details>

<details>

<summary><strong><code>crates</code></strong>-Gets multiple crates with filtering and sorting.</summary>

**GraphQL schema**

```graphql
crates(
  where: CrateWhereInput
  search: CrateSearchInput
  selectedOrgId: ID
  limit: Int
  offset: Int
  order: [[String!]!] = [["unpackingCount", "desc"], ["createdAt", "asc"]]
): [Crate!]!
```

**`CrateWhereInput` supported fields**

| Field             | Type                          |
| ----------------- | ----------------------------- |
| `description`     | `String`                      |
| `id`              | `ID`                          |
| `lastPublishedAt` | `String`                      |
| `name`            | `String`                      |
| `orgId`           | `ID`                          |
| `primaryPack`     | `PackWhereInput` (nested)     |
| `status`          | `String`                      |
| `tokens`          | `JSON`                        |
| `workflow`        | `WorkflowWhereInput` (nested) |
| `workflowId`      | `ID`                          |
| `gid`             | `ID`                          |
| `isPublic`        | `Boolean`                     |

**`CrateSearchInput` supported fields**

| Field             | Wrapper                    |
| ----------------- | -------------------------- |
| `description`     | `string_comparison_exp`    |
| `id`              | `id_comparison_exp`        |
| `lastPublishedAt` | `string_comparison_exp`    |
| `name`            | `string_comparison_exp`    |
| `primaryPack`     | `PackSearchInput` (nested) |
| `tokens`          | `json_comparison_exp`      |
| `workflow`        | `WorkflowSearch` (nested)  |

**Is** `where` **or** `search` **mandatory?**

`limit` and `offset`, plus a scoping filter — typically `where: { orgId: <id> }`, `where: { isPublic: true }`, or `search: { name: { _ilike: "%foo%" } }`. Unscoped calls are slow.

</details>

<details>

<summary><strong><code>crateExportInfo</code></strong>-Gets export information for a workflow to crate.</summary>

**GraphQL schema**

```graphql
crateExportInfo(workflowId: ID!): JSON
```

**Is** `where` **or** `search` **mandatory?**

No - `workflowId` returns an unstructured JSON blob.

</details>

<details>

<summary><strong><code>crateTokenTypes</code></strong>-Gets available crate token types.</summary>

**GraphQL schema**

```graphql
crateTokenTypes: [String!]!
```

**Is** `where` **or** `search` **mandatory?**

No - Returns values like `text`, `linebreak`, `selectVar`, `inputVar`, `selectPackVar`, etc.

</details>

<details>

<summary><strong><code>crateUnpackingArgumentSet</code></strong>-Gets crate unpacking argument sets.</summary>

**GraphQL schema**

```graphql
crateUnpackingArgumentSet(
  where: CrateUnpackingArgumentSetWhereInput
): CrateUnpackingArgumentSet

type CrateUnpackingArgumentSet {
  arguments: [CrateUnpackingArgument!]!
  crate: Crate!
  crateId: ID!
  crateTriggerUnpackings: [CrateTriggerUnpacking!]!
  createdAt: String!
  createdBy: User!
  createdById: ID!
  humanSecondsSaved: Int!
  id: ID!
  orgId: ID!
  updatedAt: String
  updatedBy: User
  updatedById: ID
  workflowName: String!
}
```

**`CrateUnpackingArgumentSetWhereInput` supported fields**

| Field     | Type |
| --------- | ---- |
| `crateId` | `ID` |
| `id`      | `ID` |
| `orgId`   | `ID` |

**Is** `where` **or** `search` **mandatory?**

Yes - `where` narrow enough to match a single set — typically `id`, or `crateId` + `orgId`. No search input is needed.

</details>

#### **Feature preview queries**

<details>

<summary><strong><code>featurePreviewSetting</code></strong>-Gets a specific feature preview setting.</summary>

**GraphQL schema**

```graphql
featurePreviewSetting(where: FeaturePreviewSettingWhereInput): FeaturePreviewSetting

type FeaturePreviewSetting {
  description: String!
  id: ID!
  isStaffOnly: Boolean!
  label: String!
}
```

**`FeaturePreviewSettingWhereInput` supported fields**

| Field   | Type     |
| ------- | -------- |
| `id`    | `ID`     |
| `label` | `String` |

**Is** `where` **or** `search` **mandatory?**

Yes - at least one of `id` or `label` on `where`. No search input is needed.

</details>

<details>

<summary><strong><code>featurePreviewSettings</code></strong>-Gets multiple feature preview settings.</summary>

**GraphQL schema**

```graphql
featurePreviewSettings(
  where: FeaturePreviewSettingWhereInput,
  order: [[String!]!] = [["createdAt"]]
): [FeaturePreviewSetting]
```

**Is** `where` **or** `search` **mandatory?**

No - no `search` input, no `limit`/`offset` . The table is small and unpaginated.

</details>

#### **Foreign object reference queries**

<details>

<summary><strong><code>foreignObjectReference</code></strong>-Gets a specific foreign object reference.</summary>

**GraphQL schema**

```graphql
foreignObjectReference(
  where: ForeignObjectReferenceWhereInput
): ForeignObjectReference

type ForeignObjectReference {
  action: Action
  actionId: ID
  id: ID!
  identifier: ID
  organization: Organization!
  orgId: ID!
  packConfig: PackConfig
  packConfigId: ID
  referenceId: ID!
  workflowExecution: WorkflowExecution
  workflowExecutionId: ID
}
```

**`ForeignObjectReferenceWhereInput` supported fields**

| Field               | Type                                   |
| ------------------- | -------------------------------------- |
| `id`                | `ID`                                   |
| `referenceId`       | `ID`                                   |
| `identifier`        | `ID`                                   |
| `workflowExecution` | `WorkflowExecutionWhereInput` (nested) |
| `action`            | `ActionInput` (nested)                 |
| `actionId`          | `ID`                                   |
| `packConfig`        | `PackConfigWhereInput` (nested)        |
| `packConfigId`      | `ID`                                   |
| `orgId`             | `ID`                                   |

**Is** `where` **or** `search` **mandatory?**

Yes - For `where`, at least one filter — typically `id`, or `referenceId` + `orgId`. No search input is needed.

</details>

<details>

<summary><strong><code>foreignObjectReferences</code></strong>-Gets multiple foreign object references.</summary>

**GraphQL schema**

```graphql
foreignObjectReferences(
  where: ForeignObjectReferenceWhereInput
): [ForeignObjectReference!]!
```

**`ForeignObjectReferenceWhereInput` supported fields**

| Field               | Type                                   |
| ------------------- | -------------------------------------- |
| `id`                | `ID`                                   |
| `referenceId`       | `ID`                                   |
| `identifier`        | `ID`                                   |
| `workflowExecution` | `WorkflowExecutionWhereInput` (nested) |
| `action`            | `ActionInput` (nested)                 |
| `actionId`          | `ID`                                   |
| `packConfig`        | `PackConfigWhereInput` (nested)        |
| `packConfigId`      | `ID`                                   |
| `orgId`             | `ID`                                   |

**Is** `where` **or** `search` **mandatory?**

No `search` input and no `limit`/`offset` — scope with `where: { orgId: <id> }` to avoid pulling cross-organization rows.

</details>

#### **Form management queries**

<details>

<summary><strong><code>form</code></strong>-Retrieves a specific form definition, gets a single form.</summary>

**GraphQL schema**

```graphql
form(
  where: FormWhereInput
  search: FormSearchInput
  orgContextId: ID
): Form

type Form {
  clonedFrom: Form
  clonedFromId: ID
  cloneOverrides: JSON
  clones: [Form]
  createdBy: User
  createdById: ID
  createdAt: String
  description: String
  fields(orgContextId: ID): [FormField]
  id: ID!
  isSynchronized: Boolean
  name: String!
  organization: Organization!
  orgId: ID!
  tags: [Tag!]!
  triggers: [Trigger!]
  unpackedFrom: Crate
  unpackedFromId: ID
  updatedAt: String
  updatedBy: User
  updatedById: ID
  warrant: Warrant
}
```

**`FormWhereInput` — supported fields**

| Field            | Type                         |
| ---------------- | ---------------------------- |
| `clonedFromId`   | `ID`                         |
| `id`             | `ID`                         |
| `isSynchronized` | `Boolean`                    |
| `name`           | `String`                     |
| `orgId`          | `ID`                         |
| `triggers`       | `TriggerWhereInput` (nested) |
| `triggerId`      | `[ID]`                       |
| `unpackedFromId` | `ID`                         |

**`FormSearchInput` — supported fields**

| Field            | Wrapper                            |
| ---------------- | ---------------------------------- |
| `clonedFromId`   | `id_comparison_exp`                |
| `createdBy`      | `UserSearchInput` (nested)         |
| `id`             | `id_comparison_exp`                |
| `isSynchronized` | `bool_comparison_exp`              |
| `name`           | `string_comparison_exp`            |
| `organization`   | `OrganizationSearchInput` (nested) |
| `organizationId` | `id_comparison_exp`                |
| `triggerId`      | `id_comparison_exp`                |
| `unpackedFromId` | `id_comparison_exp`                |
| `updatedBy`      | `UserSearchInput` (nested)         |

**Is** `where` **or** `search` **mandatory?**

Yes - At least one filter is needed, identifying a single form - typically `id` on `where`.

</details>

<details>

<summary><strong><code>forms</code></strong>-Gets multiple forms with filtering.</summary>

**GraphQL schema**

```graphql
forms(
  where: FormWhereInput
  search: FormSearchInput
  limit: Int
  offset: Int
  hasTagIds: [ID]
  order: [[String!]!] = [["name"]]
): [Form!]!
```

**`FormWhereInput` — supported fields**

| Field            | Type                         |
| ---------------- | ---------------------------- |
| `clonedFromId`   | `ID`                         |
| `id`             | `ID`                         |
| `isSynchronized` | `Boolean`                    |
| `name`           | `String`                     |
| `orgId`          | `ID`                         |
| `triggers`       | `TriggerWhereInput` (nested) |
| `triggerId`      | `[ID]`                       |
| `unpackedFromId` | `ID`                         |

**`FormSearchInput` — supported fields**

| Field            | Wrapper                            |
| ---------------- | ---------------------------------- |
| `clonedFromId`   | `id_comparison_exp`                |
| `createdBy`      | `UserSearchInput` (nested)         |
| `id`             | `id_comparison_exp`                |
| `isSynchronized` | `bool_comparison_exp`              |
| `name`           | `string_comparison_exp`            |
| `organization`   | `OrganizationSearchInput` (nested) |
| `organizationId` | `id_comparison_exp`                |
| `triggerId`      | `id_comparison_exp`                |
| `unpackedFromId` | `id_comparison_exp`                |
| `updatedBy`      | `UserSearchInput` (nested)         |

**Is** `where` **or** `search` **mandatory?**

`limit` and `offset`.

Note: `forms` runs SpiceDB permission filtering with a scan-budget cap (default 5× `limit`). For low-auth-ratio tenants the helper may return `hasMore: false` before exhausting the table — raise `limit` if a `while (hasMore)` paginator stops short.

</details>

<details>

<summary><strong><code>packConfigsForForm</code></strong>-Gets pack configurations associated with a form.</summary>

**GraphQL schema**

```graphql
packConfigsForForm(formId: ID!, orgId: ID!, triggerId: ID): [PackConfig!]!
```

**Is** `where` **or** `search` **mandatory?**

No - `formId`, `orgId`.

</details>

<details>

<summary><strong><code>evaluatedForm</code></strong>-Gets an evaluated form for a specific trigger.</summary>

**GraphQL schema**

```graphql
evaluatedForm(
  where: EvaluatedFormWhereInput
  orgContextId: ID
): Form
```

**`EvaluatedFormWhereInput` supported fields**

| Field       | Type             |
| ----------- | ---------------- |
| `orgId`     | `ID!` (required) |
| `triggerId` | `ID!` (required) |

**Is** `where` **or** `search` **mandatory?**

No `search` input is needed. Use both `orgId` and `triggerId` on `where` - both non-null.

</details>

#### **Microsoft CSP queries**

<details>

<summary><strong><code>microsoftCSPCustomer</code></strong>-Gets Microsoft CSP customer information.</summary>

**GraphQL schema**

```graphql
microsoftCSPCustomer(
  cspPackConfigId: ID!
  where: MicrosoftCSPCustomerWhereInput
): MicrosoftCSPCustomer

type MicrosoftCSPCustomer {
  createdAt: String!
  companyName: String!
  cspTenantId: String!
  hasConsent: Boolean!
  id: ID!
  linkedOrganizations: [Organization!]
  tenantId: String!
  updatedAt: String!
}
```

**`MicrosoftCSPCustomerWhereInput` supported fields**

| Field                 | Type                              |
| --------------------- | --------------------------------- |
| `companyName`         | `String`                          |
| `cspTenantId`         | `String`                          |
| `hasConsent`          | `Boolean`                         |
| `id`                  | `ID`                              |
| `linkedOrganizations` | `OrganizationWhereInput` (nested) |
| `tenantId`            | `String`                          |

**Is** `where` **or** `search` **mandatory?**

Yes - `cspPackConfigId` plus at least one filter on `where` to identify the customer. No `search` input is needed.

</details>

<details>

<summary><strong><code>microsoftCSPCustomers</code></strong>-Gets multiple Microsoft CSP customers.</summary>

**GraphQL schema**

```graphql
microsoftCSPCustomers(
  cspPackConfigId: ID!
  search: MicrosoftCSPCustomerSearchInput,
  where: MicrosoftCSPCustomerWhereInput
): [MicrosoftCSPCustomer!]!
```

**`MicrosoftCSPCustomerSearchInput` supported fields**

| Field                 | Wrapper                            |
| --------------------- | ---------------------------------- |
| `companyName`         | `string_comparison_exp`            |
| `cspTenantId`         | `string_comparison_exp`            |
| `hasConsent`          | `bool_comparison_exp`              |
| `id`                  | `id_comparison_exp`                |
| `linkedOrganizations` | `OrganizationSearchInput` (nested) |
| `tenantId`            | `string_comparison_exp`            |

**Is** `where` **or** `search` **mandatory?**

`cspPackConfigId`. No `limit`/`offset` — results are scoped to the supplied pack config.

</details>

#### **Trigger instance queries**

<details>

<summary><strong><code>orgTriggerInstance</code></strong>-Gets a specific organization trigger instance.</summary>

**GraphQL schema**

```graphql
orgTriggerInstance(
  where: OrgTriggerInstanceWhereInput
  search: OrgTriggerInstanceSearchInput
): OrgTriggerInstance

type OrgTriggerInstance {
  id: ID!
  isManualActivation: Boolean
  organization: Organization
  orgId: ID
  lastSearchedAt: String
  trigger: Trigger
  triggerId: ID
  state: JSON
  createdAt: String!
  updatedAt: String!
}
```

**`OrgTriggerInstanceWhereInput` supported fields**

| Field          | Type                         |
| -------------- | ---------------------------- |
| `id`           | `ID`                         |
| `orgId`        | `ID`                         |
| `organization` | `OrganizationInput` (nested) |
| `triggerId`    | `ID`                         |
| `trigger`      | `TriggerWhereInput` (nested) |

**`OrgTriggerInstanceSearchInput` supported fields**

| Field          | Wrapper                       |
| -------------- | ----------------------------- |
| `id`           | `id_comparison_exp`           |
| `orgId`        | `id_comparison_exp`           |
| `organization` | `OrganizationInput` (nested)  |
| `triggerId`    | `id_comparison_exp`           |
| `trigger`      | `TriggerSearchInput` (nested) |

**Is** `where` **or** `search` **mandatory?**

At least one filter is needed identifying a single instance — typically `id`, or `orgId` + `triggerId`.

</details>

<details>

<summary><strong><code>orgTriggerInstances</code></strong>-Gets multiple organization trigger instances.</summary>

**GraphQL schema**

```graphql
orgTriggerInstances(
  where: OrgTriggerInstanceWhereInput
  search: OrgTriggerInstanceSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["createdAt"]]
): [OrgTriggerInstance!]!
```

**`OrgTriggerInstanceWhereInput` supported fields**

| Field          | Type                         |
| -------------- | ---------------------------- |
| `id`           | `ID`                         |
| `orgId`        | `ID`                         |
| `organization` | `OrganizationInput` (nested) |
| `triggerId`    | `ID`                         |
| `trigger`      | `TriggerWhereInput` (nested) |

**`OrgTriggerInstanceSearchInput` supported fields**

| Field          | Wrapper                       |
| -------------- | ----------------------------- |
| `id`           | `id_comparison_exp`           |
| `orgId`        | `id_comparison_exp`           |
| `organization` | `OrganizationInput` (nested)  |
| `triggerId`    | `id_comparison_exp`           |
| `trigger`      | `TriggerSearchInput` (nested) |

**Is** `where` **or** `search` **mandatory?**

`limit` and `offset` .

</details>

#### **Organization variable queries**

<details>

<summary><strong><code>orgVariable</code></strong>-Gets a specific organization variable.</summary>

**GraphQL schema**

```graphql
orgVariable(
  where: OrgVariableWhereInput
  search: OrgVariableSearchInput
  maskSecrets: Boolean
): OrgVariable

type OrgVariable {
  cascade: Boolean!
  category: OrgVariableCategory!
  createdAt: String!
  id: ID!
  name: String!
  organization: Organization!
  orgId: ID!
  packConfig: PackConfig
  packConfigId: ID
  updatedAt: String
  value: String
}

enum OrgVariableCategory {
  contact
  general
  secret
  system
}
```

**`OrgVariableWhereInput` supported fields**

| Field          | Type                              |
| -------------- | --------------------------------- |
| `id`           | `ID`                              |
| `name`         | `String`                          |
| `value`        | `String`                          |
| `category`     | `OrgVariableCategory`             |
| `orgId`        | `ID`                              |
| `organization` | `OrganizationWhereInput` (nested) |
| `packConfigId` | `ID`                              |
| `packConfig`   | `PackConfigWhereInput` (nested)   |

**`OrgVariableSearchInput` supported fields**

| Field          | Wrapper                            |
| -------------- | ---------------------------------- |
| `id`           | `id_comparison_exp`                |
| `name`         | `string_comparison_exp`            |
| `value`        | `string_comparison_exp`            |
| `category`     | `OrgVariableCategorySearchInput`   |
| `orgId`        | `id_comparison_exp`                |
| `organization` | `OrganizationSearchInput` (nested) |
| `packConfigId` | `id_comparison_exp`                |
| `packConfig`   | `PackConfigSearch` (nested)        |

**Is** `where` **or** `search` **mandatory?**

At least one filter is required— typically `id`, or `orgId` + `name`. Pass `maskSecrets: false` only when raw secret values are required.

</details>

<details>

<summary><strong><code>orgVariables</code></strong>-Gets multiple organization variables.</summary>

**GraphQL schema**

```graphql
orgVariables(
  where: OrgVariableWhereInput
  search: OrgVariableSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
  maskSecrets: Boolean
): [OrgVariable!]!
```

**`OrgVariableWhereInput` supported fields**

| Field          | Type                              |
| -------------- | --------------------------------- |
| `id`           | `ID`                              |
| `name`         | `String`                          |
| `value`        | `String`                          |
| `category`     | `OrgVariableCategory`             |
| `orgId`        | `ID`                              |
| `organization` | `OrganizationWhereInput` (nested) |
| `packConfigId` | `ID`                              |
| `packConfig`   | `PackConfigWhereInput` (nested)   |

**`OrgVariableSearchInput` supported fields**

| Field          | Wrapper                            |
| -------------- | ---------------------------------- |
| `id`           | `id_comparison_exp`                |
| `name`         | `string_comparison_exp`            |
| `value`        | `string_comparison_exp`            |
| `category`     | `OrgVariableCategorySearchInput`   |
| `orgId`        | `id_comparison_exp`                |
| `organization` | `OrganizationSearchInput` (nested) |
| `packConfigId` | `id_comparison_exp`                |
| `packConfig`   | `PackConfigSearch` (nested)        |

**Is** `where` **or** `search` **mandatory?**

Yes - `limit` and `offset`; scope with `where: { orgId: <id> }`.

</details>

<details>

<summary><strong><code>visibleOrgVariables</code></strong>-Gets organization variables visible to a specific organization.</summary>

**GraphQL schema**

```graphql
visibleOrgVariables(
  search: OrgVariableSearchInput
  visibleForOrgId: ID!
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [OrgVariable!]!
```

**`OrgVariableWhereInput` supported fields**

| Field          | Type                              |
| -------------- | --------------------------------- |
| `id`           | `ID`                              |
| `name`         | `String`                          |
| `value`        | `String`                          |
| `category`     | `OrgVariableCategory`             |
| `orgId`        | `ID`                              |
| `organization` | `OrganizationWhereInput` (nested) |
| `packConfigId` | `ID`                              |
| `packConfig`   | `PackConfigWhereInput` (nested)   |

**`OrgVariableSearchInput` supported fields**

| Field          | Wrapper                            |
| -------------- | ---------------------------------- |
| `id`           | `id_comparison_exp`                |
| `name`         | `string_comparison_exp`            |
| `value`        | `string_comparison_exp`            |
| `category`     | `OrgVariableCategorySearchInput`   |
| `orgId`        | `id_comparison_exp`                |
| `organization` | `OrganizationSearchInput` (nested) |
| `packConfigId` | `id_comparison_exp`                |
| `packConfig`   | `PackConfigSearch` (nested)        |

**Is** `where` **or** `search` **mandatory?**

Yes - filter via `search`. Results include cascading variables from parent orgs. No `where` input is required. `visibleForOrgId`, `limit`, `offset`.

</details>

#### **Organization management queries**

<details>

<summary><strong><code>organization</code></strong>-Gets a specific organization.</summary>

**GraphQL schema**

```graphql
organization(
  where: OrganizationWhereInput
  search: OrganizationSearchInput
): Organization

type Organization {
  actions: [Action!]!
  activatedTriggers: [Trigger!]!
  createdAt: String
  createdTags: [Tag!]!
  domain: String
  deletedAt: String
  forms: [Form!]!
  id: ID
  isMsp: Boolean
  isStaff: Boolean
  isEnabled: Boolean
  isDeleted: Boolean
  isInternal: Boolean
  installedPacks: [Pack!]!
  featurePreviewSettings: [OrganizationFeaturePreviewSetting]
  managedOrgAutoInstallingWorkflows: [Workflow!]!
  managedAndSubOrgs: [Organization!]!
  managedOrgs: [Organization!]!
  managingOrg: Organization
  managingOrgId: ID
  name: String!
  orgSlug: String
  packConfigs: [PackConfig!]!
  resultsRetentionDays: Int
  rocSiteId: String
  tags: [Tag!]!
  templates: [Template!]!
  tid: ID
  triggerInstances: [OrgTriggerInstance!]!
  triggers: [Trigger!]!
  users: [User!]!
  variables: [OrgVariable!]!
  visibleActions: [Action!]!
  visiblePackConfigs: [PackConfig!]!
  visibleWorkflows: [Workflow!]!
  workflowExecutions: [WorkflowExecution!]!
  workflows: [Workflow!]!
  supportAccessStatus: SupportAccessStatus
}
```

**`OrganizationWhereInput` supported fields**

| Field           | Type                                 | Notes                      |
| --------------- | ------------------------------------ | -------------------------- |
| `id`            | `ID`                                 |                            |
| `isStaff`       | `Boolean`                            |                            |
| `managedOrgs`   | `OrganizationWhereInput` (recursive) |                            |
| `managingOrg`   | `OrganizationWhereInput` (recursive) |                            |
| `managingOrgId` | `ID`                                 |                            |
| `name`          | `String`                             | Exact match only           |
| `orgSlug`       | `String`                             |                            |
| `rocSiteId`     | `String`                             |                            |
| `tags`          | `OrganizationTagsWhereInput`         | Nested: `{ id: [ID!] }`    |
| `users`         | `UserWhereInput`                     | Filter orgs by their users |
| `domain`        | `String`                             |                            |

**`OrganizationSearchInput` supported fields**

| Field                  | Wrapper                               |
| ---------------------- | ------------------------------------- |
| `createdAt`            | `string_comparison_exp`               |
| `id`                   | `id_comparison_exp`                   |
| `installedPacks`       | `PackSearchInput`                     |
| `isDeleted`            | `bool_comparison_exp`                 |
| `isEnabled`            | `bool_comparison_exp`                 |
| `isInternal`           | `bool_comparison_exp`                 |
| `isOnboarding`         | `bool_comparison_exp`                 |
| `isStaff`              | `bool_comparison_exp`                 |
| `managedOrgs`          | `OrganizationSearchInput` (recursive) |
| `managingOrg`          | `OrganizationSearchInput` (recursive) |
| `managingOrgId`        | `id_comparison_exp`                   |
| `name`                 | `string_comparison_exp`               |
| `orgSlug`              | `string_comparison_exp`               |
| `resultsRetentionDays` | `int_comparison_exp`                  |
| `rocSiteId`            | `string_comparison_exp`               |
| `tags`                 | `TagSearchInput`                      |
| `users`                | `UserSearchInput`                     |

**Is `where` or `search` mandatory?**

At least one of `where` or `search` to identify the org — typically `where: { id: <id> }` or `where: { orgSlug: <slug> }`.

</details>

<details>

<summary><strong><code>organizations</code></strong>-Gets multiple organizations.</summary>

**GraphQL schema**

```graphql
organizations(
  where: OrganizationWhereInput
  search: OrganizationSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [Organization!]!
```

**`OrganizationWhereInput` supported fields**

| Field           | Type                                 | Notes                      |
| --------------- | ------------------------------------ | -------------------------- |
| `id`            | `ID`                                 |                            |
| `isStaff`       | `Boolean`                            |                            |
| `managedOrgs`   | `OrganizationWhereInput` (recursive) |                            |
| `managingOrg`   | `OrganizationWhereInput` (recursive) |                            |
| `managingOrgId` | `ID`                                 |                            |
| `name`          | `String`                             | Exact match only           |
| `orgSlug`       | `String`                             |                            |
| `rocSiteId`     | `String`                             |                            |
| `tags`          | `OrganizationTagsWhereInput`         | Nested: `{ id: [ID!] }`    |
| `users`         | `UserWhereInput`                     | Filter orgs by their users |
| `domain`        | `String`                             |                            |

Not filterable via `where` - available via `search`: `isEnabled`, `isInternal`, `isDeleted`, `isOnboarding`, `createdAt`, `resultsRetentionDays`

Not filterable at all - neither `where` nor `search`): `isMsp`, `tid`, `deletedAt`

**`OrganizationSearchInput` supported fields**

| Field                  | Wrapper                               |
| ---------------------- | ------------------------------------- |
| `createdAt`            | `string_comparison_exp`               |
| `id`                   | `id_comparison_exp`                   |
| `installedPacks`       | `PackSearchInput`                     |
| `isDeleted`            | `bool_comparison_exp`                 |
| `isEnabled`            | `bool_comparison_exp`                 |
| `isInternal`           | `bool_comparison_exp`                 |
| `isOnboarding`         | `bool_comparison_exp`                 |
| `isStaff`              | `bool_comparison_exp`                 |
| `managedOrgs`          | `OrganizationSearchInput` (recursive) |
| `managingOrg`          | `OrganizationSearchInput` (recursive) |
| `managingOrgId`        | `id_comparison_exp`                   |
| `name`                 | `string_comparison_exp`               |
| `orgSlug`              | `string_comparison_exp`               |
| `resultsRetentionDays` | `int_comparison_exp`                  |
| `rocSiteId`            | `string_comparison_exp`               |
| `tags`                 | `TagSearchInput`                      |
| `users`                | `UserSearchInput`                     |

**Is `where` or `search` mandatory?**

Yes, in practice. `organizations` is one of the three unbounded tables. Always pass:

* `where: { managingOrgId: CTX.organization.id }` or a `search` filter, and
* `limit` (recommended ≤ 100) and `offset` for pagination.

**Worked example: Listing disabled organizations**

`isEnabled` is not on `OrganizationWhereInput`, so this fails:

```yaml
# ❌ WRONG — isEnabled is not on OrganizationWhereInput
operation: organizations
variables:
  where: { isEnabled: false }
```

Use `search` instead:

```yaml
# ✅ CORRECT
operation: organizations
variables:
  search:
    isEnabled: { _eq: false }
    managingOrgId: { _eq: "{{ CTX.organization.id }}" }
  limit: 100
  offset: 0
```

</details>

<details>

<summary><strong><code>orgSearch</code></strong>-Performs organization search with breadcrumbs.</summary>

**GraphQL schema**

```graphql
orgSearch(
  search: String
  rootOrgId: ID!
  breadcrumbRootOrgId: ID!
): [OrgSearchResult!]!

type OrgSearchResult {
  id: ID!
  name: String!
  hasChildren: Boolean!
  breadcrumbs: [OrgBreadcrumb]
  managingOrgId: ID
  supportAccessStatus: SupportAccessStatus
  isInternal: Boolean
  }
```

**Is `where` or `search` mandatory?**

No - WhereInput`/`SearchInput - search here is a plain free-text string matched against org name, not an operator-wrapper type. ReturnsOrgSearchResult (id, name, hasChildren, breadcrumbs, managingOrgId, supportAccessStatus, isInternal), not fullOrganization\`.

</details>

<details>

<summary><strong><code>softDeletedOrgs</code></strong>-Gets soft-deleted organizations.</summary>

**GraphQL schema**

```graphql
softDeletedOrgs(managingOrgId: ID!): [Organization!]!
```

**Is `where` or `search` mandatory?**

There is no `where`/`search`/pagination. Scoping is solely `managingOrgId`.

</details>

#### **Pack action option queries**

<details>

<summary><strong><code>packActionOption</code></strong>-Gets a specific pack action option.</summary>

**GraphQL schema**

```graphql
packActionOption(where: PackActionOptionWhereInput): PackActionOption

type PackActionOption {
  id: ID!
  name: String!
  packId: ID!
  path: String!
  method: HTTPMethod
  paginate: Boolean
  queryParams: JSON
  pathParams: JSON
  headers: JSON
  requiredPathVars: [String!]
  requiredQueryVars: [String!]
  requiredHeaderVars: [String!]
  resultsKey: String
  valueField: String!
  label: String!
  labelIsTemplate: Boolean
  valueFieldIsPath: Boolean
  maxPages: Int
  pageSize: Int
}
```

**`PackActionOptionWhereInput` supported fields**

| Field                | Type         |
| -------------------- | ------------ |
| `id`                 | `ID`         |
| `packId`             | `ID`         |
| `name`               | `String`     |
| `path`               | `String`     |
| `method`             | `HTTPMethod` |
| `paginate`           | `Boolean`    |
| `queryParams`        | `JSON`       |
| `pathParams`         | `JSON`       |
| `headers`            | `JSON`       |
| `requiredPathVars`   | `[String!]`  |
| `requiredQueryVars`  | `[String!]`  |
| `requiredHeaderVars` | `[String!]`  |
| `resultsKey`         | `String`     |
| `valueField`         | `String`     |
| `label`              | `String`     |
| `labelIsTemplate`    | `Boolean`    |
| `valueFieldIsPath`   | `Boolean`    |

**Is `where` or `search` mandatory?**

Yes - There is no `search` input — equality filtering via `where` only. `PackActionOptionWhereInput`

</details>

<details>

<summary><strong><code>packActionOptions</code></strong>-Gets multiple pack action options.</summary>

```graphql
packActionOptions(
  where: PackActionOptionWhereInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["label"]]
): [PackActionOption!]!
```

**GraphQL schema**

**`PackActionOptionsWhereInput` supported fields**

| Field                | Type         |
| -------------------- | ------------ |
| `id`                 | `ID`         |
| `packId`             | `ID`         |
| `name`               | `String`     |
| `path`               | `String`     |
| `method`             | `HTTPMethod` |
| `paginate`           | `Boolean`    |
| `queryParams`        | `JSON`       |
| `pathParams`         | `JSON`       |
| `headers`            | `JSON`       |
| `requiredPathVars`   | `[String!]`  |
| `requiredQueryVars`  | `[String!]`  |
| `requiredHeaderVars` | `[String!]`  |
| `resultsKey`         | `String`     |
| `valueField`         | `String`     |
| `label`              | `String`     |
| `labelIsTemplate`    | `Boolean`    |
| `valueFieldIsPath`   | `Boolean`    |

**Is `where` or `search` mandatory?**

There is no `search` input — equality filtering via `where` only. `limit`, `offset`; scope with `where: { packId: <id> }`.

</details>

#### **Pack bundle queries**

<details>

<summary><strong><code>packBundle</code></strong>-Gets a specific pack bundle.</summary>

**GraphQL schema**

```graphql
packBundle(where: PackBundleWhereInput!): PackBundle

type PackBundle {
  configSchema: JSON
  description: String
  id: ID!
  name: String!
  packs: [Pack!]!
  ref: String!
}
```

**`PackBundleWhereInput` supported fields**

| Field         | Type                      |
| ------------- | ------------------------- |
| `description` | `String`                  |
| `id`          | `ID`                      |
| `name`        | `String`                  |
| `packs`       | `PackWhereInput` (nested) |
| `ref`         | `String`                  |

**Is `where` or `search` mandatory?**

Yes - there is no `search` input. Use `where` (non-null) with at least one identifying field — typically `id` or `ref`.

</details>

<details>

<summary><strong><code>packBundles</code></strong>-Gets multiple pack bundles.</summary>

**GraphQL schema**

```graphql
packBundles(
  where: PackBundleWhereInput
  search: PackBundleSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [PackBundle]!
```

**`PackBundleSearchInput` — supported fields**

| Field         | Wrapper                                                       |
| ------------- | ------------------------------------------------------------- |
| `description` | `string_comparison_exp`                                       |
| `id`          | `id_comparison_exp`                                           |
| `name`        | `string_comparison_exp`                                       |
| `packs`       | `PackSearchInput` (nested)                                    |
| `ref`         | `String` (equality only — plain string, not a comparison exp) |

**Is `where` or `search` mandatory?**

`limit` and `offset`

</details>

#### **Pack configuration queries**

<details>

<summary><strong><code>packConfig</code></strong>-Gets a specific pack configuration.</summary>

**GraphQL schema**

```graphql
packConfig(
  where: PackConfigWhereInput
  search: PackConfigSearch
  includeSpec: Boolean
): PackConfig

type PackConfig {
  appliedToTriggers: [Trigger!]!
  config: JSON
  default: Boolean
  description: String
  id: ID
  metadata: JSON
  name: String!
  organization: Organization
  foreignObjectReferences: [ForeignObjectReference!]!
  orgId: ID
  orgVariables: [OrgVariable!]!
  pack: Pack
  packId: ID
  actionOptions: [ActionOption!]!
  updatedAt: String
  createdAt: String
  visibleForOrganizations: [Organization!]!
}
```

**`PackConfigWhereInput` supported fields**

| Field           | Type                              |
| --------------- | --------------------------------- |
| `actionOptions` | `ActionOptionWhereInput` (nested) |
| `config`        | `JSON`                            |
| `default`       | `Boolean`                         |
| `description`   | `String`                          |
| `id`            | `ID`                              |
| `metadata`      | `JSON`                            |
| `name`          | `String`                          |
| `orgId`         | `ID`                              |
| `pack`          | `PackWhereInput` (nested)         |
| `packId`        | `ID`                              |
| `ref`           | `ID`                              |

**`PackConfigSearch` supported fields**

| Field         | Wrapper                    |
| ------------- | -------------------------- |
| `id`          | `id_comparison_exp`        |
| `name`        | `string_comparison_exp`    |
| `default`     | `bool_comparison_exp`      |
| `description` | `string_comparison_exp`    |
| `config`      | `json_comparison_exp`      |
| `metadata`    | `json_comparison_exp`      |
| `orgId`       | `id_comparison_exp`        |
| `pack`        | `PackSearchInput` (nested) |
| `packId`      | `id_comparison_exp`        |

**Is `where` or `search` mandatory?**

Yes - Use at least one of `where` or `search` to identify the config.

Note: `config` and `metadata` are `@sensitive` and may be redacted depending on caller permissions.

</details>

<details>

<summary><strong><code>packConfigs</code></strong>-Gets multiple pack configurations.</summary>

**GraphQL schema**

```graphql
packConfigs(
  where: PackConfigWhereInput
  search: PackConfigSearch
  resourceNames: String
  order: [[String!]!]
  includeSpec: Boolean
): [PackConfig!]!
```

**`PackConfigWhereInput` supported fields**

| Field           | Type                              |
| --------------- | --------------------------------- |
| `actionOptions` | `ActionOptionWhereInput` (nested) |
| `config`        | `JSON`                            |
| `default`       | `Boolean`                         |
| `description`   | `String`                          |
| `id`            | `ID`                              |
| `metadata`      | `JSON`                            |
| `name`          | `String`                          |
| `orgId`         | `ID`                              |
| `pack`          | `PackWhereInput` (nested)         |
| `packId`        | `ID`                              |
| `ref`           | `ID`                              |

**`PackConfigSearch` supported fields**

| Field         | Wrapper                    |
| ------------- | -------------------------- |
| `id`          | `id_comparison_exp`        |
| `name`        | `string_comparison_exp`    |
| `default`     | `bool_comparison_exp`      |
| `description` | `string_comparison_exp`    |
| `config`      | `json_comparison_exp`      |
| `metadata`    | `json_comparison_exp`      |
| `orgId`       | `id_comparison_exp`        |
| `pack`        | `PackSearchInput` (nested) |
| `packId`      | `id_comparison_exp`        |

**Is `where` or `search` mandatory?**

Yes - `orgId` scoping via `where` or `search` — unscoped calls return everything visible to the caller.

There is no **`limit`/`offset`** — this query does not accept pagination args. Always scope aggressively - e.g. `where: { orgId: <id>, packId: <id> }`.

</details>

<details>

<summary><strong><code>packConfigsForOrg</code></strong>-Gets pack configurations for a specific organization.</summary>

**GraphQL schema**

```graphql
packConfigsForOrg(
  packIds: [ID!]!
  orgId: ID!
  includeSpec: Boolean
): [PackConfig!]!
```

**Is `where` or `search` mandatory?**

No - There is no `where`/`search`/pagination. It's scoped solely by `packIds` + `orgId`.

</details>

#### **Pack management queries**

<details>

<summary><strong><code>pack</code></strong>-Gets a specific integration pack.</summary>

**GraphQL schema**

```graphql
pack(where: PackWhereInput): Pack

type Pack {
  actions: [Action!]!
  configFormSchema: JSON
  configSchema: JSON
  metadata: JSON
  description: String
  id: String
  orgId: ID
  installedBy: [Organization]
  isDefault: Boolean
  isOauthConfiguration: Boolean
  isMultitenancyEnabled: Boolean
  name: String
  orgVariables: JSON
  packBundle: PackBundle
  packBundleId: ID
  packConfigs: [PackConfig!]!
  packOverrides: [PackOverride]
  packTestAction: Action
  packType: PackType
  ref: String
  icon: String
  sensorTypes: [SensorType!]!
  setupInstructions: String
  status: PackStatus!
  tags: [Tag!]!
  triggerTypes: [TriggerType!]!
  uid: String
  version: String
}
```

**`PackWhereInput` supported fields**

| Field                  | Type                              |
| ---------------------- | --------------------------------- |
| `actions`              | `ActionInput` (nested)            |
| `packType`             | `PackType`                        |
| `description`          | `String`                          |
| `id`                   | `ID`                              |
| `installedBy`          | `OrganizationWhereInput` (nested) |
| `name`                 | `String`                          |
| `packBundleId`         | `ID`                              |
| `ref`                  | `String`                          |
| `orgId`                | `ID`                              |
| `status`               | `PackStatus`                      |
| `isOauthConfiguration` | `Boolean`                         |

**Is `where` or `search` mandatory?**

Yes - `where` with at least one identifying field — typically `id` or `ref`. There is no `search` input.

</details>

<details>

<summary><strong><code>packsAndBundlesByInstalledState</code></strong>-Gets packs and bundles organized by installation state.</summary>

**GraphQL schema**

```graphql
packsAndBundlesByInstalledState(
  orgId: ID!
  includeCustomPack: Boolean
): PacksAndBundlesByInstalledState!

type PacksAndBundlesByInstalledState {
  installedPacksAndBundles: [PackOrPackBundle!]
  marketplacePacksAndBundles: [PackOrPackBundle!]
}
```

**Is `where` or `search` mandatory?**

There is no `where`/`search`/pagination. Returns `installedPacksAndBundles` and `marketplacePacksAndBundles`. `orgId` is mandatory.

</details>

#### **Page management queries**

<details>

<summary><strong><code>page</code></strong>-Gets a specific page definition.</summary>

**GraphQL schema**

```graphql
page(where: PageWhereInput!): Page

type Page {
  createdBy: User
  createdById: ID
  createdAt: String
  id: ID!
  loader: Loader
  name: String!
  path: String!
  site: Site
  siteId: ID
  updatedAt: String
  updatedBy: User
  updatedById: ID
  workflows: [Workflow!]!
  nodes: [PageNode]
  permission: Permission
  orgId: ID
  variables: [JSON]
  organization: Organization
  isSynchronized: Boolean
  clonedFromId: ID
  clonedFrom: Site
  cloneOverrides: JSON
  clones: [Page]
  title: String
}
```

**`PageWhereInput` supported fields**

| Field          | Type                                                         |
| -------------- | ------------------------------------------------------------ |
| `id`           | `ID`                                                         |
| `name`         | `String`                                                     |
| `siteId`       | `ID`                                                         |
| `site`         | `SitePropertiesInput` (nested: `{ id: ID, domain: String }`) |
| `path`         | `String`                                                     |
| `domain`       | `String`                                                     |
| `orgId`        | `ID`                                                         |
| `clonedFromId` | `ID`                                                         |
| `_`            | `String` (editor render hint — ignored server-side)          |

**Is `where` or `search` mandatory?**

Yes - `where` (non-null) with at least one identifying field — typically `id` or `siteId` + `path`. There is no `search` input.

</details>

<details>

<summary><strong><code>pages</code></strong>-Gets multiple pages.</summary>

**GraphQL schema**

```graphql
pages(
  where: PageWhereInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
  search: PageSearchInput
): [Page!]!
```

**`PageSearchInput` supported fields**

| Field    | Type     | Notes                                                       |
| -------- | -------- | ----------------------------------------------------------- |
| `name`   | `String` | Equality only — plain string, NOT a `string_comparison_exp` |
| `siteId` | `ID`     | Equality only                                               |

**Is `where` or `search` mandatory?**

Yes - `limit` and `offset`; scope with `where: { orgId: <id> }` or `where: { siteId: <id> }`.

`PageSearchInput` does not accept `_eq`/`_in`/`_like` wrappers despite being named `search`.

</details>

<details>

<summary><strong><code>pageVars</code></strong>-Gets page variables.</summary>

**GraphQL schema**

```graphql
pageVars(id: ID!, query: JSON): JSON
```

**Is `where` or `search` mandatory?**

`id`. `query` is an arbitrary JSON object passed as URL query params for variable resolution.

</details>

#### **Permission queries**

<details>

<summary><strong><code>permission</code></strong>-Gets a specific permission.</summary>

**GraphQL schema**

```graphql
permission(where: PermissionWhereInput): Permission

type Permission {
  id: ID
  templateId: ID
  authorizedForOrganizations: [Organization]
  authorizedForSubOrganizations: [Organization]
  excludeOrganizations: [Organization]
  roleIds: [String]
  override: String
  objectType: String
  objectId: String
  orgId: ID
  relation: String
  permissionType: String
  subjectType: String
  subjectId: String
}
```

**`PermissionWhereInput` supported fields**

| Field            | Type     |
| ---------------- | -------- |
| `id`             | `ID`     |
| `templateId`     | `ID`     |
| `objectId`       | `String` |
| `objectType`     | `String` |
| `permissionType` | `String` |

**Is `where` or `search` mandatory?**

There is no `search` input and no `limit`/`offset`. Scope to a specific object to keep result sets small (typically `objectId` + `objectType`).

</details>

<details>

<summary><strong><code>permissions</code></strong>-Gets multiple permissions.</summary>

**GraphQL schema**

```graphql
permissions(where: PermissionWhereInput): [Permission!]!
```

**`PermissionWhereInput` supported fields**

| Field            | Type     |
| ---------------- | -------- |
| `id`             | `ID`     |
| `templateId`     | `ID`     |
| `objectId`       | `String` |
| `objectType`     | `String` |
| `permissionType` | `String` |

**Is `where` or `search` mandatory?**

There is no `search` input and no `limit`/`offset`. Scope to a specific object to keep result sets small (typically `objectId` + `objectType`).

</details>

#### **Sensor type queries**

<details>

<summary><strong><code>sensorType</code></strong>-Gets a specific sensor type.</summary>

**GraphQL schema**

```graphql
sensorType(
  where: SensorTypeInput
  search: SensorTypeSearchInput
): SensorType

type SensorType {
  description: String
  enabled: Boolean
  entryPoint: String
  id: ID
  name: String
  notifyOnTriggerChanges: Boolean
  pack: Pack
  ref: String
  triggerTypes: [TriggerType!]!
}
```

**`SensorTypeInput` (where) supported fields**

| Field                    | Type      |
| ------------------------ | --------- |
| `description`            | `String`  |
| `enabled`                | `Boolean` |
| `entryPoint`             | `String`  |
| `id`                     | `ID`      |
| `name`                   | `String`  |
| `notifyOnTriggerChanges` | `Boolean` |
| `packId`                 | `ID`      |
| `ref`                    | `String`  |

**`SensorTypeSearchInput` supported fields**

| Field                    | Wrapper                   |
| ------------------------ | ------------------------- |
| `description`            | `string_comparison_exp`   |
| `enabled`                | `bool_comparison_exp`     |
| `entryPoint`             | `string_comparison_exp`   |
| `id`                     | `id_comparison_exp`       |
| `name`                   | `string_comparison_exp`   |
| `notifyOnTriggerChanges` | `Boolean` (equality only) |
| `packId`                 | `id_comparison_exp`       |
| `ref`                    | `string_comparison_exp`   |

**Is `where` or `search` mandatory?**

Yes - `where` or `search` with at least one filter field is required.

</details>

<details>

<summary><strong><code>sensorTypes</code></strong>-Gets multiple sensor types.</summary>

**GraphQL schema**

```graphql
sensorTypes(
  where: SensorTypeInput
  search: SensorTypeSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [SensorType!]!
```

**`SensorTypeInput` (where) supported fields**

| Field                    | Type      |
| ------------------------ | --------- |
| `description`            | `String`  |
| `enabled`                | `Boolean` |
| `entryPoint`             | `String`  |
| `id`                     | `ID`      |
| `name`                   | `String`  |
| `notifyOnTriggerChanges` | `Boolean` |
| `packId`                 | `ID`      |
| `ref`                    | `String`  |

**`SensorTypeSearchInput` supported fields**

| Field                    | Wrapper                   |
| ------------------------ | ------------------------- |
| `description`            | `string_comparison_exp`   |
| `enabled`                | `bool_comparison_exp`     |
| `entryPoint`             | `string_comparison_exp`   |
| `id`                     | `id_comparison_exp`       |
| `name`                   | `string_comparison_exp`   |
| `notifyOnTriggerChanges` | `Boolean` (equality only) |
| `packId`                 | `id_comparison_exp`       |
| `ref`                    | `string_comparison_exp`   |

**Is `where` or `search` mandatory?**

`limit` and `offset`.

</details>

#### **Site and app management queries**

<details>

<summary><strong><code>site</code></strong>-Gets a specific site/app.</summary>

**GraphQL schema**

```graphql
site(where: SiteWhereInput, search: SiteSearchInput): Site

type Site {
  createdBy: User
  createdById: ID
  createdAt: String
  domain: String
  id: ID!
  isLive: Boolean
  statusCode: Int
  statusMessage: String
  name: String!
  organization: Organization
  orgId: ID!
  shared: Boolean
  updatedAt: String
  updatedBy: User
  updatedById: ID
  template: String
  theme: JSON
  themeReferenceOrgVariable: String
  pages: [Page]
  permission: Permission
  customDomain: String
  isDnsValidated: Boolean
  useCustomDomain: Boolean
  isSynchronized: Boolean
  clonedFromId: ID
  clonedFrom: Site
  cloneOverrides: JSON
  clones: [Site]
  faviconUrl: String
}
```

**`SiteWhereInput` supported fields**

| Field             | Type      |
| ----------------- | --------- |
| `id`              | `ID`      |
| `isLive`          | `Boolean` |
| `name`            | `String`  |
| `domain`          | `String`  |
| `orgId`           | `ID`      |
| `customDomain`    | `String`  |
| `isDnsValidated`  | `Boolean` |
| `useCustomDomain` | `Boolean` |
| `clonedFromId`    | `ID`      |
| `isSynchronized`  | `Boolean` |

**`SiteSearchInput` supported fields**

| Field             | Wrapper                            |
| ----------------- | ---------------------------------- |
| `id`              | `id_comparison_exp`                |
| `isLive`          | `bool_comparison_exp`              |
| `name`            | `string_comparison_exp`            |
| `domain`          | `string_comparison_exp`            |
| `organization`    | `OrganizationSearchInput` (nested) |
| `organizationId`  | `id_comparison_exp`                |
| `customDomain`    | `string_comparison_exp`            |
| `isDnsValidated`  | `bool_comparison_exp`              |
| `useCustomDomain` | `bool_comparison_exp`              |
| `clonedFromId`    | `id_comparison_exp`                |

**Is `where` or `search` mandatory?**

Yes - `where` or `search` with at least one filter field.

</details>

<details>

<summary><strong><code>sites</code></strong>-Gets multiple sites/apps.</summary>

**GraphQL schema**

```graphql
sites(where: SiteWhereInput, search: SiteSearchInput): [Site!]!
```

**`SiteWhereInput` supported fields**

| Field             | Type      |
| ----------------- | --------- |
| `id`              | `ID`      |
| `isLive`          | `Boolean` |
| `name`            | `String`  |
| `domain`          | `String`  |
| `orgId`           | `ID`      |
| `customDomain`    | `String`  |
| `isDnsValidated`  | `Boolean` |
| `useCustomDomain` | `Boolean` |
| `clonedFromId`    | `ID`      |
| `isSynchronized`  | `Boolean` |

**`SiteSearchInput` supported fields**

| Field             | Wrapper                            |
| ----------------- | ---------------------------------- |
| `id`              | `id_comparison_exp`                |
| `isLive`          | `bool_comparison_exp`              |
| `name`            | `string_comparison_exp`            |
| `domain`          | `string_comparison_exp`            |
| `organization`    | `OrganizationSearchInput` (nested) |
| `organizationId`  | `id_comparison_exp`                |
| `customDomain`    | `string_comparison_exp`            |
| `isDnsValidated`  | `bool_comparison_exp`              |
| `useCustomDomain` | `bool_comparison_exp`              |
| `clonedFromId`    | `id_comparison_exp`                |

**Is `where` or `search` mandatory?**

There is no `limit`/`offset`. Always scope by `orgId` to keep result sets small.

</details>

<details>

<summary><strong><code>getAppPermissions</code></strong>-Gets app permissions for an organization.</summary>

**GraphQL schema**

<pre class="language-graphql"><code class="lang-graphql"><strong>getAppPermissions(orgId: ID!): [Site!]!
</strong></code></pre>

**Is `where` or `search` mandatory?**

`orgId`

</details>

<details>

<summary><strong><code>getSiteTheme</code></strong>-Gets site theme configuration.</summary>

**GraphQL schema**

```graphql
getSiteTheme(id: ID, domain: String): JSON
```

**Is `where` or `search` mandatory?**

One of `id` or `domain`.

</details>

#### **Tag management queries**

<details>

<summary><strong><code>tag</code></strong>-Gets a specific tag.</summary>

**GraphQL schema**

```graphql
tag(where: TagWhereInput, search: TagSearchInput): Tag

type Tag {
  crates: [Crate!]
  createdAt: String
  description: String
  id: ID
  name: String
  organization: Organization
  organizations: [Organization!]!
  orgId: ID
  packs: [Pack!]!
  triggers: [Trigger!]!
  updatedAt: String
  color: String
}
```

**`TagWhereInput` supported fields**

| Field           | Type                         | Notes                                                                    |
| --------------- | ---------------------------- | ------------------------------------------------------------------------ |
| `id`            | `ID`                         |                                                                          |
| `name`          | `String`                     | Exact match only — use `search.name` for `_like`/`_ilike`                |
| `orgId`         | `ID`                         | Recommended on every call (see scoping rule above)                       |
| `organizations` | `TagOrganizationsWhereInput` | Nested filter: `{ id: [ID] }` — match tags assigned to any of these orgs |

**`TagSearchInput` supported fields**

| Field           | Wrapper                               |
| --------------- | ------------------------------------- |
| `id`            | `id_comparison_exp`                   |
| `name`          | `string_comparison_exp`               |
| `orgId`         | `id_comparison_exp`                   |
| `organizations` | `OrganizationSearchInput` (recursive) |

**Is `where` or `search` mandatory?**

Use `limit` and `offset`.

It is not filterable via **`where`** , despite existing on the `Tag` model: `color`, `description`, `createdAt`, `updatedAt`, `crates`, `packs`, `triggers`.

</details>

<details>

<summary><strong><code>tags</code></strong>-Gets multiple tags.</summary>

**GraphQL schema**

```graphql
tags(
  where: TagWhereInput
  search: TagSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
  includeTagsWithNoOwner: Boolean = false
): [Tag!]!
```

**`TagWhereInput` supported fields**

| Field           | Type                         | Notes                                                                    |
| --------------- | ---------------------------- | ------------------------------------------------------------------------ |
| `id`            | `ID`                         |                                                                          |
| `name`          | `String`                     | Exact match only — use `search.name` for `_like`/`_ilike`                |
| `orgId`         | `ID`                         | Recommended on every call (see scoping rule above)                       |
| `organizations` | `TagOrganizationsWhereInput` | Nested filter: `{ id: [ID] }` — match tags assigned to any of these orgs |

It is not filterable via **`where`** , despite existing on the `Tag` model: `color`, `description`, `createdAt`, `updatedAt`, `crates`, `packs`, `triggers`.

**`TagSearchInput` supported fields**

| Field           | Wrapper                               |
| --------------- | ------------------------------------- |
| `id`            | `id_comparison_exp`                   |
| `name`          | `string_comparison_exp`               |
| `orgId`         | `id_comparison_exp`                   |
| `organizations` | `OrganizationSearchInput` (recursive) |

**Is `where` or `search` mandatory?**

Schema-level: no.\
Practically: yes — pass `where: { orgId: CTX.organization.id }` to avoid the auto-inject path. This is the operation that produced the `Symbol(or)/Symbol(eq)/Symbol(in)` error.

</details>

<details>

<summary><strong><code>crateTags</code></strong>-Gets tags associated with crates.</summary>

**GraphQL schema**

```graphql
crateTags(
  where: TagWhereInput
  search: TagSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [Tag!]!

input TagWhereInput {
  id: ID
  name: String
  orgId: ID
  organizations: TagOrganizationsWhereInput
}

input TagSearchInput {
  id: id_comparison_exp
  name: string_comparison_exp
  orgId: id_comparison_exp
  organizations: OrganizationSearchInput
}
```

**Is `where` or `search` mandatory?**

`tag.orgId`, `limit` and `offset`.

</details>

#### **Task and execution analytics queries**

<details>

<summary><strong><code>dailyTaskCountsByDateRange</code></strong>-Gets daily task counts within a date range.</summary>

**GraphQL schema**

```graphql
dailyTaskCountsByDateRange(
  orgId: ID!
  startDate: String!
  endDate: String!
): [TaskCountByDate!]!

type TaskCountByDate {
  date: String!
  count: Int!
}
```

**Is `where` or `search` mandatory?**

`orgId`, `startDate`, `endDate`

</details>

<details>

<summary><strong><code>taskExecutionStats</code></strong>-Gets task execution statistics.</summary>

**GraphQL schema**

```graphql
taskExecutionStats(orgId: ID!, createdSince: String): Int!
```

**Is `where` or `search` mandatory?**

`orgId`. `createdSince` is optional but recommended to bound the scan.

</details>

<details>

<summary><strong><code>taskLog</code></strong>-Gets a specific task log entry.</summary>

**GraphQL schema**

```graphql
taskLog(
  where: TaskLogWhereInput
  search: TaskLogSearchInput
): TaskLog

type TaskLog {
  createdAt: String
  executionId: String
  executionTime: String
  id: ID
  input: JSON
  message: String
  originalParentTaskId: String
  originalPrincipalOrgId: ID
  originalPrincipalOrgName: String
  originalRunAsOrgId: String
  originalRunAsOrgName: String
  originalWorkflowExecutionId: String
  originalWorkflowTaskId: String
  originalWorkflowTaskName: String
  parentTask: WorkflowTask
  parentTaskId: ID
  result: JSON
  runAsOrg: Organization
  runAsOrgId: ID
  principalOrg: Organization
  principalOrgId: ID
  status: String
  taskExecutionId: ID
  updatedAt: String
  workflow: Workflow
  workflowExecution: WorkflowExecution
  workflowExecutionId: String
  workflowTask: WorkflowTask
  workflowTaskId: ID
}
```

**`TaskLogWhereInput` supported fields**

| Field                         | Type     |
| ----------------------------- | -------- |
| `executionTime`               | `String` |
| `id`                          | `ID`     |
| `input`                       | `JSON`   |
| `message`                     | `String` |
| `originalParentTaskId`        | `String` |
| `originalPrincipalOrgId`      | `String` |
| `originalPrincipalOrgName`    | `String` |
| `originalRunAsOrgId`          | `String` |
| `originalRunAsOrgName`        | `String` |
| `originalWorkflowExecutionId` | `String` |
| `originalWorkflowTaskId`      | `String` |
| `parentTaskId`                | `ID`     |
| `principalOrgId`              | `ID`     |
| `result`                      | `JSON`   |
| `runAsOrgId`                  | `ID`     |
| `status`                      | `String` |
| `taskExecutionId`             | `ID`     |
| `workflowExecutionId`         | `ID`     |
| `workflowTaskId`              | `ID`     |

**`TaskLogSearchInput` supported fields**

| Field                      | Wrapper                 |
| -------------------------- | ----------------------- |
| `id`                       | `ID` (equality only)    |
| `originalPrincipalOrgId`   | `string_comparison_exp` |
| `originalPrincipalOrgName` | `string_comparison_exp` |
| `originalRunAsOrgId`       | `string_comparison_exp` |
| `originalRunAsOrgName`     | `string_comparison_exp` |
| `principalOrgId`           | `id_comparison_exp`     |
| `runAsOrgId`               | `id_comparison_exp`     |
| `status`                   | `string_comparison_exp` |
| `workflowExecutionId`      | `id_comparison_exp`     |

**Is `where` or `search` mandatory?**

Yes - `where` or `search` with at least `id` or `workflowExecutionId` is required.

Note: `input` and `result` are sensitive fields and may be redacted.

</details>

<details>

<summary><strong><code>taskLogs</code></strong>-Gets multiple task log entries.</summary>

**GraphQL schema**

```graphql
taskLogs(
  where: TaskLogWhereInput
  search: TaskLogSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["createdAt"]]
  ): [TaskLog!]!
```

**`TaskLogWhereInput` supported fields**

| Field                         | Type     |
| ----------------------------- | -------- |
| `executionTime`               | `String` |
| `id`                          | `ID`     |
| `input`                       | `JSON`   |
| `message`                     | `String` |
| `originalParentTaskId`        | `String` |
| `originalPrincipalOrgId`      | `String` |
| `originalPrincipalOrgName`    | `String` |
| `originalRunAsOrgId`          | `String` |
| `originalRunAsOrgName`        | `String` |
| `originalWorkflowExecutionId` | `String` |
| `originalWorkflowTaskId`      | `String` |
| `parentTaskId`                | `ID`     |
| `principalOrgId`              | `ID`     |
| `result`                      | `JSON`   |
| `runAsOrgId`                  | `ID`     |
| `status`                      | `String` |
| `taskExecutionId`             | `ID`     |
| `workflowExecutionId`         | `ID`     |
| `workflowTaskId`              | `ID`     |

**`TaskLogSearchInput` supported fields**

| Field                      | Wrapper                 |
| -------------------------- | ----------------------- |
| `id`                       | `ID` (equality only)    |
| `originalPrincipalOrgId`   | `string_comparison_exp` |
| `originalPrincipalOrgName` | `string_comparison_exp` |
| `originalRunAsOrgId`       | `string_comparison_exp` |
| `originalRunAsOrgName`     | `string_comparison_exp` |
| `principalOrgId`           | `id_comparison_exp`     |
| `runAsOrgId`               | `id_comparison_exp`     |
| `status`                   | `string_comparison_exp` |
| `workflowExecutionId`      | `id_comparison_exp`     |

**Is `where` or `search` mandatory?**

workflowExecutionId`(via`where`or`search`),` limit`, and` offset`.` task\_logs\` is one of the three large unbounded tables — unscoped or unpaginated calls will time out.

</details>

#### **Template management queries**

<details>

<summary><strong><code>template</code></strong>- Gets a specific template.</summary>

**GraphQL schema**

```graphql
template(where: TemplateInput): Template

type Template {
  body: String!
  clonedFrom: Template
  clonedFromId: ID
  cloneOverrides: JSON
  clones: [Template]
  contentType: String!
  context: JSON
  createdAt: String!
  description: String
  id: ID!
  isShared: Boolean
  isSynchronized: Boolean
  language: String!
  name: String!
  organization: Organization!
  orgId: ID!
  permission: Permission
  tags: [Tag!]!
  unpackedFrom: Crate
  unpackedFromId: ID
  updatedAt: String!
  updatedBy: User
  updatedById: ID
}
```

**`TemplateInput` (where) supported fields**

| Field            | Type      |
| ---------------- | --------- |
| `body`           | `String`  |
| `clonedFromId`   | `ID`      |
| `contentType`    | `String`  |
| `description`    | `String`  |
| `id`             | `ID`      |
| `isSynchronized` | `Boolean` |
| `language`       | `String`  |
| `name`           | `String`  |
| `orgId`          | `ID`      |
| `tagIds`         | `[ID!]`   |
| `unpackedFromId` | `ID`      |

**Is `where` or `search` mandatory?**

Yes - `where` with at least one filter field, typically `id`. There is no `search` input.

</details>

<details>

<summary><strong><code>templates</code></strong>-Gets multiple templates.</summary>

**GraphQL schema**

```graphql
templates(
  where: TemplateInput
  search: TemplateSearch
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [Template!]!
```

**`TemplateSearch` supported fields**

| Field            | Wrapper                            |
| ---------------- | ---------------------------------- |
| `clonedFromId`   | `id_comparison_exp`                |
| `contentType`    | `string_comparison_exp`            |
| `description`    | `string_comparison_exp`            |
| `id`             | `id_comparison_exp`                |
| `isSynchronized` | `bool_comparison_exp`              |
| `name`           | `string_comparison_exp`            |
| `organization`   | `OrganizationSearchInput` (nested) |
| `unpackedFromId` | `id_comparison_exp`                |

**Is `where` or `search` mandatory?**

`limit` and `offset`

</details>

<details>

<summary><strong><code>jinjaTemplate</code></strong>-Gets a Jinja template for rendering.</summary>

**GraphQL schema**

```graphql
jinjaTemplate(where: TemplateInput): Template
```

</details>

#### **Trigger type queries**

<details>

<summary><strong><code>triggerType</code></strong>-Gets a specific trigger type.</summary>

**GraphQL schema**

```graphql
triggerType(where: TriggerTypeWhereInput): TriggerType

type TriggerType {
  description: String
  id: ID
  name: String
  pack: Pack
  parametersSchema(filterArg: JSON, orgId: ID): JSON
  outputSchema: JSON
  ref: String
  isPoll: Boolean
  isWebhook: Boolean
  sensorType: SensorType
  triggers: [Trigger!]!
  webhookUrlTemplate: String
  canRunForManagedOrgs: Boolean
  enabled: Boolean
}
```

**`TriggerTypeWhereInput` supported fields**

| Field              | Type                         |
| ------------------ | ---------------------------- |
| `description`      | `String`                     |
| `id`               | `ID`                         |
| `isPoll`           | `Boolean`                    |
| `isWebhook`        | `Boolean`                    |
| `name`             | `String`                     |
| `packId`           | `ID`                         |
| `parametersSchema` | `JSON`                       |
| `outputSchema`     | `JSON`                       |
| `ref`              | `String`                     |
| `triggers`         | `TriggerWhereInput` (nested) |
| `enabled`          | `Boolean`                    |

**Is `where` or `search` mandatory?**

Yes - `where` with at least one filter field. There is no `search` input.

</details>

<details>

<summary><strong><code>triggerTypes</code></strong>-Gets multiple trigger types.</summary>

**GraphQL schema**

```graphql
triggerTypes(
  where: TriggerTypeWhereInput
  search: TriggerTypesSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [TriggerType!]!

input TriggerTypesSearchInput {
  description: string_comparison_exp
  id: id_comparison_exp
  isPoll: Boolean
  isWebhook: Boolean
  name: string_comparison_exp
  pack: PackSearchInput
  parametersSchema: json_comparison_exp
  outputSchema: json_comparison_exp
  ref: string_comparison_exp
  triggers: TriggerSearchInput
  enabled: bool_comparison_exp
```

| Field              | Wrapper                       |
| ------------------ | ----------------------------- |
| `description`      | `string_comparison_exp`       |
| `id`               | `id_comparison_exp`           |
| `isPoll`           | `Boolean` (equality only)     |
| `isWebhook`        | `Boolean` (equality only)     |
| `name`             | `string_comparison_exp`       |
| `pack`             | `PackSearchInput` (nested)    |
| `parametersSchema` | `json_comparison_exp`         |
| `outputSchema`     | `json_comparison_exp`         |
| `ref`              | `string_comparison_exp`       |
| `triggers`         | `TriggerSearchInput` (nested) |
| `enabled`          | `bool_comparison_exp`         |

**Is `where` or `search` mandatory?**

`limit` and `offset`

</details>

#### **Trigger management queries**

<details>

<summary><strong><code>trigger</code></strong>-Gets a specific trigger.</summary>

**GraphQL schema**

```graphql
trigger(
  where: TriggerWhereInput
  search: TriggerSearchInput
): Trigger

type Trigger {
  activatedForOrgs: [Organization!]!
  autoActivateManagedOrgs: Boolean!
  clonedFrom: Trigger
  clonedFromId: ID
  cloneOverrides: JSON
  clones: [Trigger]!
  criteria: JSON
  description: String
  enabled: Boolean
  id: ID!
  isSynchronized: Boolean
  name: String
  organization: Organization!
  orgId: ID
  orgInstances: [OrgTriggerInstance]
  packOverrides: [PackOverride!]
  parameters: JSON
  state: JSON
  tags: [Tag!]!
  triggerType: TriggerType
  triggerTypeId: ID!
  unpackedFrom: Crate
  unpackedFromId: ID
  vars: [JSON]
  workflowId: ID!
  form: Form
  formId: ID
  workflow: Workflow!
}
```

**`TriggerWhereInput` supported fields**

| Field            | Type                                    |
| ---------------- | --------------------------------------- |
| `clonedFromId`   | `ID`                                    |
| `criteria`       | `JSON`                                  |
| `description`    | `String`                                |
| `enabled`        | `Boolean`                               |
| `formId`         | `ID`                                    |
| `id`             | `ID`                                    |
| `isSynchronized` | `Boolean`                               |
| `name`           | `String`                                |
| `orgId`          | `ID`                                    |
| `orgInstances`   | `OrgTriggerInstanceWhereInput` (nested) |
| `parameters`     | `JSON`                                  |
| `state`          | `JSON`                                  |
| `triggerType`    | `TriggerTypeInput` (nested)             |
| `triggerTypeId`  | `ID`                                    |
| `unpackedFromId` | `ID`                                    |
| `workflowId`     | `ID`                                    |

**`TriggerSearchInput` supported fields**

| Field            | Wrapper                                  |
| ---------------- | ---------------------------------------- |
| `clonedFromId`   | `id_comparison_exp`                      |
| `criteria`       | `json_comparison_exp`                    |
| `description`    | `string_comparison_exp`                  |
| `enabled`        | `Boolean` (equality only)                |
| `formId`         | `id_comparison_exp`                      |
| `id`             | `id_comparison_exp`                      |
| `isSynchronized` | `bool_comparison_exp`                    |
| `name`           | `string_comparison_exp`                  |
| `organization`   | `OrganizationSearchInput` (nested)       |
| `orgId`          | `id_comparison_exp`                      |
| `orgInstances`   | `OrgTriggerInstanceSearchInput` (nested) |
| `packOverrides`  | `PackOverrideSearchInput` (nested)       |
| `parameters`     | `json_comparison_exp`                    |
| `state`          | `json_comparison_exp`                    |
| `triggerType`    | `TriggerTypesSearchInput` (nested)       |
| `triggerTypeId`  | `id_comparison_exp`                      |
| `unpackedFromId` | `id_comparison_exp`                      |
| `workflow`       | `WorkflowSearch` (nested)                |
| `workflowId`     | `id_comparison_exp`                      |

**Is `where` or `search` mandatory?**

Yes - `where` or `search` with at least one filter field.

</details>

<details>

<summary><strong><code>workflowCompletionListeners</code></strong>-Gets triggers configured to listen for workflow completion events.</summary>

**GraphQL schema:**

```graphql
workflowCompletionListeners(
  where: TriggerWhereInput
  search: TriggerSearchInput
): [Trigger!]!
```

</details>

<details>

<summary><strong><code>triggers</code></strong>-Gets multiple triggers.</summary>

**GraphQL schema**

```graphql
triggers(
  includeUnlisted: Boolean
  where: TriggerWhereInput
  search: TriggerSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [Trigger!]!
```

**`TriggerWhereInput` supported fields**

| Field            | Type                                    |
| ---------------- | --------------------------------------- |
| `clonedFromId`   | `ID`                                    |
| `criteria`       | `JSON`                                  |
| `description`    | `String`                                |
| `enabled`        | `Boolean`                               |
| `formId`         | `ID`                                    |
| `id`             | `ID`                                    |
| `isSynchronized` | `Boolean`                               |
| `name`           | `String`                                |
| `orgId`          | `ID`                                    |
| `orgInstances`   | `OrgTriggerInstanceWhereInput` (nested) |
| `parameters`     | `JSON`                                  |
| `state`          | `JSON`                                  |
| `triggerType`    | `TriggerTypeInput` (nested)             |
| `triggerTypeId`  | `ID`                                    |
| `unpackedFromId` | `ID`                                    |
| `workflowId`     | `ID`                                    |

**`TriggerSearchInput` supported fields**

| Field            | Wrapper                                  |
| ---------------- | ---------------------------------------- |
| `clonedFromId`   | `id_comparison_exp`                      |
| `criteria`       | `json_comparison_exp`                    |
| `description`    | `string_comparison_exp`                  |
| `enabled`        | `Boolean` (equality only)                |
| `formId`         | `id_comparison_exp`                      |
| `id`             | `id_comparison_exp`                      |
| `isSynchronized` | `bool_comparison_exp`                    |
| `name`           | `string_comparison_exp`                  |
| `organization`   | `OrganizationSearchInput` (nested)       |
| `orgId`          | `id_comparison_exp`                      |
| `orgInstances`   | `OrgTriggerInstanceSearchInput` (nested) |
| `packOverrides`  | `PackOverrideSearchInput` (nested)       |
| `parameters`     | `json_comparison_exp`                    |
| `state`          | `json_comparison_exp`                    |
| `triggerType`    | `TriggerTypesSearchInput` (nested)       |
| `triggerTypeId`  | `id_comparison_exp`                      |
| `unpackedFromId` | `id_comparison_exp`                      |
| `workflow`       | `WorkflowSearch` (nested)                |
| `workflowId`     | `id_comparison_exp`                      |

**Is `where` or `search` mandatory?**

Yes - `limit` and `offset`, plus a scoping filter (typically `where: { orgId: <id> }` or `workflowId`). `hasTagIds` and `excludeTagIds` are convenience filters layered on top of `where`/`search`.

</details>

<details>

<summary><strong><code>triggerDbNotificationErrors</code></strong>-Gets database notification errors for a trigger.</summary>

**GraphQL schema**

```graphql
triggerDbNotificationErrors(triggerId: ID!): [DatabaseNotificationError!]!

type DatabaseNotificationError {
  detail: String!
  raised_at: String!
  type: String!
}
```

**Is `where` or `search` mandatory?**

`triggerId`

</details>

#### **User invite queries**

<details>

<summary><strong><code>userInvite</code></strong>-Gets a specific user invite.</summary>

**GraphQL schema**

```graphql
userInvite(
  where: UserInviteWhereInput
  search: UserInviteSearchInput
): UserInvite

type UserInvite {
  acceptedAt: String
  createdAt: String
  createdBy: User
  createdById: ID
  email: String!
  id: ID!
  isAccepted: Boolean
  organization: Organization!
  orgId: ID!
  roleIds: [String]
  roles: [JSON]
  sendEmail: Boolean
}
```

**`UserInviteWhereInput` supported fields**

| Field          | Type                              |
| -------------- | --------------------------------- |
| `acceptedAt`   | `String`                          |
| `email`        | `String`                          |
| `id`           | `ID`                              |
| `isAccepted`   | `Boolean`                         |
| `organization` | `OrganizationWhereInput` (nested) |
| `orgId`        | `ID`                              |
| `sendEmail`    | `Boolean`                         |

**`UserInviteSearchInput` supported fields**

| Field          | Wrapper                            |
| -------------- | ---------------------------------- |
| `email`        | `string_comparison_exp`            |
| `id`           | `id_comparison_exp`                |
| `organization` | `OrganizationSearchInput` (nested) |
| `orgId`        | `id_comparison_exp`                |
| `sendEmail`    | `bool_comparison_exp`              |

**Is `where` or `search` mandatory?**

Yes - use `where` or `search` with at least one filter field. Only available when `ENABLE_ADMIN_APPROVAL_REQUESTS` is OFF.

</details>

<details>

<summary><strong><code>userInvites</code></strong>-Gets multiple user invites.</summary>

**GraphQL schema**

```graphql
userInvites(
  where: UserInviteWhereInput
  search: UserInviteSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["email"]]
): [UserInvite]
```

**`UserInviteWhereInput` supported fields**

| Field          | Type                              |
| -------------- | --------------------------------- |
| `acceptedAt`   | `String`                          |
| `email`        | `String`                          |
| `id`           | `ID`                              |
| `isAccepted`   | `Boolean`                         |
| `organization` | `OrganizationWhereInput` (nested) |
| `orgId`        | `ID`                              |
| `sendEmail`    | `Boolean`                         |

**`UserInviteSearchInput` supported fields**

| Field          | Wrapper                            |
| -------------- | ---------------------------------- |
| `email`        | `string_comparison_exp`            |
| `id`           | `id_comparison_exp`                |
| `organization` | `OrganizationSearchInput` (nested) |
| `orgId`        | `id_comparison_exp`                |
| `sendEmail`    | `bool_comparison_exp`              |

**Is `where` or `search` mandatory?**

`limit`, `offset`, and a scoping filter, typically `where: { orgId: <id> }`). Only available when `ENABLE_ADMIN_APPROVAL_REQUESTS` is OFF.

</details>

#### **User management queries**

<details>

<summary><strong><code>me</code></strong>-Gets current user information.</summary>

**GraphQL schema**

```graphql
me: User

type User {
  createdAt: String
  favoriteActions: [UserFavoriteAction!]!
  id: ID
  isApiUser: Boolean
  isSuperuser: Boolean
  isTestUser: Boolean
  managedOrgs: [Organization!]!
  orgId: ID
  organization: Organization
  preferences: UserPreferences!
  roleIds: [String!]!
  roles: [JSON]
  sub: String
  username: String
  parentUserId: ID
  parentUsername: String
}
```

**Is `where` or `search` mandatory?**

No - returns the currently authenticated user and their organization respectively.

</details>

<details>

<summary><strong><code>userOrganization</code></strong>-Gets the user's organization.</summary>

**GraphQL schema:**

```graphql
userOrganization: Organization
```

</details>

<details>

<summary><strong><code>user</code></strong>-Gets a specific user.</summary>

**GraphQL schema**

```graphql
user(where: UserWhereInput, search: UserSearchInput): User
```

**`GetUserWhereInput` supported fields**

| Field          | Type                              |
| -------------- | --------------------------------- |
| `id`           | `ID`                              |
| `isSuperuser`  | `Boolean`                         |
| `managedOrgs`  | `OrganizationWhereInput` (nested) |
| `organization` | `OrganizationWhereInput` (nested) |
| `orgId`        | `ID!` (required)                  |
| `roleIds`      | `[String!]`                       |
| `sub`          | `String`                          |
| `username`     | `String`                          |
| `isTestUser`   | `Boolean`                         |
| `isApiUser`    | `Boolean`                         |

**`UserSearchInput` supported fields**

| Field          | Wrapper                            |
| -------------- | ---------------------------------- |
| `createdAt`    | `string_comparison_exp`            |
| `id`           | `id_comparison_exp`                |
| `isApiUser`    | `bool_comparison_exp`              |
| `isSuperuser`  | `bool_comparison_exp`              |
| `isTestUser`   | `bool_comparison_exp`              |
| `managedOrgs`  | `OrganizationSearchInput` (nested) |
| `organization` | `OrganizationSearchInput` (nested) |
| `orgId`        | `id_comparison_exp`                |
| `roleIds`      | `string_comparison_exp`            |
| `sub`          | `string_comparison_exp`            |
| `username`     | `string_comparison_exp`            |

**Is `where` or `search` mandatory?**

`orgId` on `where` is non-null — every user lookup must be scoped to an org. `createdAt` is filterable only via `search`, not `where`.

</details>

<details>

<summary><strong><code>users</code></strong>-Gets multiple users.</summary>

**GraphQL schema**

```graphql
users(
  where: UserWhereInput
  search: UserSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["username"]]
): [User!]!
```

**`GetUserWhereInput` supported fields**

| Field          | Type                              |
| -------------- | --------------------------------- |
| `id`           | `ID`                              |
| `isSuperuser`  | `Boolean`                         |
| `managedOrgs`  | `OrganizationWhereInput` (nested) |
| `organization` | `OrganizationWhereInput` (nested) |
| `orgId`        | `ID!` (required)                  |
| `roleIds`      | `[String!]`                       |
| `sub`          | `String`                          |
| `username`     | `String`                          |
| `isTestUser`   | `Boolean`                         |
| `isApiUser`    | `Boolean`                         |

**`UserSearchInput` supported fields**

| Field          | Wrapper                            |
| -------------- | ---------------------------------- |
| `createdAt`    | `string_comparison_exp`            |
| `id`           | `id_comparison_exp`                |
| `isApiUser`    | `bool_comparison_exp`              |
| `isSuperuser`  | `bool_comparison_exp`              |
| `isTestUser`   | `bool_comparison_exp`              |
| `managedOrgs`  | `OrganizationSearchInput` (nested) |
| `organization` | `OrganizationSearchInput` (nested) |
| `orgId`        | `id_comparison_exp`                |
| `roleIds`      | `string_comparison_exp`            |
| `sub`          | `string_comparison_exp`            |
| `username`     | `string_comparison_exp`            |

**Is `where` or `search` mandatory?**

`orgId` on `where` (non-null), `limit`, and `offset`.

</details>

<details>

<summary><strong><code>getTestUsers</code></strong>-Gets test users.</summary>

**GraphQL schema**

```graphql
getTestUsers(where: UserWhereInput): [User!]!
```

**Is `where` or `search` mandatory?**

Yes - requires `orgId` on `where`.

</details>

<details>

<summary><strong><code>getTestUserSession</code></strong>-Gets current test user session.</summary>

**GraphQL schema**

```graphql
getTestUserSession: User
```

**Is `where` or `search` mandatory?**

No.

</details>

#### **Workflow analytics queries**

<details>

<summary><strong><code>timeSavedGroupByWorkflow</code></strong>-Gets time saved statistics grouped by workflow.</summary>

**GraphQL schema**

```graphql
timeSavedGroupByWorkflow(
  orgId: ID!
  workflowStatus: String
  updatedAt: String!
  useStatsTable: Boolean! = true
): [TimeSavedGroupByWorkflow!]!

type TimeSavedGroupByWorkflow {
  workflowId: ID!
  workflowName: String
  secondsSaved: Int
  totalExecutions: Int
  successfulExecutions: Int
  failedExecutions: Int
}
```

**Is `where` or `search` mandatory?**

`orgId`, `updatedAt`, `useStatsTable`

</details>

<details>

<summary><strong><code>timeSavedGroupBySubOrg</code></strong>-Gets time saved statistics grouped by sub-organization.</summary>

**GraphQL schema:**

```graphql
timeSavedGroupBySubOrg(
  orgId: ID!
  workflowStatus: String
  updatedAt: String!
  useStatsTable: Boolean! = true
): [TimeSavedGroupByOrg!]!

type TimeSavedGroupByOrg {
  workflowId: ID!
  workflowName: String
  secondsSaved: Int
  totalExecutions: Int
  ranForOrg: String
  }
```

</details>

<details>

<summary><strong><code>workflowExecutionStats</code></strong>-Gets workflow execution statistics.</summary>

**GraphQL schema**

```graphql
workflowExecutionStats(
  orgId: ID!
  createdSince: String!
  rollUpTimeSaved: Boolean
  includeSubWorkflows: Boolean
): WorkflowExecutionStats

type WorkflowExecutionStats {
  delayed: Int!
  failed: Int!
  humanSecondsSaved: Int!
  paused: Int!
  pending: Int!
  running: Int!
  succeeded: Int!
}
```

**Is `where` or `search` mandatory?**

`orgId`, `createdSince`.

</details>

<details>

<summary><strong><code>workflowExecution</code></strong>-Gets a specific workflow execution.</summary>

**GraphQL schema**

```graphql
workflowExecution(
  where: WorkflowExecutionWhereInput
  search: WorkflowExecutionSearchInput
): WorkflowExecution

type WorkflowExecution {
  childExecutions: [WorkflowExecution!]!
  completionHandledExecution: WorkflowExecution
  completionHandlerExecutions: [WorkflowExecution!]!
  conductor: WorkflowExecutionConductor
  createdAt: String
  id: ID
  numAwaitingResponseTasks: Int
  numSuccessfulTasks: Int
  organization: Organization!
  orgId: ID!
  originatingExecutionId: ID
  parentExecution: WorkflowExecution
  parentExecutionId: ID
  parentTaskExecutionId: ID
  pendingTasks: [PendingTask]
  processedCompletionAt: String
  status: String
  subExecutions: [WorkflowExecution!]!
  taskLogs: [TaskLog!]!
  updatedAt: String
  workflow: Workflow!
}
```

**`WorkflowExecutionWhereInput` supported fields**

| Field                      | Type                 | Notes                            |
| -------------------------- | -------------------- | -------------------------------- |
| `id`                       | `ID`                 |                                  |
| `orgId`                    | `ID`                 | **Required in practice**         |
| `originatingExecutionId`   | `ID`                 |                                  |
| `status`                   | `String`             | Exact match only                 |
| `numAwaitingResponseTasks` | `Int`                |                                  |
| `workflow`                 | `WorkflowWhereInput` | Nested filter on parent workflow |
| `workflowId`               | `ID`                 |                                  |

Not filterable via `where` - use `search` instead: `createdAt`, `processedCompletionAt`, `organization`

**`WorkflowExecutionSearchInput` supported fields**

| Field                      | Wrapper                   |
| -------------------------- | ------------------------- |
| `id`                       | `id_comparison_exp`       |
| `orgId`                    | `id_comparison_exp`       |
| `originatingExecutionId`   | `id_comparison_exp`       |
| `status`                   | `string_comparison_exp`   |
| `numAwaitingResponseTasks` | `int_comparison_exp`      |
| `workflow`                 | `WorkflowSearch`          |
| `createdAt`                | `string_comparison_exp`   |
| `processedCompletionAt`    | `string_comparison_exp`   |
| `organization`             | `OrganizationSearchInput` |

**Is `where` or `search` mandatory?**

Yes - `id` via `where` or `search`. `workflow_executions` is partitioned — pass `id` so the lookup hits a single partition. `createdAt` and `processedCompletionAt` are filterable only via `search`.

</details>

<details>

<summary><strong><code>workflowExecutions</code></strong>-Gets multiple workflow executions.</summary>

**GraphQL schema**

```graphql
workflowExecutions(
  where: WorkflowExecutionWhereInput
  search: WorkflowExecutionSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["createdAt"]]
  includeSubOrgs: Boolean
): [WorkflowExecution]
```

**`WorkflowExecutionWhereInput` supported fields**

| Field                      | Type                 | Notes                            |
| -------------------------- | -------------------- | -------------------------------- |
| `id`                       | `ID`                 |                                  |
| `orgId`                    | `ID`                 | **Required in practice**         |
| `originatingExecutionId`   | `ID`                 |                                  |
| `status`                   | `String`             | Exact match only                 |
| `numAwaitingResponseTasks` | `Int`                |                                  |
| `workflow`                 | `WorkflowWhereInput` | Nested filter on parent workflow |
| `workflowId`               | `ID`                 |                                  |

Not filterable via `where` - use `search` instead: `createdAt`, `processedCompletionAt`, `organization`

**`WorkflowExecutionSearchInput` supported fields**

| Field                      | Wrapper                   |
| -------------------------- | ------------------------- |
| `id`                       | `id_comparison_exp`       |
| `orgId`                    | `id_comparison_exp`       |
| `originatingExecutionId`   | `id_comparison_exp`       |
| `status`                   | `string_comparison_exp`   |
| `numAwaitingResponseTasks` | `int_comparison_exp`      |
| `workflow`                 | `WorkflowSearch`          |
| `createdAt`                | `string_comparison_exp`   |
| `processedCompletionAt`    | `string_comparison_exp`   |
| `organization`             | `OrganizationSearchInput` |

**Is `where` or `search` mandatory?**

Yes, strongly. `workflow_executions` is the largest of the three unbounded tables. An unscoped query is essentially guaranteed to time-out. Always pass:

* `orgId` (via `where` or `search`)
* `limit` (recommended ≤ 50; payloads are large)
* `offset` for pagination
* A `createdAt` lower bound on `search` if you can will drastically narrow the partition scan

Shared pagination rule: Every plural query should be called with `limit` and `offset`. Queries against the largest tables— `workflowExecutions`, `taskLogs`, `organizations`, and anything that traverses into them— will time out without it.

**Worked example: Recent failed executions for the current org**

```yaml
operation: workflowExecutions
variables:
  where:
    orgId: "{{ CTX.organization.id }}"
    status: "FAILED"
  search:
    createdAt: { _gte: "{{ CTX.now.minus(days=7).isoformat() }}" }
  limit: 50
  offset: 0
  order: [["createdAt", "DESC"]]
```

</details>

<details>

<summary><strong><code>workflowExecutionContexts</code></strong>-Gets workflow execution contexts.</summary>

**GraphQL schema**

```graphql
workflowExecutionContexts(workflowExecutionId: ID!): JSON
```

**Is `where` or `search` mandatory?**

`workflowExecutionId`. Always scoped to one execution — there is no list form.

</details>

<details>

<summary><strong><code>dailyTimeSavedByDateRange</code></strong>-Gets daily time saved within a date range.</summary>

**GraphQL schema**

```graphql
dailyTimeSavedByDateRange(
  orgId: ID!
  startDate: String!
  endDate: String!
): [TimeSavedByDate!]!

type TimeSavedByDate {
  date: String!
  seconds: Int!
}
```

**Is `where` or `search` mandatory?**

`orgId`, `startDate`, `endDate`

</details>

#### **Workflow patch queries**

<details>

<summary><strong><code>workflowPatch</code></strong>-Gets a specific workflow patch.</summary>

**GraphQL schema**

```graphql
workflowPatch(id: ID!): WorkflowPatch!

type WorkflowPatch {
  id: ID!
  patchType: PatchType!
  patch: JSON!
  comment: String!
  commentDescription: String
  user: User
  workflowId: ID!
  foreignId: ID
  createdAt: String!
  updatedAt: String!
}
```

**Is `where` or `search` mandatory?**

`id`

</details>

<details>

<summary><strong><code>workflowPatches</code></strong>-Gets multiple workflow patches.</summary>

**GraphQL schema**

```graphql
workflowPatches(
  where: WorkflowPatchWhereInput
  orderBy: WorkflowPatchOrderByInput = createdAt_DESC
  limit: Int
  offset: Int
  createdSince: String
): [WorkflowPatch!]!
```

**`WorkflowPatchWhereInput` — supported fields**

| Field        | Type                      |
| ------------ | ------------------------- |
| `comment`    | `String`                  |
| `user`       | `UserWhereInput` (nested) |
| `patchType`  | `PatchType`               |
| `workflowId` | `ID`                      |
| `foreignId`  | `ID`                      |
| `createdAt`  | `String`                  |
| `updatedAt`  | `String`                  |

**Is `where` or `search` mandatory?**

Uses `orderBy` (an enum), not the `order` array used by most other plural queries. `where: { workflowId }`, `limit`, `offset`.

There is no `search` input.

</details>

#### **Workflow management queries**

<details>

<summary><strong><code>workflow</code></strong>-Gets a specific workflow.</summary>

**GraphQL schema**

```graphql
workflow(
  where: WorkflowWhereInput
  search: WorkflowSearch
): Workflow

input WorkflowWhereInput {
  clonedFromId: ID
  unpackedFromId: ID
  crates: CrateWhereInput
  description: String
  id: ID
  input: [String]
  isSynchronized: Boolean
  name: String
  orgId: ID
  output: [JSON]
  schemaVersion: String
  timeout: Int
  version: String
  type: WorkflowType
  visibleForOrganizations: ID
}

input WorkflowSearch {
  createdAt: string_comparison_exp
  clonedFromId: id_comparison_exp
  description: string_comparison_exp
  id: id_comparison_exp
  input: string_comparison_exp
  isSynchronized: bool_comparison_exp
  name: string_comparison_exp
  orgId: id_comparison_exp
  organization: OrganizationSearchInput
  org_id: id_comparison_exp
  output: string_comparison_exp
  schemaVersion: string_comparison_exp
  tags: TagSearchInput
  tasks: id_comparison_exp
  timeout: int_comparison_exp
  tokens: json_comparison_exp
  updatedAt: string_comparison_exp
  updatedBy: UserSearchInput
  version: string_comparison_exp
  visibleForOrganizations: id_comparison_exp
}
```

**`WorkflowWhereInput` supported fields**

| Field                     | Type                       |
| ------------------------- | -------------------------- |
| `clonedFromId`            | `ID`                       |
| `unpackedFromId`          | `ID`                       |
| `crates`                  | `CrateWhereInput` (nested) |
| `description`             | `String`                   |
| `id`                      | `ID`                       |
| `input`                   | `[String]`                 |
| `isSynchronized`          | `Boolean`                  |
| `name`                    | `String`                   |
| `orgId`                   | `ID`                       |
| `output`                  | `[JSON]`                   |
| `schemaVersion`           | `String`                   |
| `timeout`                 | `Int`                      |
| `version`                 | `String`                   |
| `type`                    | `WorkflowType`             |
| `visibleForOrganizations` | `ID`                       |

**`WorkflowSearch` supported fields**

| Field                     | Wrapper                            |
| ------------------------- | ---------------------------------- |
| `createdAt`               | `string_comparison_exp`            |
| `clonedFromId`            | `id_comparison_exp`                |
| `description`             | `string_comparison_exp`            |
| `id`                      | `id_comparison_exp`                |
| `input`                   | `string_comparison_exp`            |
| `isSynchronized`          | `bool_comparison_exp`              |
| `name`                    | `string_comparison_exp`            |
| `orgId`                   | `id_comparison_exp`                |
| `organization`            | `OrganizationSearchInput` (nested) |
| `org_id`                  | `id_comparison_exp` (alias)        |
| `output`                  | `string_comparison_exp`            |
| `schemaVersion`           | `string_comparison_exp`            |
| `tags`                    | `TagSearchInput` (nested)          |
| `tasks`                   | `id_comparison_exp`                |
| `timeout`                 | `int_comparison_exp`               |
| `tokens`                  | `json_comparison_exp`              |
| `updatedAt`               | `string_comparison_exp`            |
| `updatedBy`               | `UserSearchInput` (nested)         |
| `version`                 | `string_comparison_exp`            |
| `visibleForOrganizations` | `id_comparison_exp`                |

**Is `where` or `search` mandatory?**

Yes - `id` via `where` or `search`.\
Note: `createdAt`, `updatedAt`, and `tokens` are filterable only via `search`.

</details>

<details>

<summary><strong><code>workflows</code></strong>-Gets multiple workflows.</summary>

**GraphQL schema**

```graphql
workflows(
  where: WorkflowWhereInput
  search: WorkflowSearch
  hasListeners: Boolean
  hasParentWorkflows: Boolean
  hasTriggers: Boolean
  hasTriggerOfType: TriggerOfType
  hasTokens: Boolean
  isOptionsGenerator: Boolean
  isClone: Boolean
  isSyncClone: Boolean
  hasClones: Boolean
  isCrate: Boolean
  isCrateSource: Boolean
  hasTagIds: [ID!]
  excludeTagIds: [ID!]
  requireMatchingTasks: Boolean
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [Workflow!]!
```

**`WorkflowWhereInput` supported fields**

| Field                     | Type                       |
| ------------------------- | -------------------------- |
| `clonedFromId`            | `ID`                       |
| `unpackedFromId`          | `ID`                       |
| `crates`                  | `CrateWhereInput` (nested) |
| `description`             | `String`                   |
| `id`                      | `ID`                       |
| `input`                   | `[String]`                 |
| `isSynchronized`          | `Boolean`                  |
| `name`                    | `String`                   |
| `orgId`                   | `ID`                       |
| `output`                  | `[JSON]`                   |
| `schemaVersion`           | `String`                   |
| `timeout`                 | `Int`                      |
| `version`                 | `String`                   |
| `type`                    | `WorkflowType`             |
| `visibleForOrganizations` | `ID`                       |

**`WorkflowSearch` supported fields**

| Field                     | Wrapper                            |
| ------------------------- | ---------------------------------- |
| `createdAt`               | `string_comparison_exp`            |
| `clonedFromId`            | `id_comparison_exp`                |
| `description`             | `string_comparison_exp`            |
| `id`                      | `id_comparison_exp`                |
| `input`                   | `string_comparison_exp`            |
| `isSynchronized`          | `bool_comparison_exp`              |
| `name`                    | `string_comparison_exp`            |
| `orgId`                   | `id_comparison_exp`                |
| `organization`            | `OrganizationSearchInput` (nested) |
| `org_id`                  | `id_comparison_exp` (alias)        |
| `output`                  | `string_comparison_exp`            |
| `schemaVersion`           | `string_comparison_exp`            |
| `tags`                    | `TagSearchInput` (nested)          |
| `tasks`                   | `id_comparison_exp`                |
| `timeout`                 | `int_comparison_exp`               |
| `tokens`                  | `json_comparison_exp`              |
| `updatedAt`               | `string_comparison_exp`            |
| `updatedBy`               | `UserSearchInput` (nested)         |
| `version`                 | `string_comparison_exp`            |
| `visibleForOrganizations` | `id_comparison_exp`                |

**Is `where` or `search` mandatory?**

`limit` and `offset`. Scope by `orgId` — `workflows` is a large table and unscoped calls will be slow.

</details>

<details>

<summary><strong><code>workflowNote</code></strong>-Gets a specific workflow note.</summary>

**GraphQL schema**

```graphql
workflowNote(where: WorkflowNoteWhereInput): WorkflowNote

type WorkflowNote {
  id: ID
  title: String
  clonedFrom: WorkflowNote
  clonedFromId: ID
  createdAt: String
  content: String
  metadata: JSON
  index: Int!
  updatedAt: String
  workflow: Workflow
  workflowId: ID
}
```

**`WorkflowNoteWhereInput` supported fields**

| Field          | Type     |
| -------------- | -------- |
| `id`           | `ID`     |
| `title`        | `String` |
| `content`      | `String` |
| `metadata`     | `JSON`   |
| `clonedFromId` | `ID`     |
| `index`        | `Int`    |
| `workflowId`   | `ID`     |

**Is `where` or `search` mandatory?**

`id` or `workflowId` on `where` . There is no `search` input.

</details>

<details>

<summary><strong><code>workflowNotes</code></strong>-Gets multiple workflow notes.</summary>

**GraphQL schema**

```graphql
workflowNotes(
  where: WorkflowNoteWhereInput
  search: WorkflowNoteSearchInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["index"]]
  ): [WorkflowNote!]!
```

**`WorkflowNoteSearchInput` supported fields**

| Field          | Wrapper                 |
| -------------- | ----------------------- |
| `id`           | `id_comparison_exp`     |
| `title`        | `string_comparison_exp` |
| `content`      | `string_comparison_exp` |
| `metadata`     | `json_comparison_exp`   |
| `clonedFromId` | `id_comparison_exp`     |
| `index`        | `int_comparison_exp`    |
| `workflowId`   | `id_comparison_exp`     |

**Is `where` or `search` mandatory?**

`limit` and `offset`. Scope by `workflowId`.

</details>

<details>

<summary><strong><code>workflowTask</code></strong>-Gets a specific workflow task.</summary>

**GraphQL schema**

```graphql
workflowTask(where: WorkflowTaskWhereInput): WorkflowTask

type WorkflowTask {
  action: Action
  actionId: ID
  description: String
  humanSecondsSaved: Int
  id: ID
  input: JSON
  isMocked: Boolean
  join: Int
  metadata: JSON
  mockInput: JSON
  name: String
  next: [WorkflowTransition!]!
  packOverrides: [PackOverride!]
  publishResultAs: String
  retry: WorkflowTaskRetry
  runAsOrgId: String
  timeout: Int
  transitionMode: TransitionModes
  with: WorkflowTaskWithItems
  workflow: Workflow
  workflowId: ID
  securitySchema: JSON
}
```

`WorkflowTaskWhereInput` supported fields

| Field               | Type                          |
| ------------------- | ----------------------------- |
| `action`            | `ActionInput` (nested)        |
| `actionId`          | `ID`                          |
| `description`       | `String`                      |
| `humanSecondsSaved` | `Int`                         |
| `id`                | `ID`                          |
| `input`             | `JSON`                        |
| `isMocked`          | `Boolean`                     |
| `join`              | `Int`                         |
| `metadata`          | `JSON`                        |
| `mockInput`         | `JSON`                        |
| `name`              | `String`                      |
| `next`              | `[WorkflowTransitionInput!]`  |
| `retry`             | `WorkflowTaskRetryInput`      |
| `runAsOrgId`        | `String`                      |
| `timeout`           | `Int`                         |
| `with`              | `WorkflowTaskWithItemsInput`  |
| `workflowId`        | `ID`                          |
| `workflow`          | `WorkflowWhereInput` (nested) |

**Is `where` or `search` mandatory?**

Yes - `id` or `workflowId` and a discriminator on `where`. There is no `search` input.

</details>

<details>

<summary><strong><code>workflowTasks</code></strong>-Gets multiple workflow tasks.</summary>

**GraphQL schema**

```graphql
workflowTasks(
  where: WorkflowTaskWhereInput
  limit: Int
  offset: Int
  order: [[String!]!] = [["name"]]
): [WorkflowTask!]!
```

`WorkflowTaskWhereInput` supported fields

| Field               | Type                          |
| ------------------- | ----------------------------- |
| `action`            | `ActionInput` (nested)        |
| `actionId`          | `ID`                          |
| `description`       | `String`                      |
| `humanSecondsSaved` | `Int`                         |
| `id`                | `ID`                          |
| `input`             | `JSON`                        |
| `isMocked`          | `Boolean`                     |
| `join`              | `Int`                         |
| `metadata`          | `JSON`                        |
| `mockInput`         | `JSON`                        |
| `name`              | `String`                      |
| `next`              | `[WorkflowTransitionInput!]`  |
| `retry`             | `WorkflowTaskRetryInput`      |
| `runAsOrgId`        | `String`                      |
| `timeout`           | `Int`                         |
| `with`              | `WorkflowTaskWithItemsInput`  |
| `workflowId`        | `ID`                          |
| `workflow`          | `WorkflowWhereInput` (nested) |

**Is `where` or `search` mandatory?**

Yes - `where: { workflowId }`, `limit`, `offset`. `workflow_tasks` is large — unscoped calls will be slow. There is no `search` input.

</details>

{% hint style="info" %}
Each of the mutation expanders below contains information that includes the necessary updates you'll need to make for use of the mutation. Be sure to reference this information accordingly.
{% endhint %}

### Operation type: Mutations

#### **Action option mutations**

<details>

<summary><strong><code>createActionOptions</code></strong>-Creates multiple action options.</summary>

**GraphQL schema**

```graphql
createActionOptions(
  actionOptions: [ActionOptionInput!]!
  replace: Boolean
): [ActionOption]
```

**Necessary modifications**

Each item should supply `packConfigId`, `organizationId`, `optionLabel`, `optionValue`, and `resourceName`. Pass `replace: true` to overwrite the existing set; otherwise rows are appended.

**Usage example**

```yaml
operation_type: "mutation"
operation: "createActionOptions"
variable_values:
  actionOptions:
    - optionLabel: "Environment"
      optionValue: "production"
      organizationId: "{{ CTX.org_id }}"
      packConfigId: "{{ CTX.pack_config_id }}"
      resourceName: "server"
  replace: false
fields: "id, optionLabel, optionValue"
```

</details>

#### **Clone operations mutations**

<details>

<summary><strong><code>unlinkClone</code></strong>-Unlinks a cloned object from its source.</summary>

**GraphQL schema**

```graphql
unlinkClone(id: ID!, objectType: CloneableObjectType!): ID

enum CloneableObjectType {
  form
  template
  trigger
  workflow
  page
  site
}
```

**Necessary modifications**

`id` and `objectType`.\
Note: this only severs the link. The object itself is not deleted.

**Usage example**

```yaml
operation_type: "mutation"
operation: "unlinkClone"
variable_values:
  id: "{{ CTX.workflow_id }}"
  objectType: "workflow"
```

</details>

#### **Component mutations**

<details>

<summary><strong><code>createComponent</code></strong>-Creates a new component.</summary>

**GraphQL schema**

```graphql
createComponent(component: CreateComponentInput!): Component

input CreateComponentInput {
  orgId: ID!
  name: String!
  description: String
  nodeTree: JSON!
  workflows: [ID]
  isSynced: Boolean
}
```

**Necessary modifications**

`component.orgId`, `component.name`, `component.nodeTree`.

</details>

<details>

<summary><strong><code>updateComponent</code></strong>-Updates an existing component.</summary>

**GraphQL schema**

```graphql
updateComponent(component: UpdateComponentInput!): Component
```

**Necessary modifications**

`component.id`, `component.name`, `component.orgId`. Pass through existing `name`/`orgId` values when only editing the tree.

</details>

<details>

<summary><strong><code>deleteComponent</code></strong>-Deletes a component.</summary>

**GraphQL schema**

```graphql
deleteComponent(id: ID!): Boolean
```

**Necessary modifications**

`Id`.

</details>

<details>

<summary><strong><code>duplicateComponent</code></strong>-Duplicates an existing component.</summary>

**GraphQL schema**

```graphql
duplicateComponent(id: ID!): Component
```

**Necessary modifications**

`Id`.

</details>

#### **Foreign object reference mutations**

<details>

<summary><strong><code>createForeignObjectReference</code></strong>-Creates a foreign object reference.</summary>

**GraphQL schema**

```graphql
createForeignObjectReference(
  foreignObjectReference: CreateForeignObjectReferenceInput
): ForeignObjectReference

input CreateForeignObjectReferenceInput {
  actionId: ID
  id: ID
  identifier: ID
  orgId: ID!
  packConfigId: ID
  referenceId: ID!
  workflowExecutionId: ID
}
```

**Necessary modifications**

`orgId` and `referenceId` on the input

</details>

<details>

<summary><strong><code>createOrUpdateForeignObjectReference</code></strong>-Creates or updates a foreign object reference.</summary>

**GraphQL schema**

```graphql
createOrUpdateForeignObjectReference(
  foreignObjectReference: CreateForeignObjectReferenceInput
): ForeignObjectReference
```

**Necessary modifications**

`orgId` and `referenceId`

</details>

#### **Form mutations**

<details>

<summary><strong><code>createForm</code></strong>-Creates a new form.</summary>

**GraphQL schema**

```graphql
createForm(form: FormCreateInput!): Form

input FormCreateInput {
  clonedFromId: ID
  cloneOverrides: JSON
  description: String
  fields: [FormFieldInput!]
  id: ID
  isSynchronized: Boolean
  name: String
  orgId: ID!
  unpackedFromId: ID
}

```

**Necessary modifications**

`form` with `orgId`.

**Usage example**

```yaml
operation_type: "mutation"
operation: "createForm"
variable_values:
  form:
    name: "User Information Form"
    description: "Collects user information for onboarding"
    orgId: "{{ CTX.org_id }}"
    fields:
      - type: "TEXT_INPUT"
        index: 0
        schema:
          label: "Full Name"
          required: true
fields: "id, name, description, fields { id, type, schema }"
```

</details>

<details>

<summary><strong><code>submitForm</code></strong>-Submits form data and triggers associated workflow.</summary>

**GraphQL schema**

```graphql
submitForm(
  id: ID!
  values: JSON!
  triggerId: ID!
  orgId: ID!
): JSON
```

**Necessary modifications**

`id`, `values`, `triggerId`, `orgId`

</details>

<details>

<summary><strong><code>setFormTags</code></strong>-Sets tags for a form.</summary>

**GraphQL schema**

```graphql
setFormTags(form: SetFormTagsInput!): Form

input SetFormTagsInput {
  id: ID!
  tagIds: [ID!]!
}
```

**Necessary modifications**

`id` and `tagIds`.

</details>

<details>

<summary><strong><code>shallowCloneForm</code></strong>-Creates a shallow clone of a form.</summary>

**GraphQL schema**

```graphql
shallowCloneForm(
  id: ID!
  orgId: ID!
  overrides: ShallowCloneOverridesInput
  : Form)
```

**Necessary modifications**

`id`, `orgId`.

</details>

<details>

<summary><strong><code>updateForm</code></strong>-Updates an existing form.</summary>

**GraphQL schema**

```graphql
updateForm(form: FormUpdateInput!): Form
```

**Necessary modifications**

`form` with `id`.

</details>

<details>

<summary><strong><code>deleteForm</code></strong>-Deletes a form.</summary>

**GraphQL schema**

```graphql
deleteForm(id: ID!): Void
```

**Necessary modifications**

`id`

</details>

#### **Organization trigger instance mutations**

<details>

<summary><strong><code>updateOrgTriggerInstance</code></strong>-Updates an organization trigger instance.</summary>

**GraphQL schema**

```graphql
updateOrgTriggerInstance(
  orgTriggerInstance: OrgTriggerInstanceInput!
): OrgTriggerInstance

input OrgTriggerInstanceInput {
  id: ID
  isManualActivation: Boolean
  organization: OrganizationInput
  orgId: ID
  lastSearchedAt: String
  trigger: TriggerUpdateInput
  triggerId: ID
  state: JSON
}
```

**Necessary modifications**

`orgTriggerInstance`, and an `id` or `orgId` + `triggerId` on the input to identify the row.

</details>

#### **Organization variable mutations**

<details>

<summary><strong><code>createOrgVariable</code></strong>-Creates a new organization variable.</summary>

**GraphQL schema:**

```graphql
createOrgVariable(orgVariable: OrgVariableCreateInput!): OrgVariable

input OrgVariableCreateInput {
  cascade: Boolean!
  id: ID
  name: String!
  value: String!
  category: OrgVariableCategory
  orgId: ID!
  packConfigId: ID
}
```

**Necessary modifications**

`cascade`, `name`, `value`, `orgId`.

**Usage example**

```yaml
operation_type: "mutation"
operation: "createOrgVariable"
variable_values:
  orgVariable:
    name: "api_endpoint"
    value: "https://api.example.com/v1"
    category: "general"
    cascade: true
    orgId: "{{ CTX.org_id }}"
fields: "id, name, value, category, cascade"
```

</details>

<details>

<summary><strong><code>deleteOrgVariable</code></strong>-Deletes an organization variable.</summary>

**GraphQL schema**

```graphql
deleteOrgVariable(id: ID!): ID
```

**Necessary modifications**

`id`

</details>

<details>

<summary><strong><code>updateOrgVariables</code></strong>-Updates multiple organization variables.</summary>

**GraphQL schema**

```graphql
updateOrgVariables(
  orgVariables: [OrgVariableUpdateInput!]!
): [OrgVariable!]!

input OrgVariableUpdateInput {
  cascade: Boolean
  category: OrgVariableCategory
  id: ID
  name: String!
  value: String
  orgId: ID
  packConfigId: ID
}
```

**Necessary modifications**

`orgVariables` (non-empty); each entry requires `id` and `name`.

</details>

#### **Organization management mutations**

<details>

<summary><strong><code>bulkCreateOrganizations</code></strong>-Creates multiple organizations in bulk.</summary>

**GraphQL schema**

```graphql
bulkCreateOrganizations(
  organizations: [OrganizationInput!]!
): [Organization!]!
```

**Necessary modifications**

`organizations` (non-empty); each item requires `name`.

</details>

<details>

<summary><strong><code>bulkDeleteOrganizations</code></strong>-Deletes multiple organizations in bulk.</summary>

**GraphQL schema**

```graphql
bulkDeleteOrganizations(organizationIds: [ID!]!): Void
```

**Necessary modifications**

`organizationIds`

</details>

<details>

<summary><strong><code>createOrganization</code></strong>-Creates a single organization.</summary>

**GraphQL schema**

```graphql
createOrganization(organization: OrganizationInput): Organization

input OrganizationInput {
  domain: String
  id: ID
  isEnabled: Boolean
  managingOrgId: ID
  name: String!
  orgSlug: String
  rocSiteId: String
  tid: String
  tagIds: [ID!]
}
```

**Necessary modifications**

`name` on each item.

Note: `createOrganizations` returns nullable elements — a per-row failure yields a `null` slot rather than aborting the batch.

</details>

<details>

<summary><strong><code>createOrganizations</code></strong>-Creates multiple organizations.</summary>

**GraphQL schema**

```graphql
createOrganizations(
  organizations: [OrganizationInput!]!
): [Organization]
```

**Necessary modifications**

**`organizationinput`**

</details>

<details>

<summary><strong><code>deleteOrganization</code></strong>-Deletes an organization.</summary>

**GraphQL schema**

```graphql
deleteOrganization(id: ID!): Void
```

**Necessary modifications**

`id`

</details>

<details>

<summary><strong><code>updateManagedAndSubOrganizations</code></strong>-Updates all managed and suborganizations.</summary>

**GraphQL schema**

```graphql
updateManagedAndSubOrganizations(
  organization: OrganizationUpdateInput!
): Int

input OrganizationUpdateInput {
  domain: String
  id: ID!
  isEnabled: Boolean
  isInternal: Boolean
  isDeleted: Boolean
  isOnboarding: Boolean
  deletedAt: String
  name: String
  orgSlug: String
  resultsRetentionDays: Int
  rocSiteId: String
  tagIds: [ID!]
  tid: ID
}
```

**Necessary modifications**

`organization.id` (the parent org whose tree is being updated). Returns the count of affected rows.

</details>

<details>

<summary><strong><code>updateOrganization</code></strong>-Updates an organization.</summary>

**GraphQL schema**

```graphql
updateOrganization(
  organization: OrganizationUpdateInput
  cascadeChildOrgReenable: Boolean = false
): Organization

input OrganizationUpdateInput {
  domain: String
  id: ID!
  isEnabled: Boolean
  isInternal: Boolean
  isDeleted: Boolean
  isOnboarding: Boolean
  deletedAt: String
  name: String
  orgSlug: String
  resultsRetentionDays: Int
  rocSiteId: String
  tagIds: [ID!]
  tid: ID
}
```

**Necessary modifications**

`organization.id`. Pass `cascadeChildOrgReenable: true` to propagate `isEnabled: true` to child orgs when re-enabling.

</details>

<details>

<summary><strong><code>bulkUpdateOrganizationFeaturePreviewSettingByLabel</code></strong>-Bulk updates feature preview settings by label.</summary>

**Necessary modifications**

```graphql
bulkUpdateOrganizationFeaturePreviewSettingByLabel(
  isEnabled: Boolean!
  label: String!
  orgIds: [ID!]!
): [OrganizationFeaturePreviewSetting!]!
```

</details>

#### **Pack configuration mutations**

<details>

<summary><strong><code>synchronizePackBundleConfigs</code></strong>-Synchronizes pack bundle configurations.</summary>

**GraphQL schema**

```graphql
synchronizePackBundleConfigs(
  orgId: ID!
  packBundleId: ID!
  primaryPackConfigId: ID!
): [SynchronizedPackConfig!]!
```

**Necessary modifications**

`orgId`, `packBundleId`, `primaryPackConfigId`

</details>

<details>

<summary><strong><code>createPackConfig</code></strong>-Creates a new pack configuration.</summary>

**GraphQL schema**

```graphql
createPackConfig(packConfig: PackConfigCreateInput!): PackConfig

input PackConfigCreateInput {
  id: ID
  name: String!
  default: Boolean
  description: String
  config: JSON
  metadata: JSON
  orgId: ID!
  packId: ID!
}
```

**Necessary modifications**

`packConfig.name`, `packConfig.orgId`, `packConfig.packId`.

</details>

<details>

<summary><strong><code>deletePackConfig</code></strong>-Deletes a pack configuration.</summary>

**GraphQL schema**

```graphql
deletePackConfig(id: ID!, orgId: ID!): Void
```

**Necessary modifications**

`id`, `orgId`.

</details>

<details>

<summary><strong><code>refetchPackConfigRefOptions</code></strong>-Refetches pack configuration reference options.</summary>

**GraphQL schema**

```graphql
refetchPackConfigRefOptions(
  packConfigId: ID!
  reference: JSON
): JobRequestedResponse
```

**Necessary modifications**

`packConfigId` returns a `JobRequestedResponse` — work is asynchronous.

</details>

<details>

<summary><strong><code>testPackConfig</code></strong>-Tests a pack configuration.</summary>

**GraphQL schema**

```graphql
testPackConfig(packConfig: PackConfigTestInput!): JobRequestedResponse
```

**Necessary modifications**

`packConfig.id` returns a `JobRequestedResponse` — results delivered via `actionResults` subscription.

</details>

<details>

<summary><strong><code>updatePackConfig</code></strong>-Updates a pack configuration.</summary>

**GraphQL schema**

```graphql
updatePackConfig(packConfig: PackConfigUpdateInput!): PackConfig
```

**Necessary modifications**

`id` on each entry

</details>

<details>

<summary><strong><code>updatePackConfigs</code></strong>-Updates multiple pack configurations.</summary>

**GraphQL schema**

```graphql
updatePackConfigs(
  packConfigs: [PackConfigUpdateInput!]!
): [PackConfig!]!
```

</details>

#### **Pack mutations**

<details>

<summary><strong><code>generatePackOrBundleAuthUrl</code></strong>-Generates authorization URL for pack or bundle.</summary>

**GraphQL schema**

```graphql
generatePackOrBundleAuthUrl(
  orgId: ID!
  packBundleId: ID
  packConfigId: ID
  extra: JSON
): AuthUrlResponse

type AuthUrlResponse {
  authUrl: String
  error: String
}
```

**Necessary modifications**

`orgId`, plus exactly one of `packBundleId` or `packConfigId`.

</details>

<details>

<summary><strong><code>installPack</code></strong>-Installs a pack for an organization. Returns the updated Organization, not the pack.</summary>

**GraphQL schema**

```graphql
installPack(orgId: ID!, packId: ID!, name: String): Organization
```

**Necessary modifications**

`orgId`, `packId`

</details>

<details>

<summary><strong><code>getPackInstallations</code></strong>-Gets pack installation information. Defined as a mutation despite being read-only.</summary>

**GraphQL schema**

```graphql
getPackInstallations(packId: ID!): PackInstalledByResponse
```

**Necessary modifications**

`packId`

</details>

<details>

<summary><strong><code>getPackPageUrl</code></strong>-Gets the URL for a pack page. Defined as a mutation despite being read-only.</summary>

**GraphQL schema**

```graphql
getPackPageUrl(integrationRef: String!, pagePath: String!): String
```

**Necessary modifications**

`integrationRef`, `pagePath`

</details>

<details>

<summary><strong><code>updatePack</code></strong>-Updates a pack.</summary>

**GraphQL schema**

```graphql
updatePack(pack: PackUpdateInput!): Pack

input PackUpdateInput {
  actions: [ActionUpdateInput!]
  configSchema: JSON
  description: String
  icon: String
  id: ID
  isDefault: Boolean
  isMultitenancyEnabled: Boolean
  isOauthConfiguration: Boolean
  metadata: JSON
  name: String
  orgId: ID
  orgVariables: JSON
  packTestActionId: ID
  ref: String
  setupInstructions: String
  status: PackStatus
  tags: [String!]
  uid: String
  version: String
}
```

**Necessary modifications**

`pack` with `id` to identify the row

</details>

#### **Page mutations**

<details>

<summary><strong><code>createPage</code></strong>-Creates a new page.</summary>

**GraphQL schema**

```graphql
createPage(
  page: PageCreateInput!
  preset: String
  nodes: [PageNodeInput]
): Page

input PageCreateInput {
  id: ID
  loader: Loader
  siteId: ID
  workflows: [WorkflowInput]
  name: String!
  path: String!
  variables: [JSON]
  orgId: ID!
  clonedFromId: ID
  isSynchronized: Boolean
  cloneOverrides: JSON
}
```

**Necessary modifications**

`page.name`, `page.path`, `page.orgId`

</details>

<details>

<summary><strong><code>updatePage</code></strong>-Updates an existing page.</summary>

**GraphQL schema**

```graphql
updatePage(
  page: PageUpdateInput!
  nodes: [PageNodeInput]
): Page
```

**Necessary modifications**

`page.id`, `page.siteId`.\
Note: `pageNodes` is the encoded editor state passed as a string — decoded server-side.

</details>

<details>

<summary><strong><code>deletePage</code></strong>-Deletes a page.</summary>

**GraphQL schema**

```graphql
deletePage(id: ID!): Void
```

**Necessary modifications**

`deletePage`: requires `id`.

</details>

<details>

<summary><strong><code>updatePageNode</code></strong>-Updates a page node.</summary>

**GraphQL schema**

```graphql
updatePageNode(id: ID!, props: JSON!): PageNode
```

**Necessary modifications**

`updatePageNode`: requires `id`, `props`.

</details>

<details>

<summary><strong><code>updatePageNodeByCraftId</code></strong>-Updates a page node by craft ID.</summary>

**GraphQL schema**

```graphql
updatePageNodeByCraftId(
  craftId: String!
  pageId: ID!
  props: JSON!
): PageNode
```

**Necessary modifications**

`updatePageNodeByCraftId`: requires `craftId`, `pageId`, `props` — use when you have the Craft.js editor id rather than the persisted `PageNode.id`.

</details>

#### **Site mutations**

<details>

<summary><strong><code>createSite</code></strong>-Creates a new site/app.</summary>

**GraphQL schema**

```graphql
createSite(site: SiteCreateInput!): Site

input SiteCreateInput {
  name: String
  domain: String
  orgId: ID!
  template: String
  theme: JSON
  pages: [PagesImportInput]
  clonedFromId: ID
  isSynchronized: Boolean
  cloneOverrides: JSON
}
```

**Necessary modifications**

`site.orgId`

</details>

<details>

<summary><strong><code>updateSite</code></strong>-Updates an existing site/app.</summary>

**GraphQL schema**

```graphql
updateSite(site: SiteUpdateInput!): Site
updateSites(sites: [SiteUpdateInput!]!): [Site!]!

input SiteUpdateInput {
  id: ID!
  name: String
  domain: String
  orgId: ID
  layout: String
  theme: JSON
  isLive: Boolean
  statusCode: Int
  statusMessage: String
  customDomain: String
  isDnsValidated: Boolean
  useCustomDomain: Boolean
  themeReferenceOrgVariable: String
  pages: [PagesImportInput]
  clonedFromId: ID
  isSynchronized: Boolean
  cloneOverrides: JSON
  faviconUrl: String
}
```

**Necessary modifications**

`id` on each entry

</details>

<details>

<summary><strong><code>updateSites</code></strong>-Updates multiple sites.</summary>

**GraphQL schema**

```graphql
updateSites(sites: [SiteUpdateInput!]!): [Site!]!
```

**Necessary modifications**

`id`

</details>

<details>

<summary><strong><code>deleteSite</code></strong>-Deletes a site/app.</summary>

**GraphQL schema**

```graphql
deleteSite(id: ID!): Void
```

**Necessary modifications**

`id`

</details>

<details>

<summary><strong><code>validateSiteCustomDomainDNS</code></strong>-Validates custom domain DNS settings.</summary>

**GraphQL schema**

```graphql
validateSiteCustomDomainDNS(id: ID!): DNSValidationResponse

type DNSValidationResponse {
  isValid: Boolean
  message: String
}
```

**Necessary modifications**

`id`

</details>

#### **Tag mutations**

<details>

<summary><strong><code>createTag</code> -</strong> Creates a new tag.</summary>

**GraphQL schema**

```graphql
createTag(tag: TagCreateInput!): Tag

input TagCreateInput {
  id: ID
  name: String
  description: String
  orgId: ID!
  color: String
}
```

**Necessary modifications**

Use `id`, `name`, and `orgId` on each entry.

</details>

<details>

<summary><strong><code>deleteTag</code></strong>-Deletes a tag.</summary>

**GraphQL schema**

```graphql
deleteTag(id: ID!): ID
```

**Necessary modifications**

`id`

</details>

<details>

<summary><strong><code>updateTag or updateTags</code></strong>-Updates one tag, updates multiple tags.</summary>

**GraphQL schema**

```graphql
updateTag(tag: TagUpdateInput!): Tag!
updateTags(tags: [TagUpdateInput!]!): [Tag!]!

input TagUpdateInput {
  id: ID!
  name: String!
  description: String
  orgId: ID!
  color: String
}
```

**Necessary modifications**

`id`, `name`, and `orgId` on each entry.

</details>

<details>

<summary><strong><code>setOrganizationTags</code></strong>-Sets tags for an organization.</summary>

**GraphQL schema**

```graphql
setOrganizationTags(tagIds: [ID!]!, orgId: ID!): Organization
```

**Necessary modifications**

Use `tagIds` and `orgId`. This is a replace operation — passing `tagIds: []` clears all tags on the org.

</details>

#### **Template mutations**

<details>

<summary><strong><code>createTemplate</code></strong>-Creates a new template.</summary>

**GraphQL schema**

````graphql
createTemplate(template: TemplateCreateInput!): Template

input TemplateCreateInput {
  body: String!
  clonedFromId: ID
  cloneOverrides: JSON
  contentType: String
  context: JSON
  description: String
  id: ID
  isShared: Boolean
  isSynchronized: Boolean
  language: String
  name: String!
  orgId: ID!
  tags: [TagInput!]
  unpackedFromId: ID
}

## Best Practices

### Query Optimization

1. **Limit Data Retrieval**: Only request the fields you actually need
2. **Use Pagination**: Implement proper limit and offset for large datasets
3. **Filter Early**: Apply filters at the query level rather than post-processing

### Error Handling

```yaml
# Example workflow task with error handling
- name: execute_graphql_query
  action: rewst.generic_graph_request
  parameters:
    operation_type: "query"
    operation: "workflows"
    variable_values:
      limit: 100
      where:
        orgId: "{{ CTX.org_id }}"
  on_failure:
    - log_error:
        message: "GraphQL query failed: {{ RESULT.error }}"
````

**Necessary modifications**

`body`, `name`, `orgId`.

</details>

<details>

<summary>update<strong><code>Template</code></strong>-Updates an existing template.</summary>

**GraphQL schema**

```graphql
updateTemplate(template: TemplateUpdateInput!): Template

input TemplateUpdateInput {
  body: String
  clonedFromId: ID
  cloneOverrides: JSON
  contentType: String
  context: JSON
  description: String
  id: ID!
  isShared: Boolean
  isSynchronized: Boolean
  language: String
  name: String
  orgId: ID
  tags: [TagInput!]
  unpackedFromId: ID
}
```

**Necessary modifications**

`template.id`

</details>

<details>

<summary><code>update</code><strong><code>Template</code></strong>-Updates an existing template.</summary>

**GraphQL schema**

```graphql
updateTemplate(template: TemplateUpdateInput!): Template

input TemplateUpdateInput {
  body: String
  clonedFromId: ID
  cloneOverrides: JSON
  contentType: String
  context: JSON
  description: String
  id: ID!
  isShared: Boolean
  isSynchronized: Boolean
  language: String
  name: String
  orgId: ID
  tags: [TagInput!]
  unpackedFromId: ID
}
```

**Necessary modifications**

`template.id`

</details>

#### Trigger mutations

<details>

<summary><code>Createtrigger</code><strong>- Creates a trigger.</strong></summary>

**GraphQL schema**

```graphql
CreateTrigger(trigger: TriggerCreateInput!, createPatch: Boolean): Trigger

input TriggerCreateInput {
  activatedForOrgIds: [ID!]
  activatedForTagIds: [ID!]
  autoActivateManagedOrgs: Boolean
  clonedFromId: ID
  cloneOverrides: JSON
  criteria: JSON
  description: String
  enabled: Boolean
  formId: ID
  id: ID
  isActivatedForOwner: Boolean
  isSynchronized: Boolean
  name: String
  orgId: ID
  packOverrides: [PackOverrideInput]
  parameters: JSON
  state: JSON
  triggerTypeId: ID
  unpackedFromId: ID
  vars: [JSON!]
  workflow: WorkflowInput
  workflowBuilderInfo: JSON
  workflowId: ID
}
```

**Necessary modifications**

`trigger` with `triggerTypeId`, `orgId`, and either `workflowId` or `workflow.id`.

</details>

<details>

<summary><code>updatetrigger</code><strong>- Updates a trigger.</strong></summary>

**GraphQL schema**

```graphql
updateTrigger(
  trigger: TriggerUpdateInput!
  comment: String
  commentDescription: String
  createPatch: Boolean
): Trigger

input TriggerUpdateInput {
  activatedForOrgIds: [ID!]
  activatedForTagIds: [ID!]
  autoActivateManagedOrgs: Boolean
  clonedFromId: ID
  cloneOverrides: JSON
  criteria: JSON
  description: String
  enabled: Boolean
  formId: ID
  id: ID
  isActivatedForOwner: Boolean
  isSynchronized: Boolean
  name: String
  orgId: ID
  packOverrides: [PackOverrideInput]
  parameters: JSON
  state: JSON
  unpackedFromId: ID
  vars: [JSON!]
  workflow: WorkflowInput
  workflowBuilderInfo: JSON
  workflowId: ID
}

```

**Necessary modifications**

`trigger.id`

</details>

<details>

<summary><code>testworkflowtrigger</code><strong>-</strong> Fires a trigger against a workflow for testing.</summary>

**GraphQL schema**

```graphql
testWorkflowTrigger(
  triggerInstance: OrgTriggerInstanceInput!
  workflowId: ID
  input: JSON
): JobRequestedResponse
```

**Necessary modifications**

`triggerInstance`. `workflowId` and `input` are optional but typically supplied.

</details>

<details>

<summary><code>deletetrigger</code><strong>- Deletes a trigger.</strong></summary>

**GraphQL schema**

```graphql
deleteTrigger(id: ID!): ID
```

**Necessary modifications**

`id`

</details>

#### User mutations

<details>

<summary><code>updateuserpreferences</code> - Updates preferences for a user</summary>

**GraphQL schema**

```graphql
updateUserPreferences(userId: ID!, preferences: UserPreferencesInput!): User!

input UserPreferencesInput {
  isDarkModePreferred: Boolean
  dateFormat: String
  datetimeFormat: String
}
```

**Necessary modifications**

`userId`, `preferences`

</details>

<details>

<summary><code>createuser</code> - Creates a new user in an organization</summary>

**GraphQL schema**

```graphql
createUser(user: CreateUserInput!): User

input CreateUserInput {
  orgId: ID!
  isTestUser: Boolean
  username: String!
  roleIds: [String!]!
}
```

**Necessary modifications**

`orgId`, `username`, `roleIds`. Only available when `ENABLE_ADMIN_APPROVAL_REQUESTS` is OFF.

</details>

<details>

<summary><code>deleteuser</code> - Deletes a user in an organization</summary>

**GraphQL schema**

```graphql
deleteUser(id: ID!): Void

input UserRolesInput {
  id: ID!
  roleIds: [String!]!
}
```

**Necessary modifications**

Only available when `ENABLE_ADMIN_APPROVAL_REQUESTS` is OFF.

</details>

<details>

<summary><code>addfavoriteaction</code> - Adds a favorite action</summary>

**GraphQL schema**

```graphql
addFavoriteAction(userId: ID!, actionId: ID!): Void
```

**Necessary modifications**

`actionId` and `index`

</details>

<details>

<summary><code>removefavoriteaction</code> - Removes a favorite action</summary>

**GraphQL schema**

```graphql
removeFavoriteAction(userId: ID!, actionId: ID!): Void
```

**Necessary modifications**

`actionId` and `index`

</details>

<details>

<summary><code>setFavoriteActions</code> - Replaces the entire favorites list</summary>

**GraphQL schema**

```graphql
setFavoriteActions(userId: ID!, favoriteActions: [UserFavoriteActionInput!]!): [UserFavoriteAction!]!
```

**Necessary modifications**

`actionId` and `index`

</details>

#### Workflow mutations

<details>

<summary><code>createworkflow</code> - Creates a new workflow</summary>

**GraphQL schema**

```graphql
deleteWorkflows(ids: [ID!]!): [ID]
```

**Necessary modifications**

`id`

</details>

<details>

<summary><code>deleteworkflow</code> - Deletes a workflow</summary>

**GraphQL schema**

```graphql
deleteWorkflows(ids: [ID!]!): [ID]
```

**Necessary modifications**

`id`

</details>

<details>

<summary><code>deleteworkflows</code> - Deletes multiple workflows</summary>

**GraphQL schema**

```graphql
deleteWorkflows(ids: [ID!]!): [ID]
```

**Necessary modifications**

`id`

</details>

<details>

<summary><code>deleteWorkflowExecution</code> - Deletes workflow executions</summary>

**GraphQL schema**

```graphql
deleteWorkflowExecution(id: ID!): Boolean
```

**Necessary modifications**

`id`

</details>

<details>

<summary><code>killWorkflowExecution</code> - Kills active workflow executions</summary>

**GraphQL schema**

```graphql
killWorkflowExecution(id: ID!): JSON
```

**Necessary modifications**

`id`

</details>

<details>

<summary><code>shallowcloneworkflow</code> - Creates a shallow clone of a workflow into an org.</summary>

**GraphQL schema**

```graphql
shallowCloneWorkflow(id: ID!, orgId: ID!, overrides: ShallowCloneOverridesInput): Workflow

input ShallowCloneOverridesInput {
  name: String
}
```

**Necessary modifications**

`id`, `orgId`. Does not deep-clone referenced objects.

</details>

<details>

<summary><code>testworkflow</code> - Triggers a one-off test execution of a workflow.</summary>

**GraphQL schema**

```graphql
testWorkflow(id: ID!, orgId: ID!, input: JSON, context: ExecuteContextType): JobRequestedResponse
```

**Necessary modifications**

`id`, `orgId`.

</details>

<details>

<summary><code>bulksetworkflowtags</code> - Replaces tag assignments on multiple workflows in one call.</summary>

**GraphQL schema**

```graphql
bulkSetWorkflowTags(workflowIds: [ID!]!, tagIds: [ID!]!): [Workflow!]!
```

**Necessary modifications**

`workflowIds`, `tagIds`.

</details>

<details>

<summary><code>createWorkflowCompletionListener</code> - Creates a completion listener trigger.</summary>

**GraphQL schema**

```graphql
createWorkflowCompletionListener(listener: CompletionListenerCreateInput!): Trigger

input CompletionListenerCreateInput {
  enabled: Boolean
  listeningToWorkflowId: ID!
  orgId: ID!
  packOverrides: [PackOverrideInput]
  handlerWorkflowId: ID!
  triggerOnStatuses: [String!]!
}
```

**Necessary modifications**

`listeningToWorkflowId`, `orgId`, `handlerWorkflowId`, `triggerOnStatuses`

</details>

<details>

<summary><code>updateWorkflowCompletionListener</code> - Updates a completion listener trigger.</summary>

**GraphQL schema**

```graphql
updateWorkflowCompletionListener(listener: CompletionListenerUpdateInput!): Trigger

input CompletionListenerUpdateInput {
  enabled: Boolean
  triggerId: ID!
  listeningToWorkflowId: ID!
  orgId: ID!
  packOverrides: [PackOverrideInput]
  handlerWorkflowId: ID!
  triggerOnStatuses: [String!]!
  cloneOverrides: JSON
}
```

**Necessary modifications**

`triggerId`, `listeningToWorkflowId`, `orgId`, `handlerWorkflowId`, `triggerOnStatuses`.

</details>

<details>

<summary><code>deleteWorkflowCompletionListener</code> - Deletes a completion listener trigger.</summary>

**GraphQL schema**

```graphql
deleteWorkflowCompletionListener(id: ID!): Void

input CompletionListenerUpdateInput {
  enabled: Boolean
  triggerId: ID!
  listeningToWorkflowId: ID!
  orgId: ID!
  packOverrides: [PackOverrideInput]
  handlerWorkflowId: ID!
  triggerOnStatuses: [String!]!
  cloneOverrides: JSON
}
```

**Necessary modifications**

`id`

</details>

## Security considerations

1. Always validate user inputs before including in queries
2. Use organization and permission filters to restrict data access
3. Track usage patterns for potential security issues

## Common use cases for the Generic GraphQL request action

### Bulk data operations

**Action configuration:**

* **Operation type**: `mutation`
* **Operation**: `updateOrgVariables`
* **Variable values**:

  ```json
  {
    "orgVariables": [
      {
        "id": "var1",
        "name": "setting1",
        "value": "updated_value1"
      },
      {
        "id": "var2",
        "name": "setting2",
        "value": "updated_value2"
      }
    ]
  }
  ```

### Complex reporting

**Action configuration:**

* **Operation type**: `query`
* **Operation**: `workflows`
* **Variable values**:

  ```json
  {
    "where": {
      "orgId": "{{ CTX.org_id }}"
    },
    "limit": 1000
  }
  ```
* **Fields**:

  ```
  id
  name
  description
  createdAt
  updatedAt
  tasks {
    id
    name
    action {
      name
      pack {
        name
      }
    }
  }
  triggers {
    id
    name
    enabled
  }
  ```

### Data synchronization

**Action configuration:**

* **Operation type**: `query`
* **Operation**: `organizations`
* **Variable values**:

  ```json
  {
    "where": {
      "managingOrgId": "{{ CTX.parent_org_id }}"
    },
    "order": [["name"]]
  }
  ```
* **Fields**: `id, name, domain, createdAt, managedOrgs { id, name }`

## Troubleshoot the Generic GraphQL request action

### **Permission denied**

* Check for query syntax issues
* You may be attempting to run an unsupported GraphQL action

### **Query syntax errors**

* Validate GraphQL syntax using a GraphQL validator
* Check field names against the schema
* Ensure variable types match the expected schema types

### **Rate limiting**

* Implement exponential backoff for retries
* Consider breaking large operations into smaller batches
* Monitor API usage patterns

### Debug tips

1. Begin with basic queries before building complex operations
2. For debugging, use the `raw_query` parameter to see exact queries
3. Review workflow execution logs for detailed error messages
4. Build queries incrementally, adding fields and filters gradually


# Transform actions

*Transform actions*, or *transforms* for short, are a simplified way to achieve commonly required Jinja filters without writing complex code, while providing flexibility to adapt in the Live Editor for more advanced Rewst users. They offer the ability to modify, combine, and reshape the data you are working with in your workflows. These actions are particularly useful when dealing with complex data structures, such as nested lists and objects. They empower you to transform data according to your needs without additional coding.

{% hint style="info" %}
Click through to each of the following pages to learn more about the relevant transform actions.
{% endhint %}

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>Add or subtract from DateTime transform action</strong></td><td><a href="/pages/94VvqKtWjKOFrVGOAIVL">/pages/94VvqKtWjKOFrVGOAIVL</a></td><td></td></tr><tr><td><strong>All transform action</strong></td><td><a href="/pages/zgUEdWLcY7r1E1RDEk6g">/pages/zgUEdWLcY7r1E1RDEk6g</a></td><td></td></tr><tr><td><strong>Any transform action</strong></td><td><a href="/pages/xLpDBjc9TesMbGkflijN">/pages/xLpDBjc9TesMbGkflijN</a></td><td></td></tr><tr><td><strong>Append with items results transform action</strong></td><td><a href="/pages/iVCOFwsZReLztyCwBSNy">/pages/iVCOFwsZReLztyCwBSNy</a></td><td></td></tr><tr><td><strong>Average transform action</strong></td><td><a href="/pages/MuAV5iBTkLaxXbtZ3TPX">/pages/MuAV5iBTkLaxXbtZ3TPX</a></td><td></td></tr><tr><td><strong>Base64 decode transform action</strong></td><td><a href="/pages/Hs63WnEFMdU7ayFJiyLV">/pages/Hs63WnEFMdU7ayFJiyLV</a></td><td></td></tr><tr><td><strong>Base64 encode transform action</strong></td><td><a href="/pages/3TOQHy0tSSEEoYWDToyM">/pages/3TOQHy0tSSEEoYWDToyM</a></td><td></td></tr><tr><td><strong>Compare dates transform action</strong></td><td><a href="/pages/n8PQcMnhQKvGu1HobNgo">/pages/n8PQcMnhQKvGu1HobNgo</a></td><td></td></tr><tr><td><strong>Convert DateTime to timezone transform action</strong></td><td><a href="/pages/nIqKmTumNJDTKgThdR1l">/pages/nIqKmTumNJDTKgThdR1l</a></td><td></td></tr><tr><td><strong>Convert from epoch transform action</strong></td><td><a href="/pages/cnjQaAPLWEO3Pv0nDh5n">/pages/cnjQaAPLWEO3Pv0nDh5n</a></td><td></td></tr><tr><td><strong>Convert list to object transform action</strong></td><td><a href="/pages/dygkNPjMRNnmUGK28UI1">/pages/dygkNPjMRNnmUGK28UI1</a></td><td></td></tr><tr><td><strong>Defang transform action</strong></td><td><a href="/pages/x7W29AnqRzDtva7MEsXW">/pages/x7W29AnqRzDtva7MEsXW</a></td><td></td></tr><tr><td><strong>Diff lists transform action</strong></td><td><a href="/pages/5gc7RkOWkv0e12VAgSzZ">/pages/5gc7RkOWkv0e12VAgSzZ</a></td><td></td></tr><tr><td><strong>Extract part of a date transform action</strong></td><td><a href="/pages/PBuFVt8lWjaixgYVu9Sv">/pages/PBuFVt8lWjaixgYVu9Sv</a></td><td></td></tr><tr><td><strong>Flatten list transform action</strong></td><td><a href="/pages/B4Sts5BoPnNdsWpaZvMI">/pages/B4Sts5BoPnNdsWpaZvMI</a></td><td></td></tr><tr><td><strong>Format date time transform action</strong></td><td><a href="/pages/aC2wgAKASJ1moNIsW5Zi">/pages/aC2wgAKASJ1moNIsW5Zi</a></td><td></td></tr><tr><td><strong>Generate friendly password transform action</strong></td><td><a href="/pages/fAH7pStO1WFT2peGSkG8">/pages/fAH7pStO1WFT2peGSkG8</a></td><td></td></tr><tr><td><strong>Get business days between dates transform action</strong></td><td><a href="/pages/yo6Ew8ZTCwslgHOjYVtN">/pages/yo6Ew8ZTCwslgHOjYVtN</a></td><td></td></tr><tr><td><strong>Get DateTime transform action</strong></td><td><a href="/pages/ElESrTJdT6s7ZL9asYsF">/pages/ElESrTJdT6s7ZL9asYsF</a></td><td></td></tr><tr><td><strong>Get days between dates transform action</strong></td><td><a href="/pages/GisOlHYbpSP1TnmqkCM2">/pages/GisOlHYbpSP1TnmqkCM2</a></td><td></td></tr><tr><td><strong>Get list length transform action</strong></td><td><a href="/pages/3YJNL9fq5APhRQM1uuEf">/pages/3YJNL9fq5APhRQM1uuEf</a></td><td></td></tr><tr><td><strong>Get string length transform action</strong></td><td><a href="/pages/ealuUBdQqMQrcctJ8q9y">/pages/ealuUBdQqMQrcctJ8q9y</a></td><td></td></tr><tr><td><strong>Is JSON transform action</strong></td><td><a href="/pages/LK3M6zmdHZGNH6E9PczO">/pages/LK3M6zmdHZGNH6E9PczO</a></td><td></td></tr><tr><td><strong>Map to an attribute within a list transform action</strong></td><td><a href="/pages/GgJQcbcTwjLGa0rYQsAl">/pages/GgJQcbcTwjLGa0rYQsAl</a></td><td></td></tr><tr><td><strong>Merge lists transform action</strong></td><td><a href="/pages/b6KuxcunghNggGewvQip">/pages/b6KuxcunghNggGewvQip</a></td><td></td></tr><tr><td><strong>Parse CSV transform action</strong></td><td><a href="/pages/pd2rEtXgSBUiGz7JdR4s">/pages/pd2rEtXgSBUiGz7JdR4s</a></td><td></td></tr><tr><td><strong>Parse text to JSON transform action</strong></td><td><a href="/pages/PAh7D8CUZwZ6UIouO7ET">/pages/PAh7D8CUZwZ6UIouO7ET</a></td><td></td></tr><tr><td><strong>Range transform action</strong></td><td><a href="/pages/1kNHOEHnPmtQUv5y4tDC">/pages/1kNHOEHnPmtQUv5y4tDC</a></td><td></td></tr><tr><td><strong>Refang transform action</strong></td><td><a href="/pages/VifM1lScmYmsrdtq7q4v">/pages/VifM1lScmYmsrdtq7q4v</a></td><td></td></tr><tr><td><strong>Remove duplicates from list transform action</strong></td><td><a href="/pages/xKJes1d1OT8GAwh52Zfi">/pages/xKJes1d1OT8GAwh52Zfi</a></td><td></td></tr><tr><td><strong>Return element transform action</strong></td><td><a href="/pages/wmoO0QOnCPrxX7wrYtN5">/pages/wmoO0QOnCPrxX7wrYtN5</a></td><td></td></tr><tr><td><strong>Select attribute transform action</strong></td><td><a href="/pages/jSzeeXumO1RA09H5O7ME">/pages/jSzeeXumO1RA09H5O7ME</a></td><td></td></tr><tr><td><strong>Set list field value transform action</strong></td><td><a href="/pages/aUyqY6JFAZIPqTRtECfW">/pages/aUyqY6JFAZIPqTRtECfW</a></td><td></td></tr><tr><td><strong>Set variable transform action</strong></td><td><a href="/pages/6LQ0hxDmBIlhQFB71IU8">/pages/6LQ0hxDmBIlhQFB71IU8</a></td><td></td></tr><tr><td><strong>Sort transform action</strong></td><td><a href="/pages/8jc8MeKCN2bO5ksTPdHZ">/pages/8jc8MeKCN2bO5ksTPdHZ</a></td><td></td></tr><tr><td><strong>Split text transform action</strong></td><td><a href="/pages/LIyimMVNoharuPrXhOaR">/pages/LIyimMVNoharuPrXhOaR</a></td><td></td></tr><tr><td><strong>Transform list objects transform action</strong></td><td><a href="/pages/dJhQgEeQYAgdlJYJY9rk">/pages/dJhQgEeQYAgdlJYJY9rk</a></td><td></td></tr><tr><td><strong>Trim variable transform action</strong></td><td><a href="/pages/I4u3825s6Iv7Z1E8N1uR">/pages/I4u3825s6Iv7Z1E8N1uR</a></td><td></td></tr><tr><td><strong>URL decode transform action</strong></td><td><a href="/pages/Jb3Mxsf4SopkJSGXoGyi">/pages/Jb3Mxsf4SopkJSGXoGyi</a></td><td></td></tr><tr><td><strong>URL encode transform action</strong></td><td><a href="/pages/ELNDDW3L4pkil3rezsEH">/pages/ELNDDW3L4pkil3rezsEH</a></td><td></td></tr><tr><td><strong>Yaml parse transform action</strong></td><td><a href="/pages/JJD4HnCgAT4Q8ZnxQX9U">/pages/JJD4HnCgAT4Q8ZnxQX9U</a></td><td></td></tr></tbody></table>


# Add or subtract from DateTime transform action

## Use case

You would like to programmatically determine what the date was thirty days ago.

## Overview

Add or Subtract from a DateTime

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>DateTime to add or subtract from</td><td>Use https://strftime.org/ for various options</td><td>true</td></tr><tr><td>Days to add or subtract</td><td>Integer value for how many days to add or subtract.</td><td>false</td></tr><tr><td>Hours to add or subtract</td><td>Integer value for how many hours to add or subtract.</td><td>false</td></tr><tr><td>Microseconds to add or subtract</td><td>Integer value for how many microseconds to add or subtract.</td><td>false</td></tr><tr><td>Minutes to add or subtract</td><td>Integer value for how many minutes to add or subtract.</td><td>false</td></tr><tr><td>Months to add or subtract</td><td>Integer value for how many months to add or subtract.</td><td>false</td></tr><tr><td>Seconds to add or subtract</td><td>Integer value for how many seconds to add or subtract.</td><td>false</td></tr><tr><td>Years to add or subtract</td><td>Integer value for how many years to add or subtract.</td><td>false</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Get 30 days from today's date</summary>

Inputs:

**DateTime to add or subtract from:** `{{ now("UTC","%m-%d-%Y") }}`**Days to add or subtract:** 30

The rest of the inputs in this example are blank.

</details>

## Results output

Result from Example 1 (if run on 04/16/2025):

```
"2025-05-16T00:00:00+00:00"
```


# All transform action

## Use case

You are reviewing a list of users, and want to determine if all of the users are enabled. The previous list has been mapped using the map transform action to the attribute `enabled` , providing a list of boolean True/False values to check against.

## Overview

This transform action will look at a list of boolean values and return true if all of the elements in the list are true.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>List</td><td>List of boolean values to check against.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Confirm All Items In List Are True</summary>

**List to Check** (input):

```
{{ [true, false, true, true] }}
```

</details>

## Results output

This transform will output a boolean value.

Example output from Example 1:

```json
False
```


# Any transform action

## Use case

You are reviewing a list of users and you need to determine if any of the users are enabled. The previous list has been mapped using the map transform action to the attribute `enabled` , providing a list of boolean True/False values to check against.

## Overview

This transform action will look at a list of boolean values and return true if any of the elements are true.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>List</td><td>List of boolean values to check against.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Confirm Any Items In List Are True</summary>

**List to Check** (input):

```
{{ [true, false, true, true] }}
```

</details>

## Results output

This transform will output a boolean value.

Example output from Example 1:

```json
True
```


# Append with items results transform action

Seamlessly integrate "With Items" task results into your original list.

## Use case

You're dealing with nested data structures and need to extract results from tasks ran With Items into your original list. You want a unified, easy-to-manipulate list that includes all necessary data.

## Overview

The `Append With Items Results` transform enables effective incorporation of "With Items" task results into your original list. It bridges the gap between the collected results and the original list, making your data manipulation tasks simpler and more efficient. Extract a nested `result.result` list from each item in a specified list and append it to another specified list as an attribute with a provided name.

## Parameters

<table><thead><tr><th width="164">Parameter</th><th width="473.33333333333326">Description</th><th data-type="checkbox">Required</th><th data-hidden data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Base List</td><td>This is the main list to which you want your collected results to be appended.</td><td>true</td><td>true</td></tr><tr><td>Collected List</td><td>This is the list of results from your completed <code>With Items</code> task, from which the nested <code>result.result</code> attribute will be extracted.</td><td>true</td><td>true</td></tr><tr><td>Attribute Name</td><td>This is the name you'd like to set for the new attribute to be appended to the <code>Base List</code>.</td><td>true</td><td>true</td></tr></tbody></table>

## Usage

The below scenario will attempt to illustrate how the `Process With Items Results` transform can be utilized to simplify `With Items` results collection.

### **Input lists**

Assume we have a base list called `base_list`:

```json
base_list: [
  {
    name: "John",
    age: 30,
  },
  {
    name: "Mary",
    age: 35,
  },
]
```

And we ran a `With Items` task against this list to collect additional data from these items that's stored in a new list called `collected_list` that includes `result.result` attributes like this

```json
collected_list: [
  {
    result: {
      result: ["golf", "reading"]
    }
  },
  {
    result: {
      result: ["cooking", "music"]
    }
  },
]
```

### Action parameters:

We want to extract the `result.result` list from each item in the `collected_list` and append it to each corresponding item in the `base_list` as a new attribute named `hobbies`.

```yaml
base_list: base_list
collected_list: collected_list
attribute_name: hobbies
```

### **Jinja2 equivalent:**

```jinja2
{% set normalized_list = [item.result.result for item in my_collected_list] %}
{% for list_item in normalized_list %}
  {% do my_base_list[loop.index0].update({'hobbies': list_item}) %}
{% endfor %}
```

## Results output

After processing, your results will look like this:

```json
results: [
  {
    name: "John",
    age: 30,
    hobbies: ["golf", "reading"]
  },
  {
    name: "Mary",
    age: 35,
    hobbies: ["cooking", "music"]
  },
]
```

{% hint style="success" %}
Remember to carefully specify your `Collected List`, `Base List`, and `Attribute Name` to ensure a successful transformation.
{% endhint %}


# Average transform action

## Use case

You received a list of users from an API that contains the user's ages.

You have mapped to the age attribute of the user dictionaries and would like to calculate the average of the new list of integers to get the average age of the users.

## Overview

Returns the average, or arithmetic mean, of a list of numbers.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>List</td><td>List to average</td><td>true</td></tr><tr><td></td><td></td><td>false</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Calculate the average of a list</summary>

Inputs: **List**: \[2,3,3,5,7,10]

</details>

## Results output

Result of example:

```
5
```


# Base64 Encode transform action

## Use Case

You have a string value of a CSV file and you are looking to send it as an attachment using the `Send Mail As Impersonated User` action via the `Microsoft Graph` integration which requires the CSV string to be base64 encoded.

## Overview

Encode a string in base64.

### Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>String</td><td>String to encode</td><td>true</td></tr><tr><td>URL Safe</td><td>Whether to return a URL-safe base64 format. '-' is used instead of '+', and '_' instead of '/'.</td><td>false</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Encoding a String</summary>

Inputs:\
\*\*String\*\*: This @is my test string-yeeeehaw\
\*\*URL Safe\*\*: false

</details>

## Results output

Result of Example 1:

```
VGhpcyBAaXMgbXkgdGVzdCBzdHJpbmcteWVlZWVoYXc=
```


# Base64 Decode transform action

## Use case

An API has returned a value that is base64 encoded and you would like to decode it.

## Overview

Decode a base64 encoded string.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>String</td><td>String to decode.</td><td>true</td></tr><tr><td>URL Safe</td><td>Whether the base64-encoded has been encoded in URL-safe format.</td><td>false</td></tr><tr><td>As Bytes</td><td>Whether to return the raw bytes, instead of decoding the bytes as a UTF-8 string.</td><td>false</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Decoding a String</summary>

Inputs:\
\*\*String\*\*: VGhpcyBAaXMgbXkgdGVzdCBzdHJpbmcteWVlZWVoYXc=\
\*\*URL Safe\*\*: false\
\*\*As Bytes\*\*: false

</details>

## Results output

Result of Example 1:

```
This @is my test string-yeeeehaw
```


# Compare dates transform action

## Use case

You are building a workflow that checks if the tickets closed date is greater than the expected close date and would like to know if action is needed based on a true/false value.

## Overview

This transform will take two dates and an operator, it will then perform a comparison based on the operator and return a boolean value.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>First Date</td><td>This should be a valid datetime string representation.</td><td>true</td></tr><tr><td>Second Date</td><td>This should be a valid datetime string representation.</td><td>true</td></tr><tr><td>Comparison Operator</td><td>The operator to use in the comparison.</td><td>true</td></tr><tr><td>Day First</td><td>Whether to interpret the first value in an ambiguous 3-integer date (e.g. 01/05/09) as the day (True) or month (False). If yearfirst is set to True, this distinguishes between YDM and YMD. If set to None, this value is retrieved from the current parserinfo object (which itself defaults to False).</td><td>false</td></tr><tr><td>Fuzzy Parsing</td><td>Whether to allow fuzzy parsing, allowing for string like "Today is January 1, 2047 at 8:21:00AM"</td><td>false</td></tr><tr><td>Ignore Timezone</td><td>If set True, time zones in parsed strings are ignored and a timezone naive datetime object is returned.</td><td>false</td></tr><tr><td>Year First</td><td>Whether to interpret the first value in an ambiguous 3-integer date (e.g. 01/05/09) as the year. If True, the first number is taken to be the year, otherwise the last number is taken to be the year. If set to None, this value is retrieved from the current parserinfo object (which itself defaults to False).</td><td>false</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Greater Than</summary>

Inputs:**First Date:** 2025-03-13T04:00:00.000Z**Second Date:** 2025-03-14T04:00:00.000Z**Comparison Operator:** >**Day First:** None**Fuzzy Parsing:** True**Ignore Timezone:** False**Year First:** None

</details>

## Results output

The expected output for this transform is a boolean value based on the comparison of the two dates.

Result Output for Example 1:

```json
False
```


# Convert DateTime to timezone transform action

## Use case

You are working with an API that returns a time in UTC, you would like to localize this value to your timezone or a specific timezone.

## Overview

Convert a DateTime to a different timezone.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>DateTime to convert</td><td>Use <a href="https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior</a> for various options</td><td>true</td></tr><tr><td>Timezone to convert</td><td>Use https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for various options not listed</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
Some timezone values are timezone naive, such as EST. If you would like to use a timezone aware value then, as an example, you should use America/New\_York or US/Eastern.
{% endhint %}

## Usage

<details>

<summary>Example: Convert a UTC timestamp to EST/EDT</summary>

Inputs:

**DateTime to convert:** 2025-04-16T09:00:30.000Z

**Timezone to return:** US/Eastern

</details>

## Results output

Result of Example:

```json
"2025-04-16T05:00:30-04:00"
```


# Convert from epoch transform action

## Use case

You have received a time value in epoch time from an API and would like to convert it to a date time string representation.

## Overview

Given an integer for epoch time, convert it to a date time string.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Epoch Time Value</td><td>Epoch time value to convert to a date time string.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Convert epoch time value</summary>

Input: **Epoch Time Value**: `{{ now() }}`

</details>

### Results output

For this example the now( ) method is feeding in a value of `1747395397`.

```
2025-05-16T11:36:37+00:00
```


# Convert list to object transform action

Transforms a list into an object with extracted key-value pairs.

## Overview

This transform action allows you to convert a list of objects into a single object, creating each object's property using user-defined key-value pairs extracted from the list, and simplifying the handling of complicated list structures.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th><th data-hidden data-type="checkbox">Required</th></tr></thead><tbody><tr><td>List to Transform</td><td>The list of objects you want to transform into a single object. Each item in the list should be a object with key-value pairs.</td><td>true</td><td>true</td></tr><tr><td>Field to use as Key</td><td>The field name from the items in your list that you want to use as keys in your new object.</td><td>true</td><td>true</td></tr><tr><td>Field to use as Value</td><td>The field name from the items in your list that you want to use as values in your new object.</td><td>true</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
For nested field names, separate them by dots (e.g., `details.age`).
{% endhint %}

## Usage

The `Convert List to Object` transform provides a powerful way to reshape your data to meet specific requirements. The ability to define keys and values, including the ability to access nested data, makes it versatile for a range of scenarios. Let's go through a couple of use-case examples to demonstrate how this transform can be applied to your data.

<details>

<summary>Example 1: Simple Key-Value Conversion</summary>

Let's assume we have this list of objects called `mylist`:

```json
mylist: [
  {
    name: "John",
    age: 30,
    hobbies: ["golf", "reading"],
  },
  {
    name: "Mary",
    age: 35,
    hobbies: ["cooking", "music"],
  },
]
```

**Action Parameters:**

We want to create a new object where the keys are the `name` field and the values are the `age` field. We would use the following parameters:

```json
key_field: name
value_field: age
```

**Jinja2 Equivalent:**

```jinja2
{% set new_object = {} %}
{% for item in mylist %}
  {% set _ = new_object.update({item['name']: item['age']}) %}
{% endfor %}


```

</details>

<details>

<summary>Example 2: Nested Key-Value Conversion</summary>

Now, let's consider a list of objects where some fields are nested:

```json
mylist: [
  {
    name: "John",
    details: {
      age: 30,
      occupation: "Engineer"
    },
    hobbies: ["golf", "reading"],
  },
  {
    name: "Mary",
    details: {
      age: 35,
      occupation: "Doctor"
    },
    hobbies: ["cooking", "music"],
  },
]
```

**Action Parameters:**

In this case, the `age` field is nested under the `details` object. So, to create an object where the keys are the `name` field and the values are the `age` field nested under `details`, we would use the following parameters:

```json
key_field: name
value_field: details.age
```

**Jinja2 Equivalent:**

```jinja2
{% set new_object = {} %}
{% for item in mylist %}
  {% set _ = new_object.update({item['name']: item['details']['age']}) %}
{% endfor %}


```

</details>

## Results output

In both of these examples, your new output object would look as follows:

```json
results: {
  "John": 30,
  "Mary": 35
}
```

{% hint style="info" %}
*This transform is especially useful when dealing with data structures like ConnectWise PSA Custom Fields or Communication Items.*
{% endhint %}


# Defang transform action

## Use case

You have a email with a URL in it similar to something like:\
<https://rewst.io/aprilfools/surprise.html\\>
You would like to defang it and make it not directly usable.

## Overview

Given a URL, this action will 'defang' the url by adding characters to prevent it from being directly usable.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>URL</td><td>URL to defang</td><td>true</td></tr><tr><td>Colon</td><td>If true defang colons.</td><td>false</td></tr><tr><td>Dots</td><td>If true defang all dots.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Defang the url https://rewst.io/aprilfools/surprise.html</summary>

Inputs:

Colon: True

Dots: True

URL: <https://rewst.io/aprilfools/surprise.html>

</details>

## Results output

The expected result of this transform is a defanged url.

Result from Example 1:

```
hXXps[:]//rewst[.]io/aprilfools/surprise.html
```


# Diff lists transform action

Identify the differences between two input lists.

## Use case

You need to compare two lists and highlight the unique entries or entries exclusive to the first list, A transformation action that simplifies this complex comparison process is required.

## Overview

The `Diff Lists` transform is your solution for list comparison tasks. It uses two methods - `Anti-Join` and `Symmetric Difference` - to focus on unique or exclusive entries, thereby streamlining your data comparison process.

## Parameters

Here are the parameters you have available to you within the action, and their descriptions:

<table><thead><tr><th width="192">Parameter</th><th width="438.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Difference Method</td><td>Choose the method to compute the differences between the lists. Options are <code>anti_join</code> and <code>symmetric_difference</code> (described below).</td><td>true</td></tr><tr><td>First List</td><td>Enter the first list to be compared.</td><td>true</td></tr><tr><td>First List's Key</td><td>Identify the key attribute for matching items in the first list.</td><td>true</td></tr><tr><td>Second List</td><td>Enter the second list to be compared.</td><td>true</td></tr><tr><td>Second List's Key</td><td>Identify the key attribute for matching items in the second list.</td><td>true</td></tr></tbody></table>

## Usage

### **Input lists**

For this transform, we will want to feed the action two separate lists, that we will then identify the fields in which we want to identify differences. Let's use these two lists as example:

**List 1:**

```json
list_1: [
  {"id": 1, "name": "John"},
  {"id": 2, "name": "Mary"}
]
```

**List 2:**

```json
list_2: [
  {"id": 1, "age": 30},
  {"id": 3, "age": 35}
]
```

### Difference methods

We have two options for the `Difference Method` you can pick to have the action perform, these method have slight differences that are quite helpful in various situations:

* **Anti-join:** for scenarios where you want to find entries that are exclusive to the first list.
* **Symmetric difference:** for comparing two sets of data and identifying unique records in each.

Take a look at examples of both below:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th></tr></thead><tbody><tr><td><img src="/files/XkiYRnWxrtrq4sesXZTy" alt="" data-size="original"></td><td>The <code>Symmetric Difference</code> method is used when you want to identify entries that are unique to each list, i.e., items that exist in the one list and not in the other.</td><td></td></tr><tr><td></td><td><img src="/files/acsML5WFc29qmlFyBvzF" alt=""></td><td>The <code>Anti Join</code> difference method is used when you want to determine the items in the first list that don't have a corresponding match in the second list.</td></tr></tbody></table>

***

<details>

<summary>Anti join</summary>

**Action Parameters:**

```yaml
diff_method: anti_join
list_1: List 1
list1_key: id
list_2: List 2
list2_key: id
```

**Jinja2 Equivalent:**

```django
{% set result = [] %}
{% for item1 in list_1 %}
  {% if all(item1[list1_key] != item2[list2_key] for item2 in list_2) %}
    {% do result.append(item1) %}
  {% endif %}
{% endfor %}


{{ result }}
```

</details>

<details>

<summary>Symmetric difference</summary>

**Action Parameters:**

```yaml
diff_method: symmetric_difference
list_1: {{ CTX.list_1 }}
list1_key: id
list_2: {{ CTX.list_2 }}
list2_key: id
```

**Jinja2 Equivalent:**

```django
{% set result = [] %}
{% for item1 in list_1 %}
  {% if all(item1[list1_key] != item2[list2_key] for item2 in list_2) %}
    {% do result.append(item1) %}
  {% endif %}
{% endfor %}
{% for item2 in list_2 %}
  {% if all(item2[list2_key] != item1[list1_key] for item1 in list_1) %}
    {% do result.append(item2) %}
  {% endif %}
{% endfor %}


{{ result }}
```

</details>

## Results output

The results of the two different diff methods can be seen as follows:

**Anti join:** only Mary's object from `list_1` is returned in the output, as she didn't have a correlating `id` in `list_2`.

```json
result: [
  {"id": 2, "name": "Mary"}
]
```

**Symmetric difference:** both Mary's object from `list_1` and the object in `list_2` that didn't have a correlating id in `list_1` were returned in the returned list.

```json
result: [
  {"id": 2, "name": "Mary"},
  {"id": 3, "age": 35}
]
```

***

With a grasp on the `Diff Lists` transform, you're ready to analyze and compare your lists for unique entries or entries exclusive to the first list. Understanding the differences between `Anti-Join` and `Symmetric Difference` methods will aid you in making effective data comparisons.


# Extract part of a date transform action

## Use Case

You have received a date in a response from an API, you are going to use this to dynamically specify the year in another request based on what was received in the response.

## Overview

Given a date or date time string, extract a part of the date.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Date Time String</td><td>The original date time string to extract a part from.</td><td>true</td></tr><tr><td>Part to Extract</td><td>The part of the date to extract. Defaults to year.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Extract the year from a date</summary>

Inputs: **Date Time String**: 2025-06-27T00:05:24.000 **Part**: Year (4 digits)

</details>

<details>

<summary>Example 2: Extract the day from a date</summary>

Inputs: **Date Time String**: 2025-06-27T00:05:24.000 **Part**: Day

</details>

## Results output

Result from Example 1:

```
2025
```

Result from Example 2:

```
27
```


# Flatten list transform action

## Use case

You are working with a list of users, however the users are nested in a list.

You would like to flatten the list of lists so it ends up as a list of objects.

## Overview

Flatten a nested List.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Array variable to flatten</td><td>The array you would like to flatten</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Flattening nested lists</summary>

Input:

**Array variable to flatten:**

```json
[
    [
        {
            "user": "Dan"
        }
    ]
],
[
    [
        {
            "user": "Bob"
        }
    ]
],
[
    [
        {
            "user": "Sheryl"
        }
    ]
],
[
    [
        {
            "user": "Sarah"
        }
    ]
],
[
    [
        {
            "user": "Sean"
        }
    ]
]
```

</details>

## Results output

Result of Example:

```json
[
  {
    "user": "Dan"
  },
  {
    "user": "Bob"
  },
  {
    "user": "Sheryl"
  },
  {
    "user": "Sarah"
  },
  {
    "user": "Sean"
  }
][
  {
    "user": "Dan"
  },
  {
    "user": "Bob"
  },
  {
    "user": "Sheryl"
  },
  {
    "user": "Sarah"
  },
  {
    "user": "Sean"
  }
]
```


# Format date time transform action

## Use case

You have received a date time string representation from an API, you would like to utilize this value in another API, however the new API expects it to be in a certain date format.

## Overview

Given a date or date time string, format it to a different date time string. Custom input can be used, please refer to <https://strftime.org/> for the format string options.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Date Time String</td><td>The original date time string that needs formatted differently.</td><td>true</td></tr><tr><td>Day First</td><td>Whether to interpret the first value in an ambiguous 3-integer date (e.g. 01/05/09) as the day (True) or month (False). If yearfirst is set to True, this distinguishes between YDM and YMD. If set to None, this value is retrieved from the current parserinfo object (which itself defaults to False).</td><td>false</td></tr><tr><td>Year First</td><td>Whether to interpret the first value in an ambiguous 3-integer date (e.g. 01/05/09) as the year. If True, the first number is taken to be the year, otherwise the last number is taken to be the year. If set to None, this value is retrieved from the current parserinfo object (which itself defaults to False).</td><td>false</td></tr><tr><td>Fuzzy Parsing</td><td>Whether to allow fuzzy parsing, allowing for string like "Today is January 1, 2047 at 8:21:00AM"</td><td>false</td></tr><tr><td>Ignore Timezone</td><td>If set True, time zones in parsed strings are ignored and a timezone naive datetime object is returned.</td><td>false</td></tr><tr><td>Desired String Format</td><td>Defaults to YYYY-MM-DDTHH:MM:SSZ if left empty.</td><td>false</td></tr></tbody></table>

{% hint style="info" %}
You can provide a custom format by manually entering your strftime string into the format field. For placeholder references please visit <https://strftime.org/> .
{% endhint %}

## Usage

<details>

<summary>Example 1: Change date of 2025-05-25T07:00:00.000Z to YYYY-MM-DD</summary>

Inputs:\
**Date Time String:** 2025-03-13T04:00:00.000Z\
**Day First:** None\
**Fuzzy Parsing:** True\
**Ignore Timezone:** False**Y**\
**ear First:** None\
**Desired String Format:** YYYY-MM-DD

It's important to note that YYYY-MM-DD is a select-able value in the drop down for the field. If you were to do this via a custom input, then it would be: %Y-%m-%d

</details>

## Results output

Example output from Example 1:

```
2025-05-25
```


# Generate friendly password transform action

## Use case

You are resetting a user's password and would like to generate a friendly password.

## Overview

This action generates an easy password with adjective, name, number, symbol and random caps.

## Parameters

There are no parameters for this transform.

## Usage

This transform has no parameters, so no usage examples can be given.

## Results output

Example 1:

```
FAirBAnDIcooT39!
```

Example 2:

```
GREENBoNoBo73=
```

Example 3:

```
KINDSNakE41$
```


# Get business days between dates transform action

## Use case

You would like to get the count of business days between dates.

## Overview

Get the number of business days between two dates.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Start Date</td><td>The start date; This day is inclusive in the returned count.</td><td>true</td></tr><tr><td>End Date</td><td>The end date; This day is exclusive in the returned count.</td><td>true</td></tr><tr><td>Holidays</td><td>A list of holidays</td><td>false</td></tr><tr><td>Country</td><td>Country Specific Holidays to remove from the set.</td><td>false</td></tr></tbody></table>

{% hint style="info" %}
It is important to note that the end date is exclusive in the returned count, only start date is inclusive in the count.
{% endhint %}

## Usage

<details>

<summary>Example 1: 07/01/2025 through 07/07/2025 excluding US Holidays</summary>

Inputs:

**Start Date:** 07/01/2025

**End Date:** 07/07/2025

**Holidays:**

**Country:** United States of America

</details>

<details>

<summary>Example 2: 07/01/2025 through 07/07/2025 not excluding US Holidays</summary>

Inputs:

**Start Date:** 07/01/2025

**End Date:** 07/07/2025

**Holidays:**

**Country:**

</details>

## Results output

Result of Example 1:

```
3
```

Result of Example 2:

```
4
```


# Get DateTime transform action

## Use case

You would like to get the current date/datetime.

## Overview

Returns the current date/time in the requested timezone.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>DateTime format to return</td><td>Use https://strftime.org/ for various options</td><td>true</td></tr><tr><td>Timezone to return</td><td>The timezone you would like to have the date returned in.</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
Some timezone values are timezone naive, such as EST. Say you would like to use a timezone aware value. Following that example, you should use America/New\_York or US/Eastern.

A good point of reference is: <https://en.wikipedia.org/wiki/List\\_of\\_tz\\_database\\_time\\_zones>
{% endhint %}

## Usage

<details>

<summary>Example: Get Current DateTime for US Eastern</summary>

Inputs:

**DateTime format to return:** %Y-%m-%dT%H:%M:%SZ

**Timezone to return:** US/Eastern

</details>

## Results output

Results of Example:

```
2025-04-16T08:07:04Z
```


# Get days between dates transform action

## Use case

You would like to get the count of days between dates.

## Overview

Get the number of days between two dates.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Start Date</td><td>The start date; This day is inclusive in the returned count.</td><td>true</td></tr><tr><td>End Date</td><td>The end date; This day is exclusive in the returned count.</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
It is important to note that the end date is exclusive in the returned count. Only start date is inclusive in the count.
{% endhint %}

## Usage

<details>

<summary>Example: 07/01/2025 through 07/07/2025</summary>

Inputs:

**Start Date:** 07/01/2025

**End Date:** 07/07/2025

**Holidays:**

**Country:** United States of America

</details>

## Results output

Result of Example:

```
6
```


# Get list length transform action

## Use case

You have a list of user's that has been returned from an API, you would like to determine the count of user's in the list.

## Overview

Measures the length of a List. It will return the number of elements of that list.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>List to Measure</td><td>The array/list to get the length of.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Getting the count of numbers in a list</summary>

Inputs:

**List to Measure:** `[1,2,3,4,5]`

</details>

## Results output

Result of Example:

```
5
```


# Get string length transform action

## Use case

There is a character limit on a field in an upcoming API call, you would like to check the length of the input prior to making the call.

## Overview

Measures the length of a String. It will return the number of characters in that string.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>String to Measure</td><td>The string to get the length of.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Getting the count of numbers in a string</summary>

Inputs:

**String to Measure:** The quick brown fox jumps over the lazy dog

</details>

## Results output

Result of Example:

```
43
```


# Is JSON transform action

## Use case

You are working with an API and the return comes back as a JSON string instead of being a JSON object. You would like to verify that the string is valid JSON before attempting to convert it to JSON.

## Overview

This transform will check whether or not a string provided via the 'String to Check' input is a valid JSON string.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>String to Check</td><td>The string to validate.</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
This transform is useful for confirming a string is a valid JSON string prior to converting it to json using a filter such as `|json`
{% endhint %}

## Usage

<details>

<summary>Example 1: Providing a valid JSON string</summary>

Input:

```
{"test":"test"}
```

</details>

<details>

<summary>Example 2: Providing a invalid JSON string</summary>

Input:

```
I am not a JSON string!
```

</details>

## Results output

\
This transform will output a boolean value (True/False) based on whether or not the string is a valid JSON string.

Return from Example 1:

```json
True
```

Return from Example 2:

```json
False
```


# Map to an attribute within a list transform action

## Use case

You are trying to create a list of users from a Microsoft Graph return and want to create a flat list of all the display names for the users.

## Overview

Map to an attribute for each dictionary object in a list.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Attribute</td><td>The attribute to map to, dot notation can be used. For example, result.result</td><td>true</td></tr><tr><td>List</td><td>The list you would like to perform the map on.</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
This is useful for working with results returned from actions running with items so you don't have to worry about the nested result keys.
{% endhint %}

## Usage

<details>

<summary>Example 1: Mapping to usernames in a response</summary>

Inputs:

**Attribute:** result.result.data.username

**List:**

```json
[
  {
    "result": {
      "result": {
        "data": {
          "username": "amorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "username": "bmorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "username": "cmorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "username": "dmorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "username": "emorton"
        }
      }
    }
  }
]
```

</details>

## Results output

This transform is expected to return a new list that is mapped to the selected attribute.

Example of result for Example 1:

```json
[
  "amorton",
  "bmorton",
  "cmorton",
  "dmorton",
  "emorton"
]
```


# Merge lists transform action

Blend two input lists into one using a shared identifier.

## Use case

You're faced with two separate lists of data that need to be combined based on a common attribute. You require a merging method that mimics SQL JOINs.

## Overview

The `Merge Lists` transform equips you with the functionality to effectively merge two lists into one. By aligning items based on a shared key attribute and allowing for three types of merging strategies (`inner`, `left`, and `outer`), it enhances your data analysis and manipulation capabilities.

## Parameters

Here are the parameters you have available to you within the action, and their descriptions:

<table><thead><tr><th width="189">Parameter</th><th width="438.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Merge Method</td><td>Choose the strategy to merge the lists. Options are <code>inner</code>, <code>left</code>, or <code>outer</code> join.</td><td>true</td></tr><tr><td>First List</td><td>Enter the first list for the merging process.</td><td>true</td></tr><tr><td>First List's Key</td><td>Identify the key attribute for matching items in the first list.</td><td>true</td></tr><tr><td>Second List</td><td>Enter the second list to be merged with the first one.</td><td>true</td></tr><tr><td>Second List's Key</td><td>Identify the key attribute for matching items in the second list.</td><td>true</td></tr></tbody></table>

## Usage

### Input lists

For this transform, we will want to provide the action two lists and their corresponding key's to be used for mapping the comparisons. Let's use the below for our examples:

**List 1:**

```json
list_1: [
  {"id": 1, "name": "John"},
  {"id": 2, "name": "Mary"}
]
```

**List 2:**

```json
list_2: [
  {"id": 1, "age": 30},
  {"id": 3, "age": 35}
]
```

### Merge methods

This transform offers three different methods for merging your lists: `Inner`, `Left`, and `Outer` joins. These three methods mimic the functionality of SQL JOINs and each has its own use cases:

1. **Inner join:** useful when you're dealing with two datasets and only want to focus on data that is common between them.
2. **Left join:** useful when the first list is your primary dataset and you wish to append any additional, relevant data from the second list to it.
3. **Outer join:** useful when you aim for a comprehensive view, combining all data from both lists, and filling in gaps where possible.

Here are some examples of these methods in action to help you better understand their operation:

<details>

<summary>Inner join</summary>

The `Inner` merge method is used when you only want to retain the entries that are present in both lists. The intersection is based on the values of the specified keys.

**Action Parameters:**

```yaml
join_method: inner
list_1: list_1
list1_key: id
list_2: list_2
list2_key: id
```

**Jinja2 Equivalent:**

```django
jinjaCopy code
{% set result = [] %}
{% for item1 in list_1 %}
  {% for item2 in list_2 %}
    {% if item1[list1_key] == item2[list2_key] %}
      {% do result.append(item1 | combine(item2)) %}
    {% endif %}
  {% endfor %}
{% endfor %}


```

</details>

<details>

<summary>Left join</summary>

The `Left` merge method is employed when you want to keep all the entries from the first list and incorporate matching entries from the second list.

**Parameters:**

```yaml
join_method: left
list_1: List 1
list1_key: id
list_2: List 2
list2_key: id
```

**Jinja2 Equivalent:**

```django
{% for item1 in list_1 %}
  {% for item2 in list_2 %}
    {% if item1[list1_key] == item2[list2_key] %}
      {% do item1.update(item2) %}
    {% endif %}
  {% endfor %}
{% endfor %}


{{ list_1 }}
```

</details>

<details>

<summary>Outer join</summary>

The `Outer` merge method is used when you want to keep all entries from both lists, regardless of whether they have a match.

**Parameters:**

```yaml
join_method: outer
list_1: List 1
list1_key: id
list_2: List 2
list2_key: id
```

**Jinja2 Equivalent:**

```django
{% for item1 in list_1 %}
  {% for item2 in list_2 %}
    {% if item1[list1_key] == item2[list2_key] %}
      {% do item1.update(item2) %}
    {% endif %}
  {% endfor %}
{% endfor %}
{{ list_1 + [item2 for item2 in list_2 if all(item2[list2_key] != item1[list1_key] for item1 in list_1)] }}
```

</details>

## Results output

The outputs of the three different merge method examples above can be seen as follows:

**Inner join:** only John's object is returned in the output, as his `id` is present in both lists.

```json
results: [
  {"id": 1, "name": "John", "age": 30}
]
```

**Left join:** all objects from `list_1` are returned, with matching objects from `list_2` added on. This is why John's object includes the age from `list_2`, but Mary's object remains the same, as there was no matching `id` in `list_2`.

```json
results: [
  {"id": 1, "name": "John", "age": 30},
  {"id": 2, "name": "Mary"}
]
```

**Outer join:** all objects from both lists are returned, with matching objects merged together. Therefore, we get John's object with the `age` from `list_2`, Mary's object from `list_1`, and the object with `id` 3 from `list_2` which didn't have a matching `id` in `list_1`.

```css
results: [
  {"id": 1, "name": "John", "age": 30},
  {"id": 2, "name": "Mary"},
  {"id": 3, "age": 35}
]
```

***

Now that you're equipped with the knowledge of `Merge Lists` transform, you're prepared to blend data from two different lists into a coherent whole. Keep in mind your merging strategy (`inner`, `left`, or `outer`) as it directly impacts your resulting list.


# Parse CSV transform action

## Use case

You have received a return with a string in CSV format and you would like to convert this to a list of JSON objects.

## Overview

Parse CSV Data into JSON. The first line will be keys, and subsequent lines will be values.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Delimiter</td><td>Character or sequence of characters to used as a delimiter in the CSV (default is ), such as '|';':', etc.</td><td>true</td></tr><tr><td>String Contents</td><td>Input the CSV formatted string you would like to convert to JSON.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Convert CSV to JSON</summary>

Inputs:

**Delimiter:** ,

**String Contents:**

```
Index,Name,Description,Brand,Category,Price,Currency,Stock,EAN,Color,Size,Availability,Internal ID
1,Compact Printer Air Advanced Digital,Situation organization these memory much off.,"Garner, Boyle and Flynn",Books & Stationery,265,USD,774,2091465262179,ForestGreen,Large,pre_order,56
2,Tablet,Discussion loss politics free one thousand.,Mueller Inc,Shoes & Footwear,502,USD,81,5286196620740,Black,8x10 in,in_stock,29
3,Smart Blender Cooker,No situation per.,"Lawson, Keller and Winters",Kitchen Appliances,227,USD,726,1282898648918,SlateGray,XS,in_stock,70
4,Advanced Router Rechargeable,For force gas energy six laugh.,Gallagher and Sons,Kitchen Appliances,121,USD,896,3879177514583,PaleGreen,L,discontinued,31
5,Portable Mouse Monitor Phone,Feeling back religious however author room scientist.,Irwin LLC,Kids' Clothing,1,USD,925,9055773261265,SeaShell,100x200 mm,discontinued,10
6,Radio,Character prove growth contain serious customer.,"Benjamin, Nelson and Hancock",Skincare,426,USD,549,1150028980156,CornflowerBlue,30x40 cm,pre_order,60
7,Ultra Projector Oven Thermostat Prime Advanced,Pattern possible look necessary indicate work nearly.,"Mccoy, Waters and Rose",Laptops & Computers,68,USD,870,5029747624534,Purple,S,discontinued,86
8,Webcam Stove Grill,Deep area join carry age.,Morrow and Sons,Automotive,159,USD,584,9883725074294,MediumOrchid,8x10 in,pre_order,50
9,Eco Radio,Know father for act let.,"Edwards, Odonnell and Conley",Skincare,454,USD,499,1773215338624,DimGray,Medium,pre_order,88
```

</details>

## Results output

Result of Example:

```json
[
  {
    "EAN": "2091465262179",
    "Name": "Compact Printer Air Advanced Digital",
    "Size": "Large",
    "Brand": "Garner, Boyle and Flynn",
    "Color": "ForestGreen",
    "Index": "1",
    "Price": "265",
    "Stock": "774",
    "Category": "Books & Stationery",
    "Currency": "USD",
    "Description": "Situation organization these memory much off.",
    "Internal ID": "56",
    "Availability": "pre_order"
  },
  {
    "EAN": "5286196620740",
    "Name": "Tablet",
    "Size": "8x10 in",
    "Brand": "Mueller Inc",
    "Color": "Black",
    "Index": "2",
    "Price": "502",
    "Stock": "81",
    "Category": "Shoes & Footwear",
    "Currency": "USD",
    "Description": "Discussion loss politics free one thousand.",
    "Internal ID": "29",
    "Availability": "in_stock"
  },
  {
    "EAN": "1282898648918",
    "Name": "Smart Blender Cooker",
    "Size": "XS",
    "Brand": "Lawson, Keller and Winters",
    "Color": "SlateGray",
    "Index": "3",
    "Price": "227",
    "Stock": "726",
    "Category": "Kitchen Appliances",
    "Currency": "USD",
    "Description": "No situation per.",
    "Internal ID": "70",
    "Availability": "in_stock"
  },
  {
    "EAN": "3879177514583",
    "Name": "Advanced Router Rechargeable",
    "Size": "L",
    "Brand": "Gallagher and Sons",
    "Color": "PaleGreen",
    "Index": "4",
    "Price": "121",
    "Stock": "896",
    "Category": "Kitchen Appliances",
    "Currency": "USD",
    "Description": "For force gas energy six laugh.",
    "Internal ID": "31",
    "Availability": "discontinued"
  },
  {
    "EAN": "9055773261265",
    "Name": "Portable Mouse Monitor Phone",
    "Size": "100x200 mm",
    "Brand": "Irwin LLC",
    "Color": "SeaShell",
    "Index": "5",
    "Price": "1",
    "Stock": "925",
    "Category": "Kids' Clothing",
    "Currency": "USD",
    "Description": "Feeling back religious however author room scientist.",
    "Internal ID": "10",
    "Availability": "discontinued"
  },
  {
    "EAN": "1150028980156",
    "Name": "Radio",
    "Size": "30x40 cm",
    "Brand": "Benjamin, Nelson and Hancock",
    "Color": "CornflowerBlue",
    "Index": "6",
    "Price": "426",
    "Stock": "549",
    "Category": "Skincare",
    "Currency": "USD",
    "Description": "Character prove growth contain serious customer.",
    "Internal ID": "60",
    "Availability": "pre_order"
  },
  {
    "EAN": "5029747624534",
    "Name": "Ultra Projector Oven Thermostat Prime Advanced",
    "Size": "S",
    "Brand": "Mccoy, Waters and Rose",
    "Color": "Purple",
    "Index": "7",
    "Price": "68",
    "Stock": "870",
    "Category": "Laptops & Computers",
    "Currency": "USD",
    "Description": "Pattern possible look necessary indicate work nearly.",
    "Internal ID": "86",
    "Availability": "discontinued"
  },
  {
    "EAN": "9883725074294",
    "Name": "Webcam Stove Grill",
    "Size": "8x10 in",
    "Brand": "Morrow and Sons",
    "Color": "MediumOrchid",
    "Index": "8",
    "Price": "159",
    "Stock": "584",
    "Category": "Automotive",
    "Currency": "USD",
    "Description": "Deep area join carry age.",
    "Internal ID": "50",
    "Availability": "pre_order"
  },
  {
    "EAN": "1773215338624",
    "Name": "Eco Radio",
    "Size": "Medium",
    "Brand": "Edwards, Odonnell and Conley",
    "Color": "DimGray",
    "Index": "9",
    "Price": "454",
    "Stock": "499",
    "Category": "Skincare",
    "Currency": "USD",
    "Description": "Know father for act let.",
    "Internal ID": "88",
    "Availability": "pre_order"
  }
]
```


# Parse text to JSON transform action

## Use case

You have received an API response of a JSON string instead of a JSON object and would like to convert it to a JSON object.

## Overview

Parse Text Data into JSON.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>String Contents</td><td>String to convert.</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
You can utilize the Is JSON transform to test whether the string is valid JSON prior to parsing it with this transform.
{% endhint %}

## Usage

<details>

<summary>Example: Parsing a JSON String</summary>

Inputs:

**String Contents:**

```json
{"id":"676e061a-8004-4f60-ad37-cb0b2be25635","user":"Sean","age":32,"bio":"Hi, my name is Sean.\nI love hiking."}
```

</details>

## Results output

Result of Example:

```json
{
  "id": "676e061a-8004-4f60-ad37-cb0b2be25635",
  "user": "Sean",
  "age": 32,
  "bio": "Hi, my name is Sean.\nI love hiking."
}
```


# Range transform action

## Use case

You want to generate an array of integers from 1 to 100 to use in the **With Items** field of an action. This will cause the action, such as an API call, to run once for each number in the array. During each run, you can reference the current number using `item()` and use it to dynamically construct values like usernames. For example, the first run would use `"User1"`, the second `"User2"`, and so on up to `"User100"`.

## Overview

This transform will return a list of integers from start to end.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Start</td><td>The starting value of the range, inclusive. Default is 0 if not provided.</td><td>true</td></tr><tr><td>End</td><td>The ending value of the range, exclusive. Default is 0 if not provided.</td><td>true</td></tr><tr><td>Step</td><td>The step size for the range. Defaults to 1 if not provided.</td><td>false</td></tr></tbody></table>

{% hint style="info" %}
The end field value is exclusive, so if you would like to have the end value of the array be 100 (as an example) then you would need to provide an end value of 101.
{% endhint %}

## Usage

<details>

<summary>Example: Create an array with 1 to 25</summary>

Inputs:

**Start**: 1 **End**: 26 **Step**: 1

</details>

### Results output

Result of Example:

```json
[
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  10,
  11,
  12,
  13,
  14,
  15,
  16,
  17,
  18,
  19,
  20,
  21,
  22,
  23,
  24,
  25
]
```


# Refang transform action

## Use case

You have an email with a defanged URL inside of it similar to something like: hXXps\[:]//rewst\[.]io/aprilfools/surprise.html

You would like to refang it and make the URL directly usable.

## Overview

Given a defanged URL, this action will refang the url by removing the added characters that prevent it from being directly usable.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>URL</td><td>URL to refang</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Refang hXXps[:]//rewst[.]io/aprilfools/surprise.html</summary>

Inputs:

Colon: True

Dots: True

URL: [**https://rewst.io/aprilfools/surprise.html**](https://rewst.io/aprilfools/surprise.html)

</details>

## Results output

The expected result of this transform is a standard url.

Result from Example 1:

```
https://rewst.io/aprilfools/surprise.html
```


# Remove duplicates from list transform action

## Use case

You are working with a list of users however, the dataset contains multiple objects with the same GUID, you would like to remove the duplicates from the list.

## Overview

Returns a list of unique items from the given list/iterable.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Attribute</td><td>Filter objects with unique values for this attribute; Only required for lists of objects.</td><td>false</td></tr><tr><td>Case Sensitive</td><td>Treat upper and lowercase strings as distinct.</td><td>false</td></tr><tr><td>List</td><td>List to remove duplicates from.</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
For nested field names, separate them by dots (e.g., `details.age`).
{% endhint %}

## Usage

<details>

<summary>Example 1: Filter List For Unique Objects Based On Username</summary>

#### Inputs

\
**Attribute:** username\
**Case Sensitive:** False\
**List:**

```json
[
  {
    "member": true,
    "username": "Dan"
  },
  {
    "member": true,
    "username": "DAn"
  },
  {
    "member": true,
    "username": "dan"
  },
  {
    "member": true,
    "username": "DaN"
  },
  {
    "member": false,
    "username": "Bob"
  }
]

```

</details>

<details>

<summary>Example 2: Filter List of Integers For Unique Integers</summary>

#### Inputs

\
**Attribute:** username\
**Case Sensitive:** False\
**List:**

````

```json
[ 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5 ]```
````

</details>

## Results output

The expected output for this transform is a new list of the unique items from the previous list.

Result of Example 1:

```json
[
  {
    "member": true,
    "username": "Dan"
  },
  {
    "member": false,
    "username": "Bob"
  }
]
```

Result of Example 2:

```json
[
  1,
  2,
  3,
  4,
  5
]
```


# Return element transform action

## Use case

You have a list of users and you would like to grab the first user in the list.

## Overview

Returns the Nth element of a string or list

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Element</td><td>Element number to Return, starting at 0 for the first element. -1 will return the last element</td><td>true</td></tr><tr><td>Input String or List</td><td>String or list that you would like to return the element of.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Return the first user in a list of users</summary>

Input:

**Element:** 0

**Input String or List:**

```json
[
    {
        "id": 1,
        "user": "Bob"
    },
    {
        "id": 2,
        "user": "Kim"
    },
    {
        "id": 3,
        "user": "Magnus"
    },
    {
        "id": 4,
        "user": "Karin"
    },
]
```

</details>

## Results output

Result of example 1:

```json
{
	"id": 1,
	"user": "Bob"
}
```


# Select attribute transform action

## Use case

While reviewing a list of users returned from Microsoft Graph, you need to get a list of the users who have a `accountEnabled` attribute value set to `true` .

## Overview

This action filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects where the test succeeds.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Attribute</td><td>The attribute of an object in the list that you would like to select if the condition is true. If nested, please use dot notation.</td><td>true</td></tr><tr><td>Comparison Operator</td><td>Test used for selecting matches. For information on the tests see <a href="https://jinja.palletsprojects.com/en/stable/templates/#jinja-tests">Jinja's documentation here</a>.</td><td>true</td></tr><tr><td>List</td><td>This is the list to run select attribute against.</td><td>true</td></tr><tr><td>Value to Compare Against</td><td>The value to compare the attribute against, this is required for most tests but tests such as true, false, defined, undefined do not require it. If a value is supplied and not needed it will be ignored.</td><td>false</td></tr></tbody></table>

{% hint style="info" %}
For nested field names, separate them by dots (e.g., `details.age`).
{% endhint %}

## Usage

<details>

<summary>Example: List Input</summary>

```json
[
  {
    "result": {
      "result": {
        "data": {
          "age": 20,
          "bool": true,
          "username": "amorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "age": 25,
          "bool": true,
          "username": "bmorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "age": 27,
          "bool": false,
          "username": "cmorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "age": 30,
          "bool": false,
          "listah": [],
          "username": "dmorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "age": 22,
          "bool": true,
          "username": "emorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "age": 29.99,
          "bool": null,
          "username": "fmorton"
        }
      }
    }
  }
]
```

</details>

<details>

<summary>Example 1: Return Users With Odd Ages</summary>

Inputs:

**Attribute:** result.result.data.age

**Comparison Operator:** odd

**List**: See `Example: List Input`

**Value to Compare Against**: None

</details>

<details>

<summary>Example 2: Return Users With Age Greater Than or Equal to 30</summary>

Inputs:

**Attribute:** result.result.data.age

**Comparison Operator:** ge

**List**: See `Example: List Input`

**Value to Compare Against**: 30

</details>

## Results output

The expected output for this transform is a list of objects that tested true.

Example from Example 1:

```json
[
  {
    "result": {
      "result": {
        "data": {
          "age": 25,
          "bool": true,
          "username": "bmorton"
        }
      }
    }
  },
  {
    "result": {
      "result": {
        "data": {
          "age": 27,
          "bool": false,
          "username": "cmorton"
        }
      }
    }
  }
]
```

Example from Example 2:

```json
[
  {
    "result": {
      "result": {
        "data": {
          "age": 30,
          "bool": false,
          "listah": [],
          "username": "dmorton"
        }
      }
    }
  }
]
```


# Set list field value transform action

Modify a specific field's value within your list objects.

## Use case

You have a list of objects where certain field values need adjusting. You need a solution that not only allows straightforward field value modifications, but also supports conditional changes and nested element modifications.

## Overview

The `Set List Field Value` action enables the customization of a field's value within a list of objects. Whether it's for conditional value adjustment based on specific criteria or working with nested elements, this action offers the flexibility you need.

## Parameters

<table><thead><tr><th width="178">Parameter</th><th width="472.3333333333333">Description</th><th data-type="checkbox">Required</th><th data-hidden>Required</th></tr></thead><tbody><tr><td>List to Transform</td><td>The list of objects you want to modify the contents of.</td><td>true</td><td>Yes</td></tr><tr><td>Field to Update</td><td>Specify the field to be added or modified in each object.</td><td>true</td><td>Yes</td></tr><tr><td>New Value</td><td>Specify the value for the new or modified field.</td><td>true</td><td>Yes</td></tr><tr><td>New Value Mode</td><td>How you want to provide the field's new value. <code>copy_from_field</code> or <code>set_value</code> (described below)</td><td>true</td><td>Yes</td></tr><tr><td>Parent Fields</td><td>If the field should be nested within another list, specify the parent list's name here.</td><td>false</td><td>No</td></tr><tr><td>Condition Field</td><td>If you want to update the field conditionally, specify the field to base the condition on.</td><td>false</td><td>No</td></tr><tr><td>Condition Value</td><td>If a <code>Condition Field</code> is specified, provide the value that should be matched to trigger the update.</td><td>false</td><td>No</td></tr></tbody></table>

## Usage

Let's break this down into specific use-case examples, to show how each of these methods can be used within the `Set Field Value` Transform.

### Input list

Assume that we have a list of objects called `my_list` that looks like this:

```json
my_list: [
  {
    name: "John",
    age: 30,
    hobbies: ["golf", "reading"],
  },
  {
    name: "Mary",
    age: 35,
    hobbies: ["cooking", "music"],
  },
]
```

### Update methods

Using the `New Value Mode` you can define how you want to provide the data for the outputting field. You can do one of two things:

* **Copy From Field:** allows you to copy the value from an existing field
* **Set Value:** provide the literal value you'd like the field to be set to.

Here are some examples of how we can use this action to update or add to our list:

<details>

<summary>Example 1: Create and set new field values</summary>

Add a new field `adult` with value `true` to each object in the list.

**Action Parameters:**

```yaml
field_actions:
 field: adult
 new_value: true
 new_value_mode: set_value
```

**Jinja2 Equivalent:**

```django
{% set _ = item.update({'adult': true}) %}


```

</details>

<details>

<summary>Example 2: Copy value from existing field to new field</summary>

Copy the `age` field to a new field `years` in each object.

**Action Parameters:**

```yaml
field_actions:
 field: years
 new_value: age
 new_value_mode: copy_from_field
```

**Jinja2 Equivalent:**

```django
{% set _ = item.update({'years': item['age']}) %}


```

</details>

<details>

<summary>Example 3: Update fields conditionally based on other fields</summary>

Update the `name` field to `Senior` for any object where `age` is 35.

**Action Parameters:**

```yaml
field_actions:
 field: name
 new_value: "Senior"
 new_value_mode: set_value
 condition_field: age
 condition_value: 35
```

**Jinja2 Equivalent:**

```django
{% if item['age'] == 35 %}
  {% set _ = item.update({'name': 'Senior'}) %}
{% endif %}
```

</details>

### Results output

After all these examples are performed in the transformation, your newly updated list would reflect these changes in their outputted results as such:

```json
results: [
  {
    name: "John",
    age: 30,
    hobbies: ["golf", "reading"],
    adult: true,
    years: 30
  },
  {
    name: "Senior",
    age: 35,
    hobbies: ["cooking", "music"],
    adult: true,
    years: 35
  },
]
```


# Set variable transform action

## Use case

You would like to set a variable for use later in the workflow

## Overview

Set a variable as an action.

This transform will allow you to set a variable using an action vs. setting a data alias in a transition.

The name of the variable will be set via the `Publish Result As` field.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Variable Contents</td><td>The value of the variable you are setting.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example 1: Set a Variable</summary>

Inputs:

**Variable Contents:** I am a test!

</details>

## Results output

Result from Example:

```
I am a test!
```


# Sort transform action

## Use case

You are listing users from Microsoft Graph and you would like to sort the result alphabetically based on their displayName attribute.

## Overview

Given an iterable, return a new sorted list from the items in the iterable.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Attribute</td><td>When sorting a list of dictionaries, an attribute or key to sort by. Can use dot notation like "address.city".</td><td>false</td></tr><tr><td>Case Sensitive</td><td>When sorting strings, sort upper and lower case separately.</td><td>false</td></tr><tr><td>Input List or String</td><td>List or string to sort</td><td>true</td></tr><tr><td>Reverse Sort</td><td>If true, will sort in descending order instead of the ascending order.</td><td>false</td></tr></tbody></table>

{% hint style="info" %}
For nested field names, separate them by dots (e.g., `details.age`).
{% endhint %}

## Usage

<details>

<summary>Example 1: Sort Users By ID</summary>

Inputs:

*Attribute:* age

*Case Sensitive:* false

Input List or String:

```json
[
	{
		"id": 6,
		"name": "Dan6",
		"favorite_letter": "a"
	},
	{
		"id": 2,
		"name": "Dan2",
		"favorite_letter": "c"
	},
	{
		"id": 4,
		"name": "Dan4",
		"favorite_letter": "g"
	},
	{
		"id": 1,
		"name": "Dan1",
		"favorite_letter": "B"
	},
	{
		"id": 3,
		"name": "Dan3",
		"favorite_letter": "z"
	},
	{
		"id": 5,
		"name": "Dan5",
		"favorite_letter": "A"
	}
]
```

*Reverse Sort:* false

</details>

<details>

<summary>Example 2: Sort A List of Numbers</summary>

Inputs:

*Attribute:* age

*Case Sensitive:* false

Input List or String:

```json
[83, 42, 36, 30, 15, 54, 68, 30, 29]
```

*Reverse Sort:* false

</details>

## Results output

Results of example 1:

```json
[
  {
    "id": 1,
    "name": "Dan1",
    "favorite_letter": "B"
  },
  {
    "id": 2,
    "name": "Dan2",
    "favorite_letter": "c"
  },
  {
    "id": 3,
    "name": "Dan3",
    "favorite_letter": "z"
  },
  {
    "id": 4,
    "name": "Dan4",
    "favorite_letter": "g"
  },
  {
    "id": 5,
    "name": "Dan5",
    "favorite_letter": "A"
  },
  {
    "id": 6,
    "name": "Dan6",
    "favorite_letter": "a"
  }
]
```

Results of example 2:

```json
[
  15,
  29,
  30,
  30,
  36,
  42,
  54,
  68,
  83
]
```


# Split text transform action

## Use case

You have a string that you would like to split each word/character by a delimiter to create a list.

## Overview

Splits text on a delimiter into a list of strings.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Max Splits</td><td>The maximum number of splits. If not specified or -1, then there is no limit on the number of splits (all possible splits are made)</td><td>true</td></tr><tr><td>Seperator</td><td>Character or sequence of characters to split on (default is ), such as ' , ',':', etc.</td><td>false</td></tr><tr><td>Text to split</td><td>The string to be split.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Splitting a string to get each word in a sentence or phrase</summary>

Inputs:

**Max Splits:** -1

**Seperator:** (no value was provided so default of space will be used)

**Text to split:** The quick brown fox jumps over the lazy dog

</details>

## Results output

Result of Example:

```json
[
  "The",
  "quick",
  "brown",
  "fox",
  "jumps",
  "over",
  "the",
  "lazy",
  "dog"
]
```


# Transform list objects transform action

Redefine your list structure by reshaping attribute values.

## Use case

You have a list where the current structure isn't effectively supporting your data analysis and transition decision making needs. You want to remap fields, flatten nested items, or count instances within your list to provide more meaningful insights.

## Overview

The `transform list objects` action offers versatile functionality to modify the structure of your list. Whether it's remapping fields for better clarity, flattening for easier data extraction, or counting to reveal data trends, this transform is a strong tool for data restructuring.

## Parameters

<table><thead><tr><th width="177">Parameter</th><th width="451">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>List to Transform</td><td>The list that you would like to restructure.</td><td>true</td></tr><tr><td>Input Field</td><td>The item in the list you would like to transform.</td><td>true</td></tr><tr><td>Transformation Method</td><td>The transformation method to be applied on the input field. (options described below)</td><td>true</td></tr><tr><td>Output Field</td><td>The new field where the transformed value will be stored.</td><td>false</td></tr><tr><td>Append<br>Action Type</td><td>The type of appending action if the method is set to <code>append</code>.</td><td>false</td></tr><tr><td>Append Value</td><td>The value to be added if the <code>Append Action Type</code> is <code>Append Value</code>.</td><td>false</td></tr><tr><td>Append Field</td><td>The field to be joined if the <code>Append Action Type</code> is <code>Append Field</code>.</td><td>false</td></tr><tr><td>Delimiter for Append</td><td>The delimiter to be used in the <code>Append</code> method</td><td>false</td></tr><tr><td>Field for Concatenation</td><td>The field to be used in the concatenation operation if the method is <code>Concatenate</code>.</td><td>false</td></tr></tbody></table>

{% hint style="info" %}
The parameters listed under `Field Actions` are all required. Those listed under `Transformation Parameters` are optional and are needed only when `append` or `concatenate` are selected for the `Transformation Method`.
{% endhint %}

## Usage

Let's break this down into specific use-case examples, to show how each of these methods can be used within the `Restructure Lists` Transform.

### Input list

Assume that we have a list of objects called `my_list` that looks like this:

```django
my_list: [
  {
    name: "John",
    age: 30,
    hobbies: ["golf", "reading"],
    family: [
      { name: "Jane", relation: "sister" },
      { name: "Jim", relation: "brother" },
    ],
  },
  {
    name: "Mary",
    age: 35,
    hobbies: ["cooking", "music"],
    family: [
      { name: "Mike", relation: "husband" },
      { name: "Mia", relation: "daughter" },
    ],
  },
];
```

### Transformation methods

Here is the breakdown of the different transformation methods, and when you'd want to use them:

* **Retain Original Value**: The input field remains unchanged in the output. Ideal when you need to preserve the original data.
* **Append to Existing Value**: The output field shows the original input field value appended with specified values or fields. Perfect when you need to combine data from multiple sources.
* **Count the Number of Elements**: The output field displays the correct count of items in the input list. Use this when you need to know the size of your list.
* **Concatenate Nested Property in List**: The output field shows a string which is a concatenation of the specified field values in the input list.
* **Flatten List of Strings**: If your input list contains sub-lists, this method will return a flattened list with no sub-lists.

Let's use the list we declared to define a set of fields we want to restructure for this action, using the different transformation methods, and show how we can match these to their Jinja2 equivalent.

<details>

<summary>Method 1: Retain Original Value</summary>

This action retains the original value of `name`.

**Action Parameters:**

<pre class="language-yaml"><code class="lang-yaml">field_actions:
<strong> input: name
</strong> method: original
 output: name
</code></pre>

**Jinja2 Equivalent:**

```jinja2
{% set _ = transformed_item.update({'name': item['name']}) %}


```

</details>

<details>

<summary>Method 2: Append to Existing Value</summary>

This action appends the literal string "age" before the actual age, separated by a colon.

**Action Parameters:**

```yaml
field_actions:
 input: age
 method: append
 output: status
 transformation_parameters:
  append_type: append_value
  append_value: 'age'
  delimiter: ':'
```

**Jinja2 Equivalent:**

```jinja2
{% set _ = transformed_item.update({'status': 'age' ~ ':' ~ item['age']}) %}


```

</details>

<details>

<summary>Method 3: Count the Number of Elements</summary>

This action counts the number of items present in the `hobbies` list.

**Action Parameters:**

```yaml
field_actions:
 input: hobbies
 method: count
 output: hobbies_count
```

**Jinja2 Equivalent:**

```jinja2
{% set _ = transformed_item.update({'hobbies_count': item['hobbies']|length}) %}


```

</details>

<details>

<summary>Method 4: Concatenate Nested Property in List</summary>

This action concatenates the `name` field from the `family` list of objects.

**Action Parameters:**

```yaml
field_actions:
 input: family
 method: concatenate
 output: family_names
 transformation_parameters:
  field: name
```

**Jinja2 Equivalent:**

```jinja2
{% set _ = transformed_item.update({'family_names': ', '.join([dep['name'] for dep in item['family']])}) %}


```

</details>

<details>

<summary>Method 5: Flatten List of Strings</summary>

This action flattens the `hobbies` list of strings into a single comma separated string.

**Action Parameters:**

```yaml
field_actions:  
 input: hobbies
 method: flatten
 output: hobbies_flat
```

**Jinja2 Equivalent:**

```jinja2
{% set _ = transformed_item.update({'hobbies_flat': ', '.join(item['hobbies'])}) %}
```

</details>

## Results output

After all these actions are performed, your newly transformed list would output looking like this:

```python
results = [
    {
        'name': 'John',
        'status': 'age:30',
        'hobbies_count': 2,
        'family_names': 'Jane, Jim',
        'hobbies_flat': 'golf, reading'
    },
    {
        'name': 'Mary',
        'status': 'age:35',
        'hobbies_count': 2,
        'family_names': 'Mike, Mia',
        'hobbies_flat': 'cooking, music'
    }
]
```


# Trim variable transform action

## Use case

You have a string that has been grabbed from an API return, however due to bad formatting the string starts or ends with extra spaces that need removed.

## Overview

Trim whitespace characters from a variable.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>Variable Contents</td><td>Variable to trim</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Trimming a string</summary>

**Variable Contents:** This is a test starting and ending with 3 spaces each

</details>

## Results output

Result of Example:

```
"This is a test starting and ending with 3 spaces each"
```

In the above return the `"` characters were kept to show the spaces being removed. These would not be present in the actual return. Only the original string without whitespaces would be returned.


# URL decode transform action

### Use case

You have a string that is URL encoded and you would like to get the original decoded value.

### Overview

When given a URL encoded string, this will decode it.

### Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>String</td><td>String to URL decode.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Decode a string</summary>

Inputs: **String**: This-is-%40-test%21

</details>

## Results output

Results of Example 1:

```
This-is-@-test!
```


# URL encode transform action

## Use case

You are writing query parameters and the API you are sending them to requires them to be URL encoded.

## Overview

When given a string this transform will URL encode it.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>String</td><td>String to URL encode.</td><td>true</td></tr></tbody></table>

## Usage

<details>

<summary>Example: Encode a string</summary>

Inputs: **String**: This-is-\@-test!

</details>

## Results output

```
This-is-%40-test%21
```


# YAML parse transform action

## Use case

An API has returned a YAML formatted string and you would like to convert it to a JSON object.

## Overview

Parses a YAML string and returns the resulting data structure in JSON.

## Parameters

<table><thead><tr><th width="217">Parameter</th><th width="417.3333333333333">Description</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>YAML Input</td><td>The YAML string to parse.</td><td>true</td></tr></tbody></table>

{% hint style="info" %}
This transform is utilizing the yaml\_parse filter, which will only work with one document.

If your YAML string contains multiple documents you should process them individually.
{% endhint %}

## Usage

<details>

<summary>Example: Parse a YAML string</summary>

**YAML input**:

```yaml
version: 2.1

# Define the jobs we want to run for this project
jobs:
  build:
    docker:
      - image: cimg/base:2023.03
    steps:
      - checkout
      - run: echo "this is the build job"
  test:
    docker:
      - image: cimg/base:2023.03
    steps:
      - checkout
      - run: echo "this is the test job"

# Orchestrate our job run sequence
workflows:
  build_and_test:
    jobs:
      - build
      - test
```

</details>

## Results output

```json
{
  "jobs": {
    "test": {
      "steps": [
        "checkout",
        {
          "run": "echo \"this is the test job\""
        }
      ],
      "docker": [
        {
          "image": "cimg/base:2023.03"
        }
      ]
    },
    "build": {
      "steps": [
        "checkout",
        {
          "run": "echo \"this is the build job\""
        }
      ],
      "docker": [
        {
          "image": "cimg/base:2023.03"
        }
      ]
    }
  },
  "version": 2.1,
  "workflows": {
    "build_and_test": {
      "jobs": [
        "build",
        "test"
      ]
    }
  }
}
```


# Workflows actions

## Available workflows actions

The **Workflows** actions accordion menu contains any existing workflows in the workflow list for the related child organization. This actions menu is what powers Rewst's [subworkflow](https://docs.rewst.help/documentation/workflows/different-types-of-workflows#subworkflow) functionality, by letting you reuse existing workflows as individual tasks in a more broadly scoped integration.

The available actions in this submenu will be different for each of your child organizations. Each time you create a new workflow, the list will grow.

<figure><img src="/files/iZFDKRWqVLOPPYgEpTXm" alt="" width="169"><figcaption><p>An example of an org's<br>Workflows action<br>accordion menu</p></figcaption></figure>

Unpacking a Crate will also add the workflows in that Crate to the Workflows actions accordion menu. You'll gain many of the common automations our team has pre-built workflows for, and can use them to build your own custom workflows.

<figure><img src="/files/snMzl8MY2eimYAE60ZBI" alt=""><figcaption><p>The parameters tab of a workflows task</p></figcaption></figure>

Note that most workflows actions will use [input variables](/documentation/automations/workflows/data-input-and-output-input-variables-and-context-variables). If present, these will appear in the **Parameters** tab of the task.


# Subworkflows

A subworkflow is a workflow that is also a part of another workflow. This collection of subworkflows has been pre-built by the Rewst team for your use. For more on subworkflows, see our workflow docs.


# \[PROD - PROCESS] Datto: Get RMM Device Count Loader

This workflow automatically retrieves and compiles device counts across all client sites in Datto RMM, serving as a foundational data-gathering component that can feed into billing automation, asset reporting, or resource allocation workflows. It's particularly valuable for MSPs who need accurate device counts for usage-based billing, license management, or regular client reporting without manual inventory checks. Technically, the workflow calls the Datto RMM API to list all sites, then leverages a specialized task to gather device counts across these sites, making this data available for consumption by other automation processes in your MSP operations.

This workflow contains 5 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **rmm\_user\_count**: List of Datto RMM companies and their counts.

### Key tasks

* **Get\_Datto\_RMM\_Device\_Counts**: Data retrieval
* **datto\_rmm\_list\_sites**: Datto RMM integration: List Sites
* **build automation log**: Logging
* **BEGIN**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{- item().uid -}}
```

Used in input parameter 'site'


# \[PROD - PROCESS] M365: M365 User License Launcher

This workflow serves as a foundational building block that retrieves Microsoft 365 user license information and makes it available for consumption by larger automation processes, functioning as a standardized entry point to license data. MSPs can leverage this component for critical scenarios including license auditing, user onboarding/offboarding processes, license optimization to prevent over-provisioning, and generating automated client billing reports. Technically, the workflow executes by calling the "\[PROD TASK] M365: Get User Licenses" task to fetch license data from Microsoft 365 tenants, presenting structured license information that other workflows can consume for decision-making and automation tasks.

This workflow contains 4 tasks.

### Inputs

* **company\_id** - string; This would be a Microsoft Entra tenant ID.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **license\_counts**: List of Rewst orgs and their license counts in Office 365.

### Key tasks

* **BEGIN**: Core integration: noop
* **workflows\_365\_get\_users**: Data retrieval
* **Create Automation Log**: Creation/initialisation

### Jinja examples

#### Example 1

```jinja
{{ CTX.company_id |d }}
```

Example for input parameter 'company\_id'

#### Example 2

```jinja
{{ RESULT.license_counts }}
```

Used in publishing 'license\_counts'


# \[PROD - TASK] Auvik: Get Counts

This workflow serves as a foundational building block that retrieves and quantifies all network devices tracked in Auvik across your client base, providing essential inventory metrics that can be leveraged in reporting, billing automation, or compliance verification processes. For MSPs, this function delivers critical visibility when performing quarterly business reviews, validating managed device counts against service agreements, or identifying growth opportunities within existing clients' networks. Technically, the workflow first retrieves all tenant details from Auvik, then calls a device listing task for each tenant, and finally merges these device counts with company information to produce comprehensive device statistics by client - all accessible via API for integration with your PSA, documentation system, or custom reporting tools.

This workflow contains 7 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **auvik\_user\_count**: List of auvik companies and their counts.

### Key tasks

* **workflows\_dev\_task\_auvik\_list\_devices**: Workflows integration: \[DEV TASK] Auvik: List Devices
* **BEGIN**: Core integration: noop
* **build automation log**: Logging
* **merge\_counts\_with\_company**: Core integration: noop
* **auvik\_list\_tenants\_detail**: Auvik integration: List Tenants Detail

### Jinja examples

#### Example 1

```jinja
{{ item().id }}
```

Used in input parameter 'id'


# \[PROD - TASK] CWA: Get Counts

This workflow serves as a fundamental building block that queries ConnectWise Automate to retrieve company and computer counts, providing essential inventory data that can be consumed by larger automation processes for reporting, billing, or compliance purposes. MSPs will find this function valuable for client onboarding/offboarding validation, license reconciliation, automated billing workflows, and generating executive dashboards showing managed device statistics across their client base. Technically, the workflow executes by first retrieving the complete list of companies from CWA, then obtaining all managed computers, calculating the relevant counts, and presenting the data in a standardized format that other workflows can easily reference when making automation decisions or populating reports.

This workflow contains 7 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

**cwa\_counts**: This output will contain a list of companies from Automate along with their counts.

### Key tasks

* **connect\_wise\_automate\_list\_companies**: ConnectWise Automate integration: List Companies
* **connect\_wise\_automate\_list\_computers**: Calculation
* **build automation log**: Logging
* **calculate\_final\_count**: Calculation
* **handle failure actions**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{ [ { "company": company.Name, "id": company.Id } for company in CTX.companies ] }}
```

**Task: connect\_wise\_automate\_list\_companies**

This expression creates a formatted list of company data by iterating through all companies available in the ConnectWise Automate integration. It extracts each company's name and ID, transforming them into a structured JSON array that can be easily consumed by other workflow steps or displayed in a dashboard.

The expression accesses the `CTX.companies` object provided by Rewst's ConnectWise Automate integration, which contains all the company records with their properties like Name and Id. MSPs can modify this to include additional company properties by adding more key-value pairs to the dictionary such as `\"location\": company.Location` or `\"contact\": company.PrimaryContact`.


# \[PROD - TASK] Datto PSA: Create Ticket

This workflow functions as a reusable building block that creates tickets in Datto Autotask PSA with proper contact association, enabling MSPs to programmatically generate standardized tickets across various automation scenarios. It's particularly valuable for integrating monitoring alerts with ticket creation, automating customer request handling, standardizing ticket generation across technicians, and incorporating ticket creation into complex workflows like onboarding/offboarding processes. Technically, the workflow first validates contact information by searching Datto PSA's contact database, then creates a properly formatted ticket with all required fields and associations, making it a reliable foundation for any automation that requires ticket generation within your PSA.

This workflow contains 8 tasks.

### Inputs

* **board** - string
* **summary** - string
* **company\_id** - string
* **contact\_id** - string
* **category\_one** - string
* **category\_two** - string
* **category\_four** - string
* **child\_company** - string
* **contact\_email** - string
* **category\_three** - string
* **ticket\_item\_id** - string
* **ticket\_type\_id** - string
* **ticket\_priority** - string
* **ticket\_subtype\_id** - string
* **initial\_description** - string
* **default\_status\_override** - string

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **success**: Boolean; States if workflow was successful.
* **ticket\_id**: Returns the ticket ID of the created ticket.
* **ticket\_data**: Return the ticket object of the created ticket.

### Key tasks

* **BEGIN**: Core integration: noop
* **create\_ticket**: Creation/initialisation
* **format\_output**: Core integration: noop
* **failed**: Core integration: noop
* **find\_contact\_id**: Datto Autotask PSA integration: List Contacts by Search v2

### Jinja examples

#### Example 1

```jinja
{{ (CTX.child_company|d) or (CTX.company_id|d) or (ORG.VARIABLES.datto_company_id|d) }}
```

Task: set\_variables | Context: Used in publishing 'company\_id'

#### Example 2

```jinja
{ - CTX.ticket_type_id|d or ORG.VARIABLES.psa_datto_default_issue_type | d or ORG.VARIABLES.psa_new_user_ticket_type | d - }
```

Task: set\_variables | Context: Used in publishing 'issue\_type\_id'


# \[PROD - TASK] Duo: Get User Counts

This workflow queries Duo Security to retrieve a comprehensive count of users across all client accounts, serving as a critical building block for MSPs to automate billing, license management, and security compliance reporting. It's particularly valuable for MSPs who bill per user, need to verify MFA deployment completeness, or must generate regular security compliance documentation for clients requiring multi-factor authentication. Technically, the workflow functions by first listing all Duo accounts, then retrieving all users from the Duo platform, and finally merging this data to generate accurate user counts that can feed into reporting systems, PSA tools, or client-facing dashboards.

This workflow contains 7 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **duo\_user\_count**: List of DUO companies and their counts.

### Key tasks

* **build automation log**: Logging
* **get\_user\_count**: Data retrieval
* **duo\_list\_accounts**: Duo integration: List Accounts
* **duo\_list\_users**: Duo integration: List Users
* **BEGIN**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{ CTX.accounts.response }}
```

Used in setting the duo\_accounts alias.


# \[PROD - TASK] Huntress: Get License Counts

This workflow queries the Huntress security platform to retrieve and compile license usage data across all client organizations, serving as a critical building block for license management, billing reconciliation, and capacity planning automations. For MSPs, this function provides essential visibility for client billing accuracy, license compliance tracking, and identifying opportunities to optimize security coverage across the client base. Technically, the workflow first authenticates with Huntress, then retrieves the complete list of managed organizations, calculates agent deployment counts per organization, and compiles this data for integration with other systems like PSAs for billing or reporting tools for client reviews. This data can be particularly valuable when integrated with onboarding/offboarding workflows or when preparing for quarterly business reviews to assess security tool adoption and coverage gaps.

This workflow contains 6 tasks.

### Inputs

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **huntress\_count**: List of Huntress companies and their counts.

### Key tasks

* **huntress\_list\_organizations**: Huntress integration: List Organizations
* **get\_huntress\_agent\_count**: Data retrieval
* **build automation log**: Logging
* **BEGIN**: Core integration: noop
* **action\_error**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{ [ { "company": org.name |d, "count": org.agents_count |d, "company_id": org.id |d } for org in CTX.huntress_orgs ] }}
```

This expression creates a structured list of all client organizations with their Huntress agent deployment statistics. It iterates through each organization in your Huntress integration (`CTX.huntress_orgs`), extracting the company name, agent count, and company ID into a list of dictionaries, with the `|d` filter providing empty string defaults for any missing values.


# \[PROD - TASK] Immybot: Get User Count

This workflow retrieves the total count of devices managed in ImmyBot, serving as a critical data-gathering building block that can feed into larger workflows for billing, license management, or resource planning automations. It's particularly valuable for MSPs needing to automate client billing based on device count, reconcile asset inventory across platforms, or trigger conditional processes based on current managed device thresholds. Technically, the workflow executes an API call to ImmyBot using the "list\_computers" action, processes the returned device data, and makes the count available for downstream automation consumption - creating a simple yet powerful integration point between ImmyBot and your broader automation ecosystem.

This workflow contains 6 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **immy\_counts**: List of ImmyBot companies and their counts.

### Key tasks

* **BEGIN**: Core integration: noop
* **get\_device\_count**: Data retrieval
* **immy\_bot\_list\_computers**: Calculation
* **build automation log**: Logging
* **action\_error**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{ [ { "company": item, "company_id": [device.company_id for device in CTX.listed_immy_devices if device.company_name == item] | first |d, "count": [device for device in CTX.listed_immy_devices if device.company_name == item] | length } for item in company_list ] }}
```

This expression creates a structured report of device counts by company, iterating through a list of companies and counting matching Immybot devices for each. It's accessing company names from `company_list` and device data from `CTX.listed_immy_devices`, using list comprehensions and filters to match devices to their respective companies.


# \[PROD - TASK] MyGlue: Get License Counts

This workflow automatically pulls organization and user data from IT Glue, matches users to their respective organizations, and calculates license utilization across client sites - serving as a foundational building block for license management, billing verification, and capacity planning automations. MSPs will find this particularly valuable for reconciling monthly MyGlue license billing, identifying underutilized licenses for reassignment, preparing client reviews with accurate license metrics, and ensuring compliance with license agreements. Technically, the workflow functions by retrieving a comprehensive list of organizations and users from IT Glue's API, processing this data to match users with their organizations, calculating per-site license counts, and then producing a structured output that can feed into reporting tools, PSA systems, or other automated processes.

This workflow contains 8 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **glue\_counts**: List of ITGlue companies and their counts.

### Key tasks

* **it\_glue\_list\_organizations**: IT Glue integration: List Organizations
* **it\_glue\_list\_users**: IT Glue integration: List Users
* **BEGIN**: Core integration: noop
* **calculate\_site\_counts**: Calculation
* **match\_users\_to\_org**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{ [ org for org in CTX.glue_orgs if org.attributes['my-glue-account-id'] ] }}
```

Creates a list of organizations that have the attribute my-glue-account-id populated.


# \[PROD - TASK] Ninja: Get Device Counts

This workflow functions as a data-gathering utility that connects to NinjaRMM, retrieves all managed organizations, and calculates the total count of workstations and servers for each client. As a building block, it provides standardized device inventory data that can be consumed by other workflows for billing automation, client reporting, compliance verification, and device management processes. The workflow executes in three main technical steps: first retrieving the organization list from NinjaRMM, then making separate API calls to collect workstation and server device lists, and finally calculating the per-organization device counts for consumption by other systems. MSPs will find this particularly valuable for usage-based billing automation, reconciling device counts against agreements, generating executive reports for clients, and tracking environment growth trends across their client base.

This workflow contains 8 tasks.

### Inputs

This sub workflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **ninja\_device\_counts**: List of Ninja RMM companies and their counts.

### Key tasks

* **BEGIN**: Core integration: noop
* **ninja\_rmm\_list\_organizations**: NinjaRMM integration: List Organizations
* **list\_workstations**: NinjaRMM integration: List Devices
* **list\_servers**: NinjaRMM integration: List Devices
* **calculate\_org\_device\_counts**: Calculation

### Jinja examples

#### Example 1

```jinja
{{ [ { "company": org.name, "company_id": org.id, "workstation_count": [item for item in CTX.ninja_workstations if item.organizationId == org.id] | length, "server_count":[item for item in CTX.ninja_servers if item.organizationId == org.id] | length, "network_device_count": [item for item in CTX.ninja_network_devices if item.organizationId == org.id] | length, } for org in CTX.ninja_orgs ] }}
```

This expression creates a detailed inventory report by iterating through all organizations in NinjaRMM and counting their workstations, servers, and network devices. It accesses NinjaRMM data stored in the CTX variable (context), filtering devices by organization ID to generate accurate device counts for each client.


# \[PROD - TASK] Proofpoint: Get Counts

This workflow is a core building block that pulls organization count data from Proofpoint’s email security platform. It allows MSPs to programmatically access client protection metrics and use them in larger automations like reporting and security audits. It’s especially useful for MSPs managing multiple clients, supporting use cases such as automated security reporting, license verification, and spotting gaps in protection across environments.

Technically, the workflow connects to the Proofpoint API, uses the `proofpoint.get_organization` action to list sub-organizations for a domain, then processes the results to extract the needed count data with built-in error handling for reliability. This removes the need for manual data collection and can feed directly into client reports, RMM dashboards, or PSA ticketing systems to support consistent email security monitoring across all managed clients.

This workflow contains 7 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **proofpoint\_user\_count**: List of ProofPoint companies and their counts.

### Key tasks

* **handle failure actions**: Core integration: noop
* **Get Proofpoint Counts**: Data retrieval
* **build automation log**: Logging
* **proof\_point\_list\_organizations**: ProofPoint integration: List Organizations
* **BEGIN**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{ [ { "company": org.name, "active_users": org.active_users, "count": org.user_licenses, "company_id": org.primary_domain } for org in CTX.proofpoint_orgs ] }}
```

This Jinja expression creates a formatted list of dictionaries containing Proofpoint license information for each managed organization. It accesses the `proofpoint_orgs` data from the context (CTX) object and extracts key metrics like organization name, active user count, license count, and primary domain for reporting or further processing.


# \[PROD - TASK] Pax8: Get License Counts

This workflow acts as a powerful building block that queries the Pax8 platform to retrieve comprehensive license counts across all client companies, providing essential data for license management, billing verification, and reporting workflows. By connecting to Pax8's API to list companies, gather product information, and enumerate active subscriptions, the workflow delivers accurate license quantity data that MSPs can leverage to identify unused licenses, verify billing accuracy, or trigger procurement processes. MSPs can integrate this into larger automation sequences that generate client-facing license reports, reconcile billing data between Pax8 and their PSA, or build automatic notifications when licenses need attention. The technical implementation is straightforward yet powerful - listing managed companies in Pax8, retrieving product details, and collecting subscription information to create a complete picture of license utilization across the entire client base.

This workflow contains 7 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **subscription\_name\_and\_quantity**: List of Pax8 companies and their counts.

### Key tasks

* **BEGIN**: Core integration: noop
* **handle failure actions**: Core integration: noop
* **pax\_8\_get\_product**: Data retrieval
* **pax\_8\_list\_companies**: Pax8 integration: List Companies
* **pax\_8\_list\_subscriptions**: Pax8 integration: List Subscriptions

### Jinja examples

#### Example 1

```jinja
{{ CTX.subscription_data }}
```

Used in publishing 'subscription\_name\_and\_quantity'


# \[PROD - TASK] Rewst: Get All Integration Ids

This utility workflow collects all integration IDs from your Rewst instance, mapping organizations to their connected systems and Microsoft tenant IDs, serving as a fundamental building block for other automation workflows that need to interact with your integrated PSA, RMM, or Microsoft 365 environments. It's particularly valuable for MSPs when creating cross-platform automation workflows, conducting integration audits, or troubleshooting connection issues where accurate integration identifiers are required. Technically, the workflow retrieves all organizations in your Rewst instance, lists the integrations for each organization, collects relevant organization variables, and specifically identifies Microsoft tenant IDs—creating a comprehensive integration mapping that other workflows can reference when executing actions against specific client environments.

This workflow contains 6 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **all\_integration\_ids**: Outputs a list of organizations, the organization object includes org info and their integration mappings.

### Key tasks

* **rewst\_list\_organizations**: Rewst integration: List Organizations
* **rewst\_list\_integrations\_for\_organization**: Rewst integration: List Integrations For Organization
* **rewst\_list\_organization\_variables**: Rewst integration: List Organization Variables
* **BEGIN**: Core integration: noop
* **workflows\_get\_ms\_tenant\_ids**: Data retrieval

### Jinja examples

#### Example 1

```jinja
{{ [org.id for org in CTX.all_orgs if org.is_enabled == true] + [ORG.ATTRIBUTES.id] }}
```

This expression creates a list of all enabled organization IDs across your MSP environment, plus the current organization's ID. It accesses the `CTX.all_orgs` collection to gather all enabled organizations (`org.is_enabled == true`) and adds the current organization ID (`ORG.ATTRIBUTES.id`) to ensure it's included regardless of its enabled status.

### Expression 2

#### Example 2

```jinja
{{ [ config.id for pack in CTX.packs for config in pack.pack_configs if config.default == true and \"csp\" in pack.name|lower ] | first or None }}
```

This expression finds the first default configuration ID for any integration pack containing "csp" in its name (cloud service provider), returning None if none exists. It performs a nested loop through integration packs and their configurations, filtering for default configurations within CSP-related integration packs.


# \[PROD - TASK] Rewst: Send Email with Attachment

This workflow provides a reliable method for sending emails with attachments through Rewst, functioning as a critical communication component that can be called from other automations to deliver documents, reports, or files to clients or team members. MSPs can leverage this building block to automate client communications for service completion notifications, scheduled security reports, license renewals, or documentation delivery—all with proper attachments and consistent branding. Technically, the workflow accepts inputs including recipient addresses, subject, body content, and attachment details, then determines whether to send via standard email or through Microsoft Graph (allowing for user impersonation), with built-in error handling for failed deliveries or missing user accounts. This reusable component eliminates the need to rebuild email functionality in every workflow, allowing MSPs to standardize client communications while focusing on building more complex automation processes.

This workflow contains 13 tasks.

### Inputs

* **send\_to** - array (Required)
  * Default: `{{ [ ] }}`
* **subject** - string
* **send\_as\_guid** - string (Required)
* **use\_failover** - boolean
  * Default: `{{ true }}`
* **attachment\_name** - string
* **attachment\_type** - string
* **encoded\_contents** - string
* **message\_contents** - string
* **no\_failover\_attachment** - boolean
  * Default: `{{ false }}`

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **output**: Outputs a dictionary object with a key for success, the value for success is a boolean value indicating whether the workflow was successful or not.

### Key tasks

* **check\_sendas\_field**: Communication/notification
* **Send\_Email**: Communication/notification
* **core\_sendmail**: Communication/notification
* **microsoft\_graph\_get\_user**: Data retrieval
* **user\_not\_found**: Core integration: noop

### Jinja examples

#### Example 1

```jinja
{{ CTX.subject|d }}
```

Used in input parameter 'subject'


# \[PROD - TASK] SentinelOne: Get License Counts

This workflow acts as a critical building block by querying the SentinelOne platform to retrieve client site information, enabling MSPs to effectively track and manage endpoint security licenses across multiple clients. It delivers essential visibility into license distribution and utilization, which directly supports compliance management, client billing accuracy, and renewal planning for cybersecurity services. The workflow functions by connecting to the SentinelOne API, retrieving a comprehensive list of all managed client sites, and preparing this data for license count analysis in subsequent automation processes. MSPs managing multiple SentinelOne deployments can leverage this automation to eliminate manual license auditing processes, proactively identify licensing gaps, and generate accurate reports for both internal operations and client discussions.

This workflow contains 5 tasks.

### Inputs

This subworkflow has no inputs.

### Outputs

* **automation\_log**: Standardized Rewst automation log
* **sentinel\_counts**: List of SentinelOne companies and their counts.

### Key tasks

* **sentinel\_one\_list\_sites**: SentinelOne integration: List Sites
* **Begin**: Core integration: noop
* **build automation log**: Logging

### Jinja examples

#### Example 1

```jinja
{{ [ { "company": site.name, "count": site.activeLicenses, "sku": site.sku, "company_id": site.id |d } for site in CTX.all_sites ] }}
```


# \[Rewst Master v2] PSA-Datto: List Ticket Subtypes

This workflow retrieves all available ticket subtypes from Datto Autotask PSA, serving as a critical reference component for any automation that needs to create, route, or categorize tickets programmatically. MSPs will find this building block invaluable when developing automated ticket creation from RMM alerts, implementing intelligent ticket routing based on issue type, or synchronizing ticket classifications between different platforms. Technically, it executes a simple query to the Datto PSA API that returns all defined ticket subtypes and their associated picklist values, making these values available as variables for other workflows. This standardized method for accessing ticket classification data ensures that downstream automations always use valid subtype values, preventing errors when integrating with the PSA.

This workflow contains 1 task.

### Inputs

* **ticket\_type** - string
* **choose\_variable** - string

### Outputs

* **options**: Array of ticket subtype objects.

### Key tasks

* **list\_ticket\_subtypes**: Datto Autotask PSA integration: List Ticket Fields with Picklists

### Jinja example

```jinja
{%- set all_subissues = [] -%}

{%- for item in CTX.list_all_types -%}

{%- if CTX.ticket_type|d == item.type_id|d -%}

{%- set is_default = item.value|d == ORG.VARIABLES[CTX.choose_variable]|d -%}

{%- set _ = all_subissues.append({"label":item.subType_name, "id":item.subType_id, "default":is_default}) -%}

{% endif %}

{%- endfor -%}

{{- all_subissues -}}
```

This is used in publishing the ticket\_subtypes data alias.


# \[Rewst Master v2] PSA-Halo: Get Agents

This workflow serves as a fundamental data retrieval building block that pulls a complete list of technicians/agents from Halo PSA, providing essential personnel data that can be utilized in more complex automation sequences. MSPs would find this function valuable when building ticket assignment workflows, creating technician availability reports, implementing skill-based routing, or developing any automation that requires filtering or assigning work based on agent attributes. Technically, the workflow executes a straightforward API call to Halo PSA that retrieves all agent records, returning them as a structured array that other workflows can filter, iterate through, or use for decision-making processes without requiring administrators to manually extract this information each time it's needed.

This workflow contains 1 task.

### Inputs

* **choose\_variable** - string

### Outputs

* **options**: Array of agent objects.

### Key tasks

* **list\_agents**: HaloPSA integration: List Agents

### Jinja examples

#### Example 1

```jinja
{{ [{"id": agents.id, "label": agents.name, "default": true if agents.id == ORG.VARIABLES[CTX.choose_variable]|d|int else false} for agents in TASKS.list_agents.result.result] }}
```


# \[Rewst Master v2] PSA-Datto: Get Company Classification

This workflow retrieves all available company classification types from Datto Autotask PSA, serving as a foundational building block for more complex automation processes that need to categorize or filter clients. MSPs would find this function valuable when automating client onboarding workflows, implementing classification-based automation rules, or synchronizing client categorization between systems. Technically, the workflow executes a single API call to Datto PSA using the "companies\_query\_field\_definitions" action, which returns the standardized classification options configured in your PSA that can then be used in dropdown menus or conditional logic within other workflows. This reusable component eliminates the need to hardcode classification values, ensuring your automations remain current even when PSA configurations change.

This workflow contains 1 task.

### Inputs

* **choose\_variable** - string

### Outputs

* **options**: Array of company classifications.

### Key tasks

* **get\_company\_classifications**: Data retrieval

### Jinja example

```jinja
{%- set all_classifications = [] -%}

{%- for item in RESULT.result.fields -%}
  {% if item.isPickList == true and item.name == "classification" %}
    {%- set tmp = item.picklistValues | list -%}
    {% for classifications in tmp %}
      {%- set is_default = classifications.value|string in ORG.VARIABLES[CTX.choose_variable]|d -%}
      {%- set tmp2 = all_classifications.append({"name": classifications.label, "id": classifications.value, "default": is_default}) -%}
    {% endfor %}
  {% else %}
  {% endif %}
{% endfor %}

{{- all_classifications | list -}}

```

This is used in publishing 'all\_classifications'


# \[Rewst Master v2] PSA-Datto: Get Company Status

This workflow pulls all company status values from Datto PSA with a single API call, making it a key reference point for automations that depend on client status. MSPs can use it to filter clients, trigger conditional actions, or validate status fields before updates. By returning standardized status options, it avoids hardcoding and keeps automations flexible, even when custom statuses are added, ensuring reliable, status-aware workflows across your PSA environment.

This workflow contains 1 task.

### Inputs

* **choose\_variable** - string

### Outputs

* **options**: Array of company statuses.

### Key tasks

* **get\_company\_statuses**: Data retrieval

### Jinja example

```jinja
{%- set all_company_statuses = [] -%}

{%- for item in RESULT.result.fields -%}
  {% if item.isPickList == true and item.name == "companyType" %}
    {%- set tmp = item.picklistValues | list -%}
    {% for companystatuses in tmp %}
      {%- set is_default = companystatuses.value|string in ORG.VARIABLES[CTX.choose_variable]|d -%}
      {%- set tmp2 = all_company_statuses.append({"name": companystatuses.label, "id": companystatuses.value, "default": is_default}) -%}
    {% endfor %}
  {% else %}
  {% endif %}
{% endfor %}

{{- all_company_statuses | list -}}

```

This is used in publishing all\_company\_statuses


# \[Rewst Master v2] PSA-Datto: Get Priorities

This workflow retrieves the standardized list of ticket priorities from Datto Autotask PSA, serving as a fundamental building block that other automations can leverage when creating, updating, or processing tickets. MSPs will find this function valuable when building ticket creation workflows with conditional priority assignment, implementing SLA-based escalation processes, or ensuring consistent priority values across integration points with other tools. Technically, the workflow executes a single API call to Datto Autotask PSA using the "List Ticket Fields with Picklists" action, retrieving the current priority options configured in your PSA. By centralizing this function, MSPs can maintain consistent priority handling across their entire automation ecosystem while easily adapting if priority configurations change in Autotask.

This workflow contains 1 task.

### Inputs

* **choose\_variable** - string

### Outputs

* **options**: Array of priorities.

### Key tasks

* **get\_priorities**: Data retrieval

### Jinja example

```jinja
{%- set all_priorities = [] -%}

{%- for item in RESULT.result.fields -%}
  {% if item.isPickList == true and item.name == "priority" %}
    {%- set tmp = item.picklistValues | list -%}
    {% for priority in tmp %}
      {%- set is_default = priority.value|int == ORG.VARIABLES[CTX.choose_variable]|d|int -%}
      {%- set tmp2 = all_priorities.append({"name": priority.label, "id": priority.value, "default": is_default}) -%}
    {% endfor %}
  {% else %}
  {% endif %}
{% endfor %}

{{- all_priorities | list -}}
```

This is used in publishing the all\_priorities data alias.


# \[Rewst Master v2] PSA-Datto: Get Queues

This workflow retrieves queue information from Datto PSA, serving as a critical building block for more complex ticket routing and management automations. MSPs can leverage this function when implementing automated ticket assignment processes, workload balancing between teams, or creating custom reporting dashboards that provide visibility into queue status and performance. Technically, the workflow executes a simple API call to Datto PSA's resource role queues endpoint, retrieving the field definitions and structure of available queues, which other workflows can then consume to make intelligent routing decisions or gather queue metrics for service delivery improvements.

This workflow contains 1 task.

### Inputs

* **choose\_variable** - string

### Outputs

* **options**: Array of queues.

### Key tasks

* **datto\_psa\_resource\_role\_queues\_query\_field\_definitions**: Datto Autotask PSA integration: resource\_role\_queues\_query\_field\_definitions

### Jinja Example

```jinja
{%- set all_queues = [] -%}

{%- for item in RESULT.result.fields -%}
  {% if item.isPickList == true %}
    {%- set tmp = item.picklistValues | list -%}
    {% for queues in tmp %}
      {%- set is_default = queues.value|int == ORG.VARIABLES[CTX.choose_variable]|d|int -%}
      {%- set tmp2 = all_queues.append({"name": queues.label, "id": queues.value, "default": is_default}) -%}
    {% endfor %}
  {% else %}
  {% endif %}
{% endfor %}

{{- all_queues | list -}}

```

This is used to populate the queues data alias.




---

[Next Page](/llms-full.txt/1)

