> 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

Learn how to build custom agents with triggers, actions, and conditional logic; use template variables; and test and publish agents.

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

### Understanding Agents and Automation

Custom agents let you automate work that runs based on triggers (manual, scheduled, events, or inbound webhooks) and execute a sequence of steps. Agents can integrate with Slack, Teams, Okta, HRIS systems, MDM tools, ServiceNow, GitHub, Jira, and Harmony itself.

#### Understanding the Agent Builder

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

#### Understanding the Canvas

The canvas is a drag-and-drop area where steps 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 Agents List

Open **Agents** at `/agents` to see all custom agents. Each card shows the agent name, description, enabled state, and toggle. Click an agent to edit it. Click **Build custom agent** to start a new one (when the Agent Builder feature is enabled).

#### Creating Your First Agent

1. Click **Build custom agent** on the Agents 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 agent.

***

### Building Agents

#### Adding Steps

* **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 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 agent. One per agent. 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 Agent Triggers

#### Using Manual Triggers

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

#### Using Scheduled Triggers

Runs the agent 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 agent. When you save an agent with a webhook trigger, the URL is created automatically and is ready to use immediately.

The full request body is passed into your agent 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 agent runs (e.g., only for certain desks, statuses, or types). Use the conditions section in the trigger configuration.

***

### Using Agent 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 agents. 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 agent itself.

Sensitive values such as OTP codes and temporary passwords are encrypted at rest and are never exposed in plain text in run 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 agent 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 an Agent with the Sleep Block

Add a **Sleep** block from the Logic category to pause the agent 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 agent 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:

* **Agent 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 Agents

#### Editing Existing Agents

Open an agent from the Agents list. The builder loads the agent. Make changes to nodes, connections, or configuration. Save to persist. Unsaved changes are indicated in the toolbar.

#### Testing Agent 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 agent. 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 agent.

#### 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 agent.

#### Executing Agents

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

#### Viewing Agent 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 Agent 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 Agent 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 Agent Health

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

You can retrieve an agent'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 Agent Failures

Each agent 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 agent 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 agent **Settings** drawer.

#### Managing Agent Versions

You can add a human-readable description to each agent 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 Agents

Duplicate an existing agent via the API using `POST /workflows/{id}/duplicate`. The copy is a fully independent agent - 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 Agents

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

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

#### Deleting Agents

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

***

### Using the Agent Toolbar and Properties

#### Using the Agent Toolbar

The toolbar at the top includes:

* **Back** - Return to the Agents list.
* **Agent name** - Click to edit. Click the emoji to change the agent icon.
* **Undo/Redo** - Revert or reapply edits.
* **Run** - Execute the agent.
* **Runs** - Open the run history drawer.
* **Save** - Save the agent.
* **Settings** - Open agent settings (name, description, error notifications, delete).
* **Enabled** - Toggle agent on/off (publish/unpublish).
* **AI** - Open the AI agent 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.
