# Workflows (/concepts/workflows)



Workflows in Sendly allow you to create automated email sequences that can be triggered based on events you send using the API.

## Prerequisites for workflows [#prerequisites-for-workflows]

### Sending an event [#sending-an-event]

Workflows are triggered by sending events to Sendly using the [/api/track](/api-reference/events/trackEvent) endpoint. When sending an event, you can specify the contact it is associated with and include any relevant data.

### Creating a template [#creating-a-template]

Before setting up the workflow, ensure you have created a template that will be used for the emails sent by the workflow. You can create templates in the [Templates](/concepts/templates) section of the dashboard.

## Creating a workflow [#creating-a-workflow]

To create a workflow, navigate to the [Workflows](/concepts/workflows) section of the dashboard and create a workflow.

<Callout title="Trigger" variant="idea">
  In the dashboard the trigger event is fixed once the workflow exists, so choose the event name carefully. Over the API it can be changed — `PATCH /api/v1/workflows/{id}` accepts `event_name` and `trigger_type` — and the change is refused with a `409` while any run is still in flight.
</Callout>

### Defining workflow steps [#defining-workflow-steps]

Workflows consists of multiple steps that define the sequence of actions to be taken.

| Step Type            | Description                                                                                                                                                            |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Send Email           | Sends an email to the contact using a specified template. You can customize the email content using variables from the event data.                                     |
| Delay                | Pauses the workflow for a specified duration before proceeding to the next step.                                                                                       |
| Wait for Event       | Pauses the workflow until a specified event is received for the contact. You can also set a timeout duration to proceed if the event is not received within that time. |
| Condition            | Evaluates a condition based on the event data or contact data and branches the workflow accordingly.                                                                   |
| Webhook              | Sends a webhook to a specified URL with the event and contact data.                                                                                                    |
| Update Contact       | Updates the contact's data with specified key-value pairs.                                                                                                             |
| Exit                 | Terminates the workflow for the contact, and stamps an exit reason on the run.                                                                                         |
| Send at Optimal Time | Like Send Email, but held until this contact's historically best open hour, falling back to a fixed hour and never waiting longer than the step's maximum delay.       |

## Managing workflow executions [#managing-workflow-executions]

You can monitor and manage contacts going through workflows in the executions tab of the workflow detail page. Here you can see the status of each execution, cancel a specific execution or all executions.

A workflow will be locked while there are active executions. If you want to make changes to a running workflow you will either need to pause it and wait for all executions to complete, or cancel all active executions.

## Automating workflows over the API [#automating-workflows-over-the-api]

Everything above is also reachable over `/api/v1/workflows`, which is what an AI agent
connected through the [MCP server](/guides/mcp) uses too:

| What you want                                       | How                                          |
| --------------------------------------------------- | -------------------------------------------- |
| Create a workflow with its steps in one call        | `POST /api/v1/workflows` with a `sequence`   |
| Change metadata, the trigger, or the whole sequence | `PATCH /api/v1/workflows/{id}`               |
| Read or replace a branching graph                   | `GET` and `PUT /api/v1/workflows/{id}/graph` |
| Copy a workflow, steps and all, as a disabled draft | `POST /api/v1/workflows/{id}/clone`          |
| Stop it, and cancel the runs already inside it      | `POST /api/v1/workflows/{id}/pause`          |
| Re-open it to new runs                              | `POST /api/v1/workflows/{id}/resume`         |
| See how the runs are going                          | `GET /api/v1/workflows/{id}/stats`           |

<Callout type="warn" title="Disabling and pausing are not the same thing">
  Setting `enabled` to false stops the workflow being *triggered* again and leaves every
  contact already part-way through it walking the steps: the next delay still expires and the
  next email still sends. `POST /api/v1/workflows/{id}/pause` does both, and reports how many
  runs it cancelled. Cancelling is terminal — resuming re-opens the workflow to new runs, it
  does not put the cancelled contacts back where they were.
</Callout>

A `GET` on the graph endpoint returns a document that `PUT` accepts verbatim, so an edit is
read, change one step, send it all back. The step ids in it are yours: an id you send back
keeps that step and its run history, a new UUID adds a step, and an omitted step is deleted.
See the [MCP guide](/guides/mcp#building-a-workflows-steps) for the full document and its
rules.
