> For the complete documentation index, see [llms.txt](https://docs.harmony.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.harmony.io/workflows-and-automation/building-and-managing-workflows.md).

# Building and Managing Workflows

{% hint style="info" %}
**Path:** `/workflows`
{% endhint %}

### Understanding Workflow Automation

Workflow automation lets you create custom workflows that run automatically based on triggers (manual, scheduled, events, or inbound webhooks) and execute a sequence of steps. Workflows can integrate with Slack, Teams, Okta, HRIS systems, MDM tools, ServiceNow, GitHub, Jira, and Harmony itself.

#### Understanding the Workflow Builder

The Workflow Builder is a visual editor where you design workflows by adding nodes and connecting them. Open **Workflows** from the sidebar, then create a new workflow or open an existing one. The builder shows a canvas with a trigger node at the top and action/logic nodes below.

#### Understanding the Workflow Canvas

The canvas is a drag-and-drop area where workflow nodes are laid out. Nodes connect via edges (lines). Use the zoom controls (bottom-left) to zoom and pan. Right-click on the canvas or on nodes to open context menus. Use Shift+drag to select multiple nodes. The canvas snaps nodes to a grid. The canvas clips cleanly to rounded corners that match the surrounding content card, so the builder looks consistent throughout.

#### Navigating the Workflows List

Open **Workflows** at `/workflows` to see all custom workflows. Each card shows the workflow name, description, enabled state, and toggle. Click a workflow to edit it. Click **Create Workflow** to start a new one (when the Workflow Builder feature is enabled).

#### Creating Your First Workflow

1. Click **Create Workflow** on the Workflows page.
2. You're taken to the builder with a default **Manual** trigger.
3. Click the **+** handle below the trigger (or drag from it) to add a step.
4. Choose an action (e.g., Slack, Okta, Harmony) and an operation.
5. Configure the step in the Properties panel.
6. Add more steps as needed.
7. Save and enable the workflow.

***

### Building Workflows

#### Adding Workflow Nodes

* **From the trigger:** Click the **+** handle at the bottom of the trigger node, or drag from it. A step selector appears; pick a category (Slack, Okta, Harmony, etc.) and an operation.
* **From an existing step:** Drag from the output handle of a step to create a connection. Drop on the canvas to add a new step, or drop on another step's input handle to connect.
* **Context menu:** Right-click the canvas to add a step at that position.

#### Connecting Workflow Steps

Drag from a step's output handle (bottom) to another step's input handle (top) to connect them. Connections define execution order. You can insert a new step into an existing connection by dropping the new step onto the edge.

#### Understanding Node Types

| Type        | Description                                                                                                 |
| ----------- | ----------------------------------------------------------------------------------------------------------- |
| **Trigger** | Starts the workflow. One per workflow. Types: Manual, Scheduled, Event, Webhook.                            |
| **Action**  | Performs an operation (Slack message, Okta request, create ticket, etc.).                                   |
| **Logic**   | Condition (if/else), Sleep (wait), or For Each (iterate over a list). Branches, delays, or loops execution. |

***

### Understanding Workflow Triggers

#### Using Manual Triggers

The default trigger. The workflow runs only when executed manually (from the toolbar **Run** button). You can define workflow inputs (e.g., employee ID, ticket ID) that users provide when running.

#### Using Scheduled Triggers

Runs the workflow on a schedule. In the trigger configuration, select **Scheduled** and set:

* **Cron expression** - Standard cron format (e.g., `0 9 * * 1-5` for 9:00 AM weekdays).
* **Timezone** - Timezone for the schedule (e.g., America/New\_York).

#### Using Event Triggers

Runs when a specific event occurs. Select **Event** and choose an event type:

| Event                     | Description                           |
| ------------------------- | ------------------------------------- |
| **Ticket Created**        | When a new ticket is created.         |
| **Ticket Assigned**       | When a ticket is assigned to someone. |
| **Ticket Status Changed** | When a ticket's status changes.       |
| **Ticket Resolved**       | When a ticket is marked as resolved.  |

When you select an event trigger, the condition builder shows a dropdown of valid fields specific to that event type. Typing `{{ trigger.` in any step input surfaces an autocomplete list of available fields, so you always know exactly which fields are available without guessing.

Available fields by event type:

* **Ticket Created** - ticket ID, title, priority, status, reporter, and desk
* **Ticket Status Changed** - fields reflecting the previous and new status, plus ticket metadata

#### Using Webhook Triggers

Runs when an external system sends an HTTP request to a unique webhook URL generated for the workflow. When you save a workflow with a webhook trigger, the URL is created automatically and is ready to use immediately.

The full request body is passed into your workflow as `{{ trigger.* }}` data, so every field sent by the external system is available in downstream steps.

**Authentication options:**

| Method               | Description                                          |
| -------------------- | ---------------------------------------------------- |
| **API key (header)** | Include a pre-shared key in a request header.        |
| **HMAC signature**   | Validate request authenticity using a shared secret. |
| **Bearer token**     | Standard Authorization header with a bearer token.   |

You can retrieve the webhook URL at any time using `GET /workflows/{id}/webhook-url`.

#### Configuring Trigger Conditions

For event triggers, you can add conditions to filter when the workflow runs (e.g., only for certain desks, statuses, or types). Use the conditions section in the trigger configuration.

***

### Using Workflow Actions

#### Understanding Action Blocks

Action blocks are steps that call an external system or Harmony. Each block has a schema-driven configuration form with inputs. Many inputs support template variables to pass data from previous steps or the trigger. Integration identifiers are surfaced on blocks so you can precisely target the right connection, and the integration selector dropdown shows the friendly name you assigned to each integration rather than internal system identifiers.

#### Integration Actions

| Category            | Examples                                                                                                                                                                                      |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Slack**           | Send message, update message, add/remove reaction, get thread replies.                                                                                                                        |
| **Microsoft Teams** | Send message, update message, get thread replies.                                                                                                                                             |
| **Okta**            | Get user, list groups, add/remove user from group, reset password, provision access, terminate sessions, deactivate user, unlock user, retrieve recovery email, add/remove users from groups. |
| **HiBob**           | Get/create/update employee, list departments/jobs/employees.                                                                                                                                  |
| **Workday**         | Get/create/update employee, list departments/jobs/employees.                                                                                                                                  |
| **BambooHR**        | Get/create/update employee, list departments/jobs/employees.                                                                                                                                  |
| **ServiceNow**      | Run Flow, Create Ticket (incident/request), Create Service Request, discover available flows.                                                                                                 |
| **GitHub**          | Search users, retrieve SAML identities, list org teams and repo collaborators, add/remove team members.                                                                                       |
| **Jira / JSM**      | Look up issues, manage projects and service management requests.                                                                                                                              |

#### HTTP Actions

Use the **HTTP** block to make HTTP requests to any API. Configure URL, method, headers, and body. Supports template variables in the request.

#### MDM Actions

| MDM        | Examples                                  |
| ---------- | ----------------------------------------- |
| **Kandji** | Get device, list devices, custom request. |
| **Jamf**   | Get device, list devices, custom request. |
| **Intune** | Get device, list devices, custom request. |

#### Identity Provider Actions

| IdP                                | Examples                                                                                                                                                                         |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Okta**                           | Get user, list groups, add/remove users from groups (accepts a list of employee IDs), unlock user, terminate sessions, retrieve recovery email, reset password, deactivate user. |
| **Microsoft Entra**                | Get user, list groups, add/remove users from groups, reset password, terminate sessions, deactivate user, unlock user, retrieve recovery email.                                  |
| **Google Workspace**               | Get user, list groups, add/remove users from groups, terminate sessions, unlock user, retrieve recovery email, custom request.                                                   |
| **JumpCloud**                      | List groups, add/remove users from groups, reset password, deactivate user, unlock user, terminate sessions, custom request.                                                     |
| **Active Directory (on-premises)** | Unlock user accounts and additional identity management operations.                                                                                                              |

Group membership actions accept a list of employee IDs so you can add or remove multiple users in a single step. The action formerly called "Add to Groups" is now named **Add Users to Groups**.

#### AI Actions

Use the **AI** block to analyze content or generate responses. Useful for automated triage, summarization, or classification.

#### OTP Verification Actions

Use the **OTP Verification** blocks to add secure one-time password identity checks to your workflows. The flow is handled end-to-end: a code is generated, delivered to the employee by email, and they are prompted to submit it via a Slack or Microsoft Teams form - all within the workflow itself.

Sensitive values such as OTP codes and temporary passwords are encrypted at rest and are never exposed in plain text in workflow history, API responses, or step outputs.

#### Harmony Actions

| Action                        | Description                                                                                                                          |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Approval**                  | Pause for human approval before continuing.                                                                                          |
| **Create Ticket**             | Create a Harmony ticket.                                                                                                             |
| **Get/Update Ticket**         | Fetch or update a ticket.                                                                                                            |
| **List Tickets**              | List tickets with filters.                                                                                                           |
| **Get Employee**              | Fetch employee data by ID or email address.                                                                                          |
| **List Employees**            | List employees, with filters for VIP status, employment status, location, and employment start date range (all applied server-side). |
| **Get Devices**               | Fetch devices for an employee.                                                                                                       |
| **Update Device**             | Update device attributes.                                                                                                            |
| **Update Asset**              | Update asset attributes, including setting a manual sale price.                                                                      |
| **List/Get Application**      | Fetch application data.                                                                                                              |
| **Get Employee Applications** | List apps for an employee.                                                                                                           |
| **Send Email**                | Send an email.                                                                                                                       |
| **Resolve Approver**          | Resolve who should approve.                                                                                                          |
| **Resolve Identity Provider** | Resolve IdP for an employee.                                                                                                         |
| **Generate CSV Report**       | Generate a CSV report.                                                                                                               |

**Looking Up Employees**

The **Get Employee** block supports two lookup methods - by employee ID or by email address. Both methods return the same employee data and work seamlessly with downstream steps.

**Filtering Employee Lists**

The **List Employees** block supports server-side filtering by:

* VIP status
* Employment status
* Location
* Employment start date range

**Setting Asset Sale Prices**

In the **Update Asset** block, add a **Manual Sale Price** value to save a price directly to the asset's purchase details. Only the price fields are updated - no other purchase details (such as ABM-sourced data) are overwritten.

***

### Using Conditional Logic

#### Using Conditional Logic (If/Else)

Add a **Condition** block from the Logic category. Configure a condition; the workflow branches to different paths based on whether the condition is true or false. Connect follow-up steps to the "true" or "false" output handles.

#### Setting Up Conditions

In the Condition block form, select a field (from trigger or prior steps), an operator (equals, contains, greater than, etc.), and a value. You can add multiple conditions and choose whether all or any must match.

#### Understanding Field Operators

Common operators: equals, not equals, contains, not contains, starts with, ends with, greater than, less than, is empty, is not empty. The available operators depend on the field type.

#### Building Complex Conditions

Combine multiple conditions with AND/OR. Use nested Condition blocks for complex branching.

***

### Using Logic Blocks

#### Pausing Workflows with the Sleep Block

Add a **Sleep** block from the Logic category to pause workflow execution for a precise amount of time before continuing to the next step. The timer is fully durable - it survives server restarts and continues reliably even across multi-day waits without consuming processing resources.

**Duration options:**

* Specify the wait in minutes, hours, or days - or combine all three for an additive total (e.g., 1 day + 2 hours + 30 minutes).
* Use a template expression for dynamic durations (e.g., `{{ config.jit_duration_minutes }}`), so wait times can vary based on workflow data.

#### Iterating Over Lists with the For Each Block

Add a **For Each** block to iterate over a list and execute a set of steps for each item. This is useful for bulk actions such as notifying a list of employees, processing multiple tickets, or enriching a set of records.

Key configuration options:

| Option                       | Description                                                                                                 |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------- |
| **`items`**                  | The list to iterate over, specified as a dynamic expression (e.g., `{{ steps.list_employees.employees }}`). |
| **`max_parallel`**           | How many items are processed at the same time. Default: 5, maximum: 20.                                     |
| **`continue_on_item_error`** | Whether a failure on one item stops the entire loop or allows remaining items to continue.                  |

***

### Working with Variables and Templates

#### Using Template Variables

Reference data from the trigger or previous steps using `{{ ... }}` syntax:

* **Workflow inputs:** `{{ input.employee_id }}` (manual trigger inputs)
* **Trigger event data:** `{{ trigger.ticket_id }}` (event triggers)
* **Webhook data:** `{{ trigger.* }}` (any field from the webhook request body)
* **Step outputs:** `{{ steps.step_id.output_field }}` (outputs from prior steps)

#### Understanding Available Variables

Variables depend on the current node's position. Only inputs and outputs from steps that run before the current node are available. The Template Picker and Token Input show available variables with autocomplete.

#### Inserting Variables in Actions

In action block fields that support templates, type `{{` to open the template picker, or click the variable button. Select a variable to insert it into the field.

#### Using the Template Picker

The Template Picker modal shows a tree of available variables grouped by source (inputs, trigger, steps). Expand nodes to find the path, then insert it into your field.

#### Working with Token Inputs

Fields that support templates use a Token Input. It shows inserted variables as tokens. Click a token to edit or remove it. Type to search available variables.

#### Understanding Token Autocomplete

When typing `{{` in a token input, autocomplete suggests variables. Variables are filtered by the current node's context (preceding steps and trigger). When typing `{{ trigger.` in any step input, autocomplete surfaces the specific fields available for the selected trigger event type.

***

### Managing and Testing Workflows

#### Editing Existing Workflows

Open a workflow from the Workflows list. The builder loads the workflow. Make changes to nodes, connections, or configuration. Save to persist. Unsaved changes are indicated in the toolbar.

#### Testing Workflow Steps

Select an action node and click **Test this step** (or the play icon on the node). The Execute Step modal opens. Provide test values for required inputs and run the step in isolation - without running the full workflow. Inputs are validated against the block's schema before execution, so you get a clear error immediately if something is misconfigured. View the output to verify the step works before running the full workflow.

#### Re-executing Failed Steps

From a run's detail view, you can re-run a specific failed step using its original inputs or modified ones. This means you can fix a misconfiguration and retry just that step without replaying the entire workflow.

#### Executing Workflows

Click **Run** in the toolbar to execute the workflow. For manual triggers, provide any required inputs in the dialog. The workflow runs and the Runs drawer opens with the run result.

#### Viewing Workflow Run History

Click the **Runs** (History) button in the toolbar to open the Runs drawer. It lists recent runs with status, duration, and timestamps. Click a run to expand and see step-by-step execution.

#### Understanding Workflow Run Details

Each run shows: Run ID, status (running, completed, failed), duration, and step list. Expand a step to see its input, output, and any error. Completed steps show green; failed steps show red with the error message. Sensitive values such as OTP codes are never exposed in plain text in run history or step outputs.

#### Viewing Step Execution Results

In the Runs drawer, expand a run and a step to see Input (JSON sent to the step), Output (JSON returned), and Error (if the step failed).

#### Understanding Workflow Errors

When a step fails, the error message appears in the step details. Common causes: invalid inputs, integration misconfiguration, API rate limits, or missing permissions. Use the error message and step input/output to troubleshoot.

#### Troubleshooting Failed Steps

1. Check the error message in the step details.
2. Verify inputs (templates resolve correctly, required fields are set).
3. Confirm the integration is connected and has the right scopes.
4. Use **Test this step** to test the step in isolation with sample data.
5. From the run detail view, re-run the failed step with corrected inputs.

#### Monitoring Workflow Health

Harmony automatically monitors the health of your workflows and detects when a dependency a workflow relies on becomes unavailable. When a desk, sub-desk, or employee referenced by a workflow is deleted or terminated, that workflow is instantly marked as **degraded** with a reason and timestamp - so broken workflows surface immediately rather than silently failing when triggered.

You can retrieve a workflow's current health status at any time using `GET /workflows/{id}/health`. The response includes the status (`healthy` or `degraded`) and, when degraded, the reason and the time it was detected.

#### Getting Notified on Workflow Failures

Each workflow can be configured with its own failure notification target. When a step fails, Harmony sends an alert immediately to your chosen destination. Notifications include:

* The workflow name and the specific step that failed
* The error message with full context
* A direct link to the failed run so you can jump straight into debugging

Supported notification targets: Slack channels, Slack DMs, Microsoft Teams channels, and Teams direct messages. Configure the notification target in the workflow **Settings** drawer.

#### Managing Workflow Versions

You can add a human-readable description to each workflow version to track what changed. When saving or updating a version, include a short note - for example, "Fixed approval timeout from 48h to 72h" or "Added JIT support."

* Descriptions appear alongside the version number, timestamp, and author in the version history list.
* You can set or update a description at any time after a version is created.
* Descriptions are optional; versions without one still appear in the history list.

#### Duplicating Workflows

Duplicate an existing workflow via the API using `POST /workflows/{id}/duplicate`. The copy is a fully independent workflow - editing the duplicate never affects the original.

The duplicate includes all steps, triggers, configuration schema, error handling, metadata (icon, tags), and branch logic. You can supply an optional `name` in the request body; if omitted, the copy is named "{original name} (copy)". The duplicate starts at version `1.0.0` and is created in a disabled state.

#### Bulk Deleting Workflows

Delete multiple workflows in a single API call using `POST /workflows/bulk-delete`. Pass an array of up to 50 workflow IDs. All in-flight runs are cancelled and related signals, trigger subscriptions, and event waits are removed for each deleted workflow.

If one or more workflow IDs fail to delete, the response includes details of which deletions succeeded and which failed so you can handle partial failures gracefully.

#### Deleting Workflows

Open the workflow **Settings** drawer (gear icon) and scroll to the **Danger zone**. Click **Delete Workflow** and confirm. The workflow is permanently removed.

***

### Using the Workflow Toolbar and Properties

#### Using the Workflow Toolbar

The toolbar at the top includes:

* **Back** - Return to the Workflows list.
* **Workflow name** - Click to edit. Click the emoji to change the workflow icon.
* **Undo/Redo** - Revert or reapply edits.
* **Run** - Execute the workflow.
* **Runs** - Open the run history drawer.
* **Save** - Save the workflow.
* **Settings** - Open workflow settings (name, description, error notifications, delete).
* **Enabled** - Toggle workflow on/off (publish/unpublish).
* **AI** - Open the AI workflow builder.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

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

```
GET https://docs.harmony.io/workflows-and-automation/building-and-managing-workflows.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

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