---
title: "Automations"
description: "Every operation in this group: what it accepts, what it returns and the errors it can answer with."
url: "https://nextmail.sh/docs/api/reference/automations"
area: "API"
category: "Reference"
---

# Automations

Every operation in this group: what it accepts, what it returns and the errors it can answer with.

## Operations

Emails and other steps that run by themselves for each contact: a welcome series when somebody joins an audience, a nudge three days after a trial starts, a note on a birthday. An automation has a trigger, which says what puts a contact in, and steps: send an email from a template, wait, branch on what the contact did, add them to or remove them from an audience, write a custom field, call a webhook, or end. An automation can also start when somebody writes to you: it can wait for a reply, let the AI answer a yes or no question about the email, and reply inside the conversation.

You edit a draft `definition` and publish it. Publishing saves a numbered version and sets the automation `live`, and each contact stays on the version they entered on, so an edit never changes the path of somebody halfway through. Settings apply as soon as they are saved. A plan covers a number of live automations: 1 on Free, 10 on Starter and 50 on Business, with no limit on Enterprise.

Every email a send step sends goes out on the broadcast lane with a one-click unsubscribe, counts toward the monthly sends and skips suppressed addresses. A reply step answers one person inside their conversation, so it goes out as ordinary mail and carries no unsubscribe link. Publishing, resuming, sending a test and enrolling a contact in an automation that sends email also need `emails:send`, because the automation then sends mail for whoever published it. Reading needs `automations:read` and everything else `automations:write`.

### `GET /automations`

List automations

Every automation in the workspace, the most recently saved first, without the definition or settings. `counts` is counted at the moment of the read.

An app a member connected lists only the automations that member made.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Query parameters**

- `status` (`string`, one of `"draft"`, `"live"`, `"paused"`, `"archived"`): Only automations in this state.
- `limit` (`integer`, at least 1, at most 100, default `50`): Rows per page, 1 to 100.
- `cursor` (`string`): The id of the last automation on the previous page. Keyset, not offset: pass the previous page's `nextCursor`. One that names nothing in this list is a 400 `invalid_cursor`.

**Returns**

- `200` `AutomationList`: A page of automations.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.list()`](https://nextmail.sh/docs/sdk/reference/automations#list), [`nextmail.automations.listAll()`](https://nextmail.sh/docs/sdk/reference/automations#listAll), [`nextmail.automations.iterate()`](https://nextmail.sh/docs/sdk/reference/automations#iterate); Python [`automations.list()`](https://nextmail.sh/docs/python/reference/automations#list), [`automations.list_all()`](https://nextmail.sh/docs/python/reference/automations#listAll), [`automations.iterate()`](https://nextmail.sh/docs/python/reference/automations#iterate); Ruby [`automations.list`](https://nextmail.sh/docs/ruby/reference/automations#list), [`automations.list_all`](https://nextmail.sh/docs/ruby/reference/automations#listAll), [`automations.iterate`](https://nextmail.sh/docs/ruby/reference/automations#iterate); PHP [`automations->list`](https://nextmail.sh/docs/php/reference/automations#list), [`automations->listAll`](https://nextmail.sh/docs/php/reference/automations#listAll), [`automations->iterate`](https://nextmail.sh/docs/php/reference/automations#iterate); Go [`Automations.List`](https://nextmail.sh/docs/go/reference/automations#list), [`Automations.ListAll`](https://nextmail.sh/docs/go/reference/automations#listAll), [`Automations.Iterate`](https://nextmail.sh/docs/go/reference/automations#iterate); Java [`automations().list`](https://nextmail.sh/docs/java/reference/automations#list), [`automations().listAll`](https://nextmail.sh/docs/java/reference/automations#listAll), [`automations().iterate`](https://nextmail.sh/docs/java/reference/automations#iterate); C# [`Automations.ListAsync`](https://nextmail.sh/docs/csharp/reference/automations#list), [`Automations.ListAllAsync`](https://nextmail.sh/docs/csharp/reference/automations#listAll), [`Automations.IterateAsync`](https://nextmail.sh/docs/csharp/reference/automations#iterate); CLI [`nextmail automations list`](https://nextmail.sh/docs/cli/reference/automations#automations-list); MCP [`listAutomations`](https://nextmail.sh/docs/mcp/tools/automations#listAutomations).

### `POST /automations`

Create an automation

Makes a draft from `definition`, from a `starter`, or empty when neither is sent, and answers with the whole automation. A draft may be incomplete: `problems` in the answer lists what is still missing, and nothing runs until `POST /automations/{id}/publish`.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Request body**

- `name` (`string`, required, 1 to 120 characters): What the workspace calls the automation, trimmed, 1 to 120 characters. Contacts never see it, and it need not be unique.
- `description` (`string`, nullable, up to 500 characters): A note for the workspace, at most 500 characters. Contacts never see it.
- `starter` (`string`, 1 to 64 characters): Begin from a starter, by its `slug`: `welcome-series`, `trial-follow-up`, `birthday` or `win-back`. Ignored when `definition` is sent. A starter leaves the audience, the templates and the from address for you to fill in.
- `definition` (`object`): What starts an automation and what it then does. Paths never join or loop: every step is reached from exactly one place, and a definition holds at most 50 steps.
  - `trigger` (`object`, required, nullable): What puts a contact into the automation. Null in a draft that has none yet, and a draft cannot be published without one.
    - `kind` (`string`, required, one of `"audience_joined"`)
    - `audienceId` (`string`, required, up to 64 characters)
    - `includeImported` (`boolean`, required)
  - `entry` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`): The `key` of the first step, or null while the draft has no steps.
  - `steps` (`object[]`, required, up to 50 items): Every step, in any order. Each has a unique `key`, and names the step after it by key in `next`, or in `yes` and `no` for a branch. Null ends the path there.
    - `key` (`string`, required, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `name` (`string`, up to 80 characters)
    - `kind` (`string`, required, one of `"send_email"`)
    - `next` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `templateId` (`string`, required, up to 64 characters)
    - `templateVersion` (`integer`, required, nullable, at least 1)
    - `from` (`object`, required)
      - `email` (`string`, required, up to 320 characters)
      - `name` (`string`, up to 120 characters)
    - `replyTo` (`string`, required, nullable, up to 320 characters)
    - `subject` (`string`, required, nullable, up to 300 characters)
    - `props` (`Record<string, object>`, required)
- `settings` (`object`): How the automation runs: `timezone`, an IANA zone such as `Europe/London`, `sendWindow`, the days and minutes of the day in which emails may go out or null for any time, `reentryDays`, how many days after finishing a contact may enter again, 0 for straight away or null for once only, `exitOnLeave`, whether a contact leaves when they leave the audience that started it, and `listAudienceId`, the audience unsubscribes are recorded in. Every field is optional.
  - `timezone` (`string`, 1 to 64 characters)
  - `sendWindow` (`object`, nullable)
    - `days` (`integer[]`, required, up to 7 items)
    - `startMinute` (`integer`, required, at least 0, at most 1440)
    - `endMinute` (`integer`, required, at least 0, at most 1440)
  - `reentryDays` (`integer`, nullable, at least 0, at most 3650)
  - `exitOnLeave` (`boolean`)
  - `listAudienceId` (`string`, nullable, up to 64 characters)

**Returns**

- `201` `Automation`: Created, as a draft.

**Errors**

- `422`: `invalid_parameter` for a value of the wrong shape, `unknown_parameter` for a key the body does not take, `invalid_automation` for an unknown `starter` or a definition that breaks a rule of its structure, such as two steps with one key, or `workspace_limit_reached` when the workspace holds the most automations it may.
- The errors every operation can return: `400`, `401`, `403`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.create()`](https://nextmail.sh/docs/sdk/reference/automations#create); Python [`automations.create()`](https://nextmail.sh/docs/python/reference/automations#create); Ruby [`automations.create`](https://nextmail.sh/docs/ruby/reference/automations#create); PHP [`automations->create`](https://nextmail.sh/docs/php/reference/automations#create); Go [`Automations.Create`](https://nextmail.sh/docs/go/reference/automations#create); Java [`automations().create`](https://nextmail.sh/docs/java/reference/automations#create); C# [`Automations.CreateAsync`](https://nextmail.sh/docs/csharp/reference/automations#create); CLI [`nextmail automations create`](https://nextmail.sh/docs/cli/reference/automations#automations-create); MCP [`createAutomation`](https://nextmail.sh/docs/mcp/tools/automations#createAutomation).

### `GET /automations/starters`

List the automation starters

The starting points the app offers when somebody makes an automation, each with its whole `definition`. Not paginated and not workspace data. The `slug` is what `POST /automations` takes as `starter`. A starter leaves the audience, the templates and the from address empty for you to fill in.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Returns**

- `200` `AutomationStarterList`: Every starter.

**Errors**

- The errors every operation can return: `400`, `401`, `403`, `404`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.listStarters()`](https://nextmail.sh/docs/sdk/reference/automations#listStarters); Python [`automations.list_starters()`](https://nextmail.sh/docs/python/reference/automations#listStarters); Ruby [`automations.list_starters`](https://nextmail.sh/docs/ruby/reference/automations#listStarters); PHP [`automations->listStarters`](https://nextmail.sh/docs/php/reference/automations#listStarters); Go [`Automations.ListStarters`](https://nextmail.sh/docs/go/reference/automations#listStarters); Java [`automations().listStarters`](https://nextmail.sh/docs/java/reference/automations#listStarters); C# [`Automations.ListStartersAsync`](https://nextmail.sh/docs/csharp/reference/automations#listStarters); CLI [`nextmail automations list-starters`](https://nextmail.sh/docs/cli/reference/automations#automations-list-starters); MCP [`listAutomationStarters`](https://nextmail.sh/docs/mcp/tools/automations#listAutomationStarters).

### `GET /automations/analytics`

How all automations have performed

The numbers of every automation of the workspace over a window, side by side: `totals` for the automations you count, `automations` with a row for each automation, and `series` with a point for each day on which something happened. Each automation counts its days in its own time zone, so a day of `series` is the same calendar date in each of them. `active` is counted at the moment of the read, whatever the window. One automation alone, with its steps, is `GET /automations/{id}/stats`.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Query parameters**

- `automationIds` (`string`, up to 3250 characters): Only count these automations, as ids separated by commas, at most 50. Left out, every automation. `automations` lists every automation either way, so you can offer them as a filter.
- `since` (`string`, format `date-time`): Where the window starts, as an ISO 8601 instant. Left out, 30 days before `until`. It reaches back at most 366 days before `until`.
- `until` (`string`, format `date-time`): Where the window ends, as an ISO 8601 instant. Left out, now.

**Returns**

- `200` `AutomationAnalytics`: The numbers for the window.

**Errors**

- `422`: `invalid_parameter` when a time is not an ISO 8601 instant, `until` is not after `since`, or more than 50 automations are named.
- The errors every operation can return: `400`, `401`, `403`, `404`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.analytics()`](https://nextmail.sh/docs/sdk/reference/automations#analytics); Python [`automations.analytics()`](https://nextmail.sh/docs/python/reference/automations#analytics); Ruby [`automations.analytics`](https://nextmail.sh/docs/ruby/reference/automations#analytics); PHP [`automations->analytics`](https://nextmail.sh/docs/php/reference/automations#analytics); Go [`Automations.Analytics`](https://nextmail.sh/docs/go/reference/automations#analytics); Java [`automations().analytics`](https://nextmail.sh/docs/java/reference/automations#analytics); C# [`Automations.AnalyticsAsync`](https://nextmail.sh/docs/csharp/reference/automations#analytics); CLI [`nextmail automations analytics`](https://nextmail.sh/docs/cli/reference/automations#automations-analytics); MCP [`getAutomationAnalytics`](https://nextmail.sh/docs/mcp/tools/automations#getAutomationAnalytics).

### `GET /automations/{id}`

Retrieve an automation

The whole automation: the draft `definition`, the `published` definition that is running, `settings`, fresh `counts` and `problems`, what would stop the draft from being published. An automation in another workspace is a 404, never a 403.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `200` `Automation`: The automation.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.get()`](https://nextmail.sh/docs/sdk/reference/automations#get); Python [`automations.get()`](https://nextmail.sh/docs/python/reference/automations#get); Ruby [`automations.get`](https://nextmail.sh/docs/ruby/reference/automations#get); PHP [`automations->get`](https://nextmail.sh/docs/php/reference/automations#get); Go [`Automations.Get`](https://nextmail.sh/docs/go/reference/automations#get); Java [`automations().get`](https://nextmail.sh/docs/java/reference/automations#get); C# [`Automations.GetAsync`](https://nextmail.sh/docs/csharp/reference/automations#get); CLI [`nextmail automations get`](https://nextmail.sh/docs/cli/reference/automations#automations-get); MCP [`getAutomation`](https://nextmail.sh/docs/mcp/tools/automations#getAutomation).

### `PATCH /automations/{id}`

Update an automation

A partial update. `definition` replaces the draft whole, and a live automation keeps running its published version until `POST /automations/{id}/publish`. `settings` is merged field by field and takes effect at once.

Read the automation, change it and send `expectedUpdatedAt` with the `updatedAt` you read: if someone saved it in between, your change is refused instead of written over theirs.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Request body**

- `name` (`string`, 1 to 120 characters): What the workspace calls the automation, trimmed, 1 to 120 characters. Contacts never see it, and it need not be unique.
- `description` (`string`, nullable, up to 500 characters): A note for the workspace, at most 500 characters. Contacts never see it.
- `definition` (`object`): What starts an automation and what it then does. Paths never join or loop: every step is reached from exactly one place, and a definition holds at most 50 steps.
  - `trigger` (`object`, required, nullable): What puts a contact into the automation. Null in a draft that has none yet, and a draft cannot be published without one.
    - `kind` (`string`, required, one of `"audience_joined"`)
    - `audienceId` (`string`, required, up to 64 characters)
    - `includeImported` (`boolean`, required)
  - `entry` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`): The `key` of the first step, or null while the draft has no steps.
  - `steps` (`object[]`, required, up to 50 items): Every step, in any order. Each has a unique `key`, and names the step after it by key in `next`, or in `yes` and `no` for a branch. Null ends the path there.
    - `key` (`string`, required, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `name` (`string`, up to 80 characters)
    - `kind` (`string`, required, one of `"send_email"`)
    - `next` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `templateId` (`string`, required, up to 64 characters)
    - `templateVersion` (`integer`, required, nullable, at least 1)
    - `from` (`object`, required)
      - `email` (`string`, required, up to 320 characters)
      - `name` (`string`, up to 120 characters)
    - `replyTo` (`string`, required, nullable, up to 320 characters)
    - `subject` (`string`, required, nullable, up to 300 characters)
    - `props` (`Record<string, object>`, required)
- `settings` (`object`): Merged field by field into the stored settings, and applied at once, without publishing. Send only the fields you are changing.
  - `timezone` (`string`, 1 to 64 characters)
  - `sendWindow` (`object`, nullable)
    - `days` (`integer[]`, required, up to 7 items)
    - `startMinute` (`integer`, required, at least 0, at most 1440)
    - `endMinute` (`integer`, required, at least 0, at most 1440)
  - `reentryDays` (`integer`, nullable, at least 0, at most 3650)
  - `exitOnLeave` (`boolean`)
  - `listAudienceId` (`string`, nullable, up to 64 characters)
- `expectedUpdatedAt` (`string`, format `date-time`): The `updatedAt` you read. When the automation was saved since, the call is refused with 409 `version_conflict` and nothing is written.

**Returns**

- `200` `Automation`: Saved.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- `409`: `version_conflict`: the automation was saved after `expectedUpdatedAt`. `automation_archived`: an archived automation cannot be changed. Nothing was written.
- `422`: `invalid_parameter` for a value of the wrong shape, `unknown_parameter` for a key the body does not take, or `invalid_automation` when the definition breaks a rule of its structure or `settings.listAudienceId` names no audience.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.update()`](https://nextmail.sh/docs/sdk/reference/automations#update); Python [`automations.update()`](https://nextmail.sh/docs/python/reference/automations#update); Ruby [`automations.update`](https://nextmail.sh/docs/ruby/reference/automations#update); PHP [`automations->update`](https://nextmail.sh/docs/php/reference/automations#update); Go [`Automations.Update`](https://nextmail.sh/docs/go/reference/automations#update); Java [`automations().update`](https://nextmail.sh/docs/java/reference/automations#update); C# [`Automations.UpdateAsync`](https://nextmail.sh/docs/csharp/reference/automations#update); CLI [`nextmail automations update`](https://nextmail.sh/docs/cli/reference/automations#automations-update); MCP [`updateAutomation`](https://nextmail.sh/docs/mcp/tools/automations#updateAutomation).

### `DELETE /automations/{id}`

Delete an automation

Deletes the automation with its versions, its enrollments and its statistics. Contacts in it stop at once and get nothing more. The emails it already sent stay in `GET /emails`.

There is no undo. To retire one and keep its history, use `POST /automations/{id}/archive`.

Requires the `automations:write` scope.

- Scopes: `automations:write`.
- Asks an OAuth access token for a verification code.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `200` `DeletedAutomation`: Deleted.

**Errors**

- `403`: The key lacks the scope, or may not send as that address. `step_up_required`: the call was made with an OAuth access token that has not been verified in the last 60 minutes. Ask for a code with `POST /security/step-up`, send it to `POST /security/step-up/verify`, then repeat the call. The person can also choose Allow changes for 60 minutes on the app in Account settings, Connected apps, on the Nextmail website. An API key is never asked for a code.
- `404`: `automation_not_found` when the id names no automation you can reach.
- The errors every operation can return: `400`, `401`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.delete()`](https://nextmail.sh/docs/sdk/reference/automations#delete); Python [`automations.delete()`](https://nextmail.sh/docs/python/reference/automations#delete); Ruby [`automations.delete`](https://nextmail.sh/docs/ruby/reference/automations#delete); PHP [`automations->delete`](https://nextmail.sh/docs/php/reference/automations#delete); Go [`Automations.Delete`](https://nextmail.sh/docs/go/reference/automations#delete); Java [`automations().delete`](https://nextmail.sh/docs/java/reference/automations#delete); C# [`Automations.DeleteAsync`](https://nextmail.sh/docs/csharp/reference/automations#delete); CLI [`nextmail automations delete`](https://nextmail.sh/docs/cli/reference/automations#automations-delete); MCP [`deleteAutomation`](https://nextmail.sh/docs/mcp/tools/automations#deleteAutomation).

### `POST /automations/{id}/publish`

Publish an automation

Saves the draft as the next version and sets the automation `live`, so its trigger starts taking contacts in. Contacts already in it stay on the version they entered on. Publishing a paused automation turns it back on. No body.

The draft has to be complete: a trigger, at least one step, every email with a published template and a from address the caller may send as, and every audience, form and webhook it names still there. A template that does not place `{{unsubscribeUrl}}` gets the unsubscribe footer. The automation sends as whoever published it, so it pauses itself if that API key is revoked.

Requires the `automations:write` and `emails:send` scopes.

- Scopes: `automations:write`, `emails:send`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `200` `Automation`: Published and live.

**Errors**

- `403`: `automation_limit_reached` when the plan covers no more live automations, or `insufficient_scope`.
- `404`: `automation_not_found` when the id names no automation you can reach.
- `409`: `automation_archived`: an archived automation cannot be published.
- `422`: `invalid_automation` when the draft cannot run: the error carries `problems`, every problem that blocks it, each with a `code`, the `path` of the field, the `stepKey` and a `message`.
- The errors every operation can return: `400`, `401`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.publish()`](https://nextmail.sh/docs/sdk/reference/automations#publish); Python [`automations.publish()`](https://nextmail.sh/docs/python/reference/automations#publish); Ruby [`automations.publish`](https://nextmail.sh/docs/ruby/reference/automations#publish); PHP [`automations->publish`](https://nextmail.sh/docs/php/reference/automations#publish); Go [`Automations.Publish`](https://nextmail.sh/docs/go/reference/automations#publish); Java [`automations().publish`](https://nextmail.sh/docs/java/reference/automations#publish); C# [`Automations.PublishAsync`](https://nextmail.sh/docs/csharp/reference/automations#publish); CLI [`nextmail automations publish`](https://nextmail.sh/docs/cli/reference/automations#automations-publish); MCP [`publishAutomation`](https://nextmail.sh/docs/mcp/tools/automations#publishAutomation).

### `POST /automations/{id}/pause`

Pause an automation

Stops a live automation. Nobody new enters, and everyone in it stays where they are and moves on when it is resumed. Pausing a paused automation changes nothing. No body.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `200` `Automation`: Paused.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- `409`: `automation_not_published`: a draft that was never published cannot be paused. `automation_archived`: neither can an archived one.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.pause()`](https://nextmail.sh/docs/sdk/reference/automations#pause); Python [`automations.pause()`](https://nextmail.sh/docs/python/reference/automations#pause); Ruby [`automations.pause`](https://nextmail.sh/docs/ruby/reference/automations#pause); PHP [`automations->pause`](https://nextmail.sh/docs/php/reference/automations#pause); Go [`Automations.Pause`](https://nextmail.sh/docs/go/reference/automations#pause); Java [`automations().pause`](https://nextmail.sh/docs/java/reference/automations#pause); C# [`Automations.PauseAsync`](https://nextmail.sh/docs/csharp/reference/automations#pause); CLI [`nextmail automations pause`](https://nextmail.sh/docs/cli/reference/automations#automations-pause); MCP [`pauseAutomation`](https://nextmail.sh/docs/mcp/tools/automations#pauseAutomation).

### `POST /automations/{id}/resume`

Resume an automation

Turns a paused automation back on with the version it was running, without publishing the draft. Contacts that were held move on, and from now on it sends as the caller. The published version is checked again first, so an automation Nextmail paused stays paused until what stopped it is fixed. Resuming a live automation changes nothing. No body.

Requires the `automations:write` and `emails:send` scopes.

- Scopes: `automations:write`, `emails:send`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `200` `Automation`: Live again.

**Errors**

- `403`: `automation_limit_reached` when the plan covers no more live automations, or `insufficient_scope`.
- `404`: `automation_not_found` when the id names no automation you can reach.
- `409`: `automation_not_published`: there is no published version to resume. `automation_archived`: an archived automation cannot be resumed.
- `422`: `invalid_automation` when the draft cannot run: the error carries `problems`, every problem that blocks it, each with a `code`, the `path` of the field, the `stepKey` and a `message`.
- The errors every operation can return: `400`, `401`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.resume()`](https://nextmail.sh/docs/sdk/reference/automations#resume); Python [`automations.resume()`](https://nextmail.sh/docs/python/reference/automations#resume); Ruby [`automations.resume`](https://nextmail.sh/docs/ruby/reference/automations#resume); PHP [`automations->resume`](https://nextmail.sh/docs/php/reference/automations#resume); Go [`Automations.Resume`](https://nextmail.sh/docs/go/reference/automations#resume); Java [`automations().resume`](https://nextmail.sh/docs/java/reference/automations#resume); C# [`Automations.ResumeAsync`](https://nextmail.sh/docs/csharp/reference/automations#resume); CLI [`nextmail automations resume`](https://nextmail.sh/docs/cli/reference/automations#automations-resume); MCP [`resumeAutomation`](https://nextmail.sh/docs/mcp/tools/automations#resumeAutomation).

### `POST /automations/{id}/archive`

Archive an automation

Retires an automation for good and keeps its history. Everyone in it leaves with the exit reason `archived`, nobody enters again, and it can no longer be changed, published or resumed. Its versions, enrollments and statistics stay readable. Archiving an archived automation changes nothing. No body.

To start again from its steps, use `POST /automations/{id}/duplicate`.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `200` `Automation`: Archived.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.archive()`](https://nextmail.sh/docs/sdk/reference/automations#archive); Python [`automations.archive()`](https://nextmail.sh/docs/python/reference/automations#archive); Ruby [`automations.archive`](https://nextmail.sh/docs/ruby/reference/automations#archive); PHP [`automations->archive`](https://nextmail.sh/docs/php/reference/automations#archive); Go [`Automations.Archive`](https://nextmail.sh/docs/go/reference/automations#archive); Java [`automations().archive`](https://nextmail.sh/docs/java/reference/automations#archive); C# [`Automations.ArchiveAsync`](https://nextmail.sh/docs/csharp/reference/automations#archive); CLI [`nextmail automations archive`](https://nextmail.sh/docs/cli/reference/automations#automations-archive); MCP [`archiveAutomation`](https://nextmail.sh/docs/mcp/tools/automations#archiveAutomation).

### `POST /automations/{id}/duplicate`

Duplicate an automation

Makes a new draft with the same draft definition and settings, named after the original with (copy) on the end. The copy has no versions, no contacts and no statistics. No body.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `201` `Automation`: The copy, as a draft.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- `422`: `workspace_limit_reached` when the workspace holds the most automations it may.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.duplicate()`](https://nextmail.sh/docs/sdk/reference/automations#duplicate); Python [`automations.duplicate()`](https://nextmail.sh/docs/python/reference/automations#duplicate); Ruby [`automations.duplicate`](https://nextmail.sh/docs/ruby/reference/automations#duplicate); PHP [`automations->duplicate`](https://nextmail.sh/docs/php/reference/automations#duplicate); Go [`Automations.Duplicate`](https://nextmail.sh/docs/go/reference/automations#duplicate); Java [`automations().duplicate`](https://nextmail.sh/docs/java/reference/automations#duplicate); C# [`Automations.DuplicateAsync`](https://nextmail.sh/docs/csharp/reference/automations#duplicate); CLI [`nextmail automations duplicate`](https://nextmail.sh/docs/cli/reference/automations#automations-duplicate); MCP [`duplicateAutomation`](https://nextmail.sh/docs/mcp/tools/automations#duplicateAutomation).

### `POST /automations/{id}/test`

Send a test of one email step

Sends the email of one step of the draft to one address, so you can read it before publishing. Contact values are filled from a sample contact, values that come from an event are left empty, and the subject starts with [Test]. It counts toward the monthly sends, is not tracked and enrolls nobody.

Requires the `automations:write` and `emails:send` scopes.

- Scopes: `automations:write`, `emails:send`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Request body**

- `stepKey` (`string`, required, 1 to 64 characters): The `key` of the email step to send, from the draft `definition`.
- `to` (`string`, up to 320 characters, format `email`): Where the test goes. Left out, it goes to the account email of the person the key or app acts for.

**Returns**

- `200` `AutomationTest`: Sent.

**Errors**

- `403`: `from_address_forbidden` when the caller may not send as the from address of the step, or `insufficient_scope`.
- `404`: `automation_not_found` when the id names no automation you can reach.
- `409`: `domain_not_sendable` when the domain of the from address cannot send yet.
- `422`: `invalid_automation` when `stepKey` names no step, the step is not an email, or its template cannot be sent, with `param` set to `stepKey`.
- `429`: `send_quota_exceeded`: the monthly sends of the plan are used up. `rate_limited`: the key or app made more than 600 requests in 60 seconds. Wait for the seconds in `Retry-After`.
- The errors every operation can return: `400`, `401`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.sendTest()`](https://nextmail.sh/docs/sdk/reference/automations#sendTest); Python [`automations.send_test()`](https://nextmail.sh/docs/python/reference/automations#sendTest); Ruby [`automations.send_test`](https://nextmail.sh/docs/ruby/reference/automations#sendTest); PHP [`automations->sendTest`](https://nextmail.sh/docs/php/reference/automations#sendTest); Go [`Automations.SendTest`](https://nextmail.sh/docs/go/reference/automations#sendTest); Java [`automations().sendTest`](https://nextmail.sh/docs/java/reference/automations#sendTest); C# [`Automations.SendTestAsync`](https://nextmail.sh/docs/csharp/reference/automations#sendTest); CLI [`nextmail automations send-test`](https://nextmail.sh/docs/cli/reference/automations#automations-send-test); MCP [`sendAutomationTest`](https://nextmail.sh/docs/mcp/tools/automations#sendAutomationTest).

### `GET /automations/{id}/versions`

List the versions of an automation

Every published version, the newest first, each with its whole definition. `current` marks the one that is running. Not paginated. A draft that was never published has none.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Returns**

- `200` `AutomationVersionList`: The versions.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.listVersions()`](https://nextmail.sh/docs/sdk/reference/automations#listVersions); Python [`automations.list_versions()`](https://nextmail.sh/docs/python/reference/automations#listVersions); Ruby [`automations.list_versions`](https://nextmail.sh/docs/ruby/reference/automations#listVersions); PHP [`automations->listVersions`](https://nextmail.sh/docs/php/reference/automations#listVersions); Go [`Automations.ListVersions`](https://nextmail.sh/docs/go/reference/automations#listVersions); Java [`automations().listVersions`](https://nextmail.sh/docs/java/reference/automations#listVersions); C# [`Automations.ListVersionsAsync`](https://nextmail.sh/docs/csharp/reference/automations#listVersions); CLI [`nextmail automations list-versions`](https://nextmail.sh/docs/cli/reference/automations#automations-list-versions); MCP [`listAutomationVersions`](https://nextmail.sh/docs/mcp/tools/automations#listAutomationVersions).

### `POST /automations/{id}/versions/{version}/restore`

Restore a version into the draft

Copies the definition of an earlier version into the draft, replacing what the draft holds. Nothing that is running changes until `POST /automations/{id}/publish`. No body.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.
- `version` (`integer`, required, at least 1): The number of the version, as `GET /automations/{id}/versions` lists it.

**Returns**

- `200` `Automation`: The automation, with the version in its draft.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach, or, with `param` set to `version`, when it has no such version.
- `409`: `automation_archived`: an archived automation cannot be changed.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.restoreVersion()`](https://nextmail.sh/docs/sdk/reference/automations#restoreVersion); Python [`automations.restore_version()`](https://nextmail.sh/docs/python/reference/automations#restoreVersion); Ruby [`automations.restore_version`](https://nextmail.sh/docs/ruby/reference/automations#restoreVersion); PHP [`automations->restoreVersion`](https://nextmail.sh/docs/php/reference/automations#restoreVersion); Go [`Automations.RestoreVersion`](https://nextmail.sh/docs/go/reference/automations#restoreVersion); Java [`automations().restoreVersion`](https://nextmail.sh/docs/java/reference/automations#restoreVersion); C# [`Automations.RestoreVersionAsync`](https://nextmail.sh/docs/csharp/reference/automations#restoreVersion); CLI [`nextmail automations restore-version`](https://nextmail.sh/docs/cli/reference/automations#automations-restore-version); MCP [`restoreAutomationVersion`](https://nextmail.sh/docs/mcp/tools/automations#restoreAutomationVersion).

### `GET /automations/{id}/stats`

How an automation has performed

Totals for a window, the same numbers step by step, and a point per day. Days are calendar days in the time zone of the automation, which `timezone` names, and each point carries its `date`. The steps are those of the published version, or of the draft when nothing is published. `active` and `waiting` are counted at the moment of the read, whatever the window.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Query parameters**

- `since` (`string`, format `date-time`): Where the window starts, as an ISO 8601 instant. Left out, 30 days before `until`. It reaches back at most 366 days before `until`.
- `until` (`string`, format `date-time`): Where the window ends, as an ISO 8601 instant. Left out, now.

**Returns**

- `200` `AutomationStats`: The numbers for the window.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- `422`: `invalid_parameter` when a time is not an ISO 8601 instant or `until` is not after `since`.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.stats()`](https://nextmail.sh/docs/sdk/reference/automations#stats); Python [`automations.stats()`](https://nextmail.sh/docs/python/reference/automations#stats); Ruby [`automations.stats`](https://nextmail.sh/docs/ruby/reference/automations#stats); PHP [`automations->stats`](https://nextmail.sh/docs/php/reference/automations#stats); Go [`Automations.Stats`](https://nextmail.sh/docs/go/reference/automations#stats); Java [`automations().stats`](https://nextmail.sh/docs/java/reference/automations#stats); C# [`Automations.StatsAsync`](https://nextmail.sh/docs/csharp/reference/automations#stats); CLI [`nextmail automations stats`](https://nextmail.sh/docs/cli/reference/automations#automations-stats); MCP [`getAutomationStats`](https://nextmail.sh/docs/mcp/tools/automations#getAutomationStats).

### `GET /automations/{id}/runs`

List what an automation did

Everything the automation did, newest first, in one list: each contact entering, every step it ran for them with its outcome, and each contact completing or leaving early with the reason. It is the run log of the whole automation; one contact alone, oldest first, is `GET /automations/{id}/enrollments/{enrollmentId}`. `stepKey` and `outcome` narrow it to steps.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Query parameters**

- `event` (`string`, one of `"entered"`, `"step"`, `"completed"`, `"exited"`): Only entries of this kind: contacts that `entered`, a `step` that ran, or contacts that `completed` or `exited`.
- `stepKey` (`string`, 1 to 64 characters): Only the steps with this `key` that ran.
- `outcome` (`string`, one of `"sent"`, `"skipped"`, `"waited"`, `"yes"`, `"no"`, `"added"`, `"removed"`, `"updated"`, `"called"`, `"exited"`, `"failed"`): Only the steps that ran with this outcome, such as `failed` or `skipped`.
- `limit` (`integer`, at least 1, at most 200, default `50`): Rows per page, 1 to 200.
- `cursor` (`string`): The `id` of the last entry on the previous page. Keyset, not offset: pass the previous page's `nextCursor`. One that names nothing in this list is a 400 `invalid_cursor`.

**Returns**

- `200` `AutomationRunList`: A page of entries, newest first.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.listRuns()`](https://nextmail.sh/docs/sdk/reference/automations#listRuns), [`nextmail.automations.listAllRuns()`](https://nextmail.sh/docs/sdk/reference/automations#listAllRuns), [`nextmail.automations.iterateRuns()`](https://nextmail.sh/docs/sdk/reference/automations#iterateRuns); Python [`automations.list_runs()`](https://nextmail.sh/docs/python/reference/automations#listRuns), [`automations.list_all_runs()`](https://nextmail.sh/docs/python/reference/automations#listAllRuns), [`automations.iterate_runs()`](https://nextmail.sh/docs/python/reference/automations#iterateRuns); Ruby [`automations.list_runs`](https://nextmail.sh/docs/ruby/reference/automations#listRuns), [`automations.list_all_runs`](https://nextmail.sh/docs/ruby/reference/automations#listAllRuns), [`automations.iterate_runs`](https://nextmail.sh/docs/ruby/reference/automations#iterateRuns); PHP [`automations->listRuns`](https://nextmail.sh/docs/php/reference/automations#listRuns), [`automations->listAllRuns`](https://nextmail.sh/docs/php/reference/automations#listAllRuns), [`automations->iterateRuns`](https://nextmail.sh/docs/php/reference/automations#iterateRuns); Go [`Automations.ListRuns`](https://nextmail.sh/docs/go/reference/automations#listRuns), [`Automations.ListAllRuns`](https://nextmail.sh/docs/go/reference/automations#listAllRuns), [`Automations.IterateRuns`](https://nextmail.sh/docs/go/reference/automations#iterateRuns); Java [`automations().listRuns`](https://nextmail.sh/docs/java/reference/automations#listRuns), [`automations().listAllRuns`](https://nextmail.sh/docs/java/reference/automations#listAllRuns), [`automations().iterateRuns`](https://nextmail.sh/docs/java/reference/automations#iterateRuns); C# [`Automations.ListRunsAsync`](https://nextmail.sh/docs/csharp/reference/automations#listRuns), [`Automations.ListAllRunsAsync`](https://nextmail.sh/docs/csharp/reference/automations#listAllRuns), [`Automations.IterateRunsAsync`](https://nextmail.sh/docs/csharp/reference/automations#iterateRuns); CLI [`nextmail automations list-runs`](https://nextmail.sh/docs/cli/reference/automations#automations-list-runs); MCP [`listAutomationRuns`](https://nextmail.sh/docs/mcp/tools/automations#listAutomationRuns).

### `GET /automations/{id}/enrollments`

List the contacts in an automation

Everyone who is in the automation or has been, the most recent entry first: where each contact is, what they are waiting for and how it ended.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Query parameters**

- `status` (`string`, one of `"active"`, `"completed"`, `"exited"`): Only enrollments in this state.
- `stepKey` (`string`, 1 to 64 characters): Only contacts at the step with this `key`.
- `q` (`string`, up to 200 characters): Only contacts whose address or name contains this text, compared without case.
- `limit` (`integer`, at least 1, at most 200, default `50`): Rows per page, 1 to 200.
- `cursor` (`string`): The id of the last enrollment on the previous page. Keyset, not offset: pass the previous page's `nextCursor`. One that names nothing in this list is a 400 `invalid_cursor`.

**Returns**

- `200` `AutomationEnrollmentList`: A page of enrollments.

**Errors**

- `404`: `automation_not_found` when the id names no automation you can reach.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.listEnrollments()`](https://nextmail.sh/docs/sdk/reference/automations#listEnrollments), [`nextmail.automations.listAllEnrollments()`](https://nextmail.sh/docs/sdk/reference/automations#listAllEnrollments), [`nextmail.automations.iterateEnrollments()`](https://nextmail.sh/docs/sdk/reference/automations#iterateEnrollments); Python [`automations.list_enrollments()`](https://nextmail.sh/docs/python/reference/automations#listEnrollments), [`automations.list_all_enrollments()`](https://nextmail.sh/docs/python/reference/automations#listAllEnrollments), [`automations.iterate_enrollments()`](https://nextmail.sh/docs/python/reference/automations#iterateEnrollments); Ruby [`automations.list_enrollments`](https://nextmail.sh/docs/ruby/reference/automations#listEnrollments), [`automations.list_all_enrollments`](https://nextmail.sh/docs/ruby/reference/automations#listAllEnrollments), [`automations.iterate_enrollments`](https://nextmail.sh/docs/ruby/reference/automations#iterateEnrollments); PHP [`automations->listEnrollments`](https://nextmail.sh/docs/php/reference/automations#listEnrollments), [`automations->listAllEnrollments`](https://nextmail.sh/docs/php/reference/automations#listAllEnrollments), [`automations->iterateEnrollments`](https://nextmail.sh/docs/php/reference/automations#iterateEnrollments); Go [`Automations.ListEnrollments`](https://nextmail.sh/docs/go/reference/automations#listEnrollments), [`Automations.ListAllEnrollments`](https://nextmail.sh/docs/go/reference/automations#listAllEnrollments), [`Automations.IterateEnrollments`](https://nextmail.sh/docs/go/reference/automations#iterateEnrollments); Java [`automations().listEnrollments`](https://nextmail.sh/docs/java/reference/automations#listEnrollments), [`automations().listAllEnrollments`](https://nextmail.sh/docs/java/reference/automations#listAllEnrollments), [`automations().iterateEnrollments`](https://nextmail.sh/docs/java/reference/automations#iterateEnrollments); C# [`Automations.ListEnrollmentsAsync`](https://nextmail.sh/docs/csharp/reference/automations#listEnrollments), [`Automations.ListAllEnrollmentsAsync`](https://nextmail.sh/docs/csharp/reference/automations#listAllEnrollments), [`Automations.IterateEnrollmentsAsync`](https://nextmail.sh/docs/csharp/reference/automations#iterateEnrollments); CLI [`nextmail automations list-enrollments`](https://nextmail.sh/docs/cli/reference/automations#automations-list-enrollments); MCP [`listAutomationEnrollments`](https://nextmail.sh/docs/mcp/tools/automations#listAutomationEnrollments).

### `POST /automations/{id}/enrollments`

Enroll a contact in an automation

Puts one contact into a live automation at its first step, whatever its trigger is. The contact has to exist already. `data` gives the steps the values they would otherwise read from an event.

A contact is in an automation once at a time, and comes back in only after `settings.reentryDays`. An address on the suppression list, or one that unsubscribed from the audience the automation sends through, is refused.

When the automation has a step that sends or answers email, enrolling also needs `emails:send`, because the automation then sends mail for whoever published it. A key or app limited to some addresses or domains can only enroll contacts in such an automation when its publisher was limited to the same addresses or fewer.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.

**Request body**

- `contactId` (`string`, 1 to 64 characters): The contact, by id. Send this or `email`, never both.
- `email` (`string`, up to 320 characters, format `email`): The contact, by email address. Send this or `contactId`, never both.
- `data` (`Record<string, any>`): Values the steps can read wherever a value comes from the event, such as an order number for an email. At most 50 keys and 4 KB of JSON. The key `email` is kept for the email an automation answers, so `data` cannot hold it.

**Returns**

- `201` `AutomationEnrollment`: Enrolled, and due at the first step.

**Errors**

- `404`: `automation_not_found`, or `contact_not_found` when no contact has that id or address.
- `409`: `automation_not_live` when it is a draft, paused or archived. `already_enrolled` when the contact is in it or finished it too recently. `contact_unreachable` when the address is suppressed or unsubscribed.
- `422`: `invalid_parameter` when neither or both of `contactId` and `email` are sent, `data` is too large or `data` holds the key `email`. `capability_unsupported` when a key or app limited to some addresses enrolls a contact in an automation that sends with wider access.
- The errors every operation can return: `400`, `401`, `403`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.enroll()`](https://nextmail.sh/docs/sdk/reference/automations#enroll); Python [`automations.enroll()`](https://nextmail.sh/docs/python/reference/automations#enroll); Ruby [`automations.enroll`](https://nextmail.sh/docs/ruby/reference/automations#enroll); PHP [`automations->enroll`](https://nextmail.sh/docs/php/reference/automations#enroll); Go [`Automations.Enroll`](https://nextmail.sh/docs/go/reference/automations#enroll); Java [`automations().enroll`](https://nextmail.sh/docs/java/reference/automations#enroll); C# [`Automations.EnrollAsync`](https://nextmail.sh/docs/csharp/reference/automations#enroll); CLI [`nextmail automations enroll`](https://nextmail.sh/docs/cli/reference/automations#automations-enroll); MCP [`enrollInAutomation`](https://nextmail.sh/docs/mcp/tools/automations#enrollInAutomation).

### `GET /automations/{id}/enrollments/{enrollmentId}`

Retrieve an enrollment

One contact's way through the automation: the enrollment, plus `runs`, what each step did for them, oldest first, up to 200.

Requires the `automations:read` scope.

- Scopes: `automations:read`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.
- `enrollmentId` (`string`, required): The enrollment, such as `aen_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /automations/{id}/enrollments` lists it.

**Returns**

- `200` `AutomationEnrollmentDetail`: The enrollment with its runs.

**Errors**

- `404`: `automation_not_found` or `automation_enrollment_not_found`.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.getEnrollment()`](https://nextmail.sh/docs/sdk/reference/automations#getEnrollment); Python [`automations.get_enrollment()`](https://nextmail.sh/docs/python/reference/automations#getEnrollment); Ruby [`automations.get_enrollment`](https://nextmail.sh/docs/ruby/reference/automations#getEnrollment); PHP [`automations->getEnrollment`](https://nextmail.sh/docs/php/reference/automations#getEnrollment); Go [`Automations.GetEnrollment`](https://nextmail.sh/docs/go/reference/automations#getEnrollment); Java [`automations().getEnrollment`](https://nextmail.sh/docs/java/reference/automations#getEnrollment); C# [`Automations.GetEnrollmentAsync`](https://nextmail.sh/docs/csharp/reference/automations#getEnrollment); CLI [`nextmail automations get-enrollment`](https://nextmail.sh/docs/cli/reference/automations#automations-get-enrollment); MCP [`getAutomationEnrollment`](https://nextmail.sh/docs/mcp/tools/automations#getAutomationEnrollment).

### `POST /automations/{id}/enrollments/{enrollmentId}/exit`

Take a contact out of an automation

Ends an active enrollment at once with the exit reason `removed`. The contact gets nothing more from this automation, and stays in the contacts and in their audiences. No body.

Requires the `automations:write` scope.

- Scopes: `automations:write`.

**Path parameters**

- `id` (`string`, required): The automation, such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`, as `GET /automations` lists it.
- `enrollmentId` (`string`, required): The enrollment, such as `aen_2b8d4f6a1c3e5079b6d8f0a2`, as `GET /automations/{id}/enrollments` lists it.

**Returns**

- `200` `AutomationEnrollment`: The enrollment, exited.

**Errors**

- `404`: `automation_not_found` or `automation_enrollment_not_found`.
- `409`: `automation_enrollment_finished`: the contact already completed or left.
- The errors every operation can return: `400`, `401`, `403`, `422`, `429`, `500`, described in the [error catalog](https://nextmail.sh/docs/api/errors).

Also available in: TypeScript [`nextmail.automations.exitEnrollment()`](https://nextmail.sh/docs/sdk/reference/automations#exitEnrollment); Python [`automations.exit_enrollment()`](https://nextmail.sh/docs/python/reference/automations#exitEnrollment); Ruby [`automations.exit_enrollment`](https://nextmail.sh/docs/ruby/reference/automations#exitEnrollment); PHP [`automations->exitEnrollment`](https://nextmail.sh/docs/php/reference/automations#exitEnrollment); Go [`Automations.ExitEnrollment`](https://nextmail.sh/docs/go/reference/automations#exitEnrollment); Java [`automations().exitEnrollment`](https://nextmail.sh/docs/java/reference/automations#exitEnrollment); C# [`Automations.ExitEnrollmentAsync`](https://nextmail.sh/docs/csharp/reference/automations#exitEnrollment); CLI [`nextmail automations exit-enrollment`](https://nextmail.sh/docs/cli/reference/automations#automations-exit-enrollment); MCP [`removeFromAutomation`](https://nextmail.sh/docs/mcp/tools/automations#removeFromAutomation).

### Objects

#### `Automation`

`object`

- `object` (`string`, required, one of `"automation"`)
- `id` (`string`, required): The id of the automation. It never changes.
- `name` (`string`, required): What the workspace calls it. Contacts never see it.
- `description` (`string`, required, nullable): A note for the workspace.
- `status` (`string`, required, one of `"draft"`, `"live"`, `"paused"`, `"archived"`): `draft` until the first publish. `live` takes contacts in and moves them along. `paused` takes nobody in and holds everyone where they are. `archived` is retired for good and everyone in it has left.
- `triggerKind` (`string`, required, nullable, one of `"audience_joined"`, `"form_submitted"`, `"event"`, `"date"`, `"manual"`, `"email_received"`): What starts the draft, or null while it has no trigger.
- `stepCount` (`integer`, required, at least 0): How many steps the draft holds.
- `emailCount` (`integer`, required, at least 0): How many of those steps send an email.
- `hasUnpublishedChanges` (`boolean`, required): True when the draft differs from the version that is running.
- `publishedVersion` (`integer`, required, nullable): The number of the version that is running. Null until the first publish.
- `pausedReason` (`string`, required, nullable, one of `"manual"`, `"sender_refused"`, `"key_revoked"`, `"template_unavailable"`, `"audience_missing"`, `"plan_limit"`): Why it is paused. `manual` is a person. The others are Nextmail stopping it: `sender_refused` when its from address can no longer send, `key_revoked` when the API key that published it was revoked, expired or turned off, `template_unavailable` when one of its templates can no longer be sent, `audience_missing` when an audience it depends on is gone, and `plan_limit` when the plan no longer covers this many live automations. Null while it is not paused.
- `lastError` (`string`, required, nullable): What went wrong the last time Nextmail paused it, in a sentence. Null otherwise.
- `counts` (`object`, required): Contacts, counted at the moment of the read.
  - `active` (`integer`, required, at least 0): In the automation now.
  - `completed` (`integer`, required, at least 0): Reached the end of a path, in all its time.
  - `exited` (`integer`, required, at least 0): Left before the end, in all its time.
- `createdBy` (`string`, required, nullable): The user id of the person who made it. Null when that account is gone.
- `publishedAt` (`string`, required, nullable, format `date-time`): The last publish. Null until the first.
- `pausedAt` (`string`, required, nullable, format `date-time`): When it was paused. Null while it is not.
- `archivedAt` (`string`, required, nullable, format `date-time`): When it was archived. Null otherwise.
- `createdAt` (`string`, required, format `date-time`): When it was made.
- `updatedAt` (`string`, required, format `date-time`): The last save. Send it back as `expectedUpdatedAt` so a change never overwrites one you have not seen.
- `definition` (`object`, required): What starts an automation and what it then does. Paths never join or loop: every step is reached from exactly one place, and a definition holds at most 50 steps.
  - `trigger` (`object`, required, nullable): What puts a contact into the automation. Null in a draft that has none yet, and a draft cannot be published without one.
    - `kind` (`string`, required, one of `"audience_joined"`)
    - `audienceId` (`string`, required, up to 64 characters)
    - `includeImported` (`boolean`, required)
  - `entry` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`): The `key` of the first step, or null while the draft has no steps.
  - `steps` (`object[]`, required, up to 50 items): Every step, in any order. Each has a unique `key`, and names the step after it by key in `next`, or in `yes` and `no` for a branch. Null ends the path there.
    - `key` (`string`, required, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `name` (`string`, up to 80 characters)
    - `kind` (`string`, required, one of `"send_email"`)
    - `next` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `templateId` (`string`, required, up to 64 characters)
    - `templateVersion` (`integer`, required, nullable, at least 1)
    - `from` (`object`, required)
      - `email` (`string`, required, up to 320 characters)
      - `name` (`string`, up to 120 characters)
    - `replyTo` (`string`, required, nullable, up to 320 characters)
    - `subject` (`string`, required, nullable, up to 300 characters)
    - `props` (`Record<string, object>`, required)
- `published` (`object`, required, nullable): What starts an automation and what it then does. Paths never join or loop: every step is reached from exactly one place, and a definition holds at most 50 steps.
  - `trigger` (`object`, required, nullable): What puts a contact into the automation. Null in a draft that has none yet, and a draft cannot be published without one.
    - `kind` (`string`, required, one of `"audience_joined"`)
    - `audienceId` (`string`, required, up to 64 characters)
    - `includeImported` (`boolean`, required)
  - `entry` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`): The `key` of the first step, or null while the draft has no steps.
  - `steps` (`object[]`, required, up to 50 items): Every step, in any order. Each has a unique `key`, and names the step after it by key in `next`, or in `yes` and `no` for a branch. Null ends the path there.
    - `key` (`string`, required, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `name` (`string`, up to 80 characters)
    - `kind` (`string`, required, one of `"send_email"`)
    - `next` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `templateId` (`string`, required, up to 64 characters)
    - `templateVersion` (`integer`, required, nullable, at least 1)
    - `from` (`object`, required)
      - `email` (`string`, required, up to 320 characters)
      - `name` (`string`, up to 120 characters)
    - `replyTo` (`string`, required, nullable, up to 320 characters)
    - `subject` (`string`, required, nullable, up to 300 characters)
    - `props` (`Record<string, object>`, required)
- `settings` (`object`, required): How it runs. Settings take effect when they are saved, published or not.
  - `timezone` (`string`, required, 1 to 64 characters): The IANA time zone the sending window and waits until a day and time are read in, such as `Europe/London`. `UTC` until you set one.
  - `sendWindow` (`object`, required, nullable): When emails may go out: `days` of the week (0 is Sunday) and `startMinute` to `endMinute` of the day, counted from midnight. An email due outside it waits for the window to open. Null sends at any time.
    - `days` (`integer[]`, required, up to 7 items)
    - `startMinute` (`integer`, required, at least 0, at most 1440)
    - `endMinute` (`integer`, required, at least 0, at most 1440)
  - `reentryDays` (`integer`, required, nullable, at least 0, at most 3650): How many days after a contact finishes before they may enter again. Null lets each contact through once only.
  - `exitOnLeave` (`boolean`, required): Take a contact out when they leave the audience that started the automation. True by default.
  - `listAudienceId` (`string`, required, nullable, up to 64 characters): The audience an unsubscribe from one of these emails is recorded in. A contact who unsubscribed from it is not sent to and cannot be enrolled. Null uses the audience that starts the automation, or the built-in audience of every contact when no audience starts it.
- `problems` (`AutomationProblem[]`, required): What is wrong with the draft, checked at the moment of the read. Empty when it is ready. A publish checks more: that every template can be sent and that the caller may send from every from address.

#### `AutomationAnalytics`

`object`

- `object` (`string`, required, one of `"automation_analytics"`)
- `since` (`string`, required, format `date-time`): Where the window starts.
- `until` (`string`, required, format `date-time`): Where the window ends.
- `totals` (`object`, required): The automations you count, together, over the window.
  - `automations` (`integer`, at least 0): Automations counted.
  - `live` (`integer`, at least 0): Of those, the ones live now.
  - `entered` (`integer`, at least 0): Contacts that entered.
  - `active` (`integer`, at least 0): Contacts in it now, whatever the window.
  - `completed` (`integer`, at least 0): Contacts that reached the end of a path.
  - `exited` (`integer`, at least 0): Contacts that left early.
  - `sent` (`integer`, at least 0): Emails sent.
  - `delivered` (`integer`, at least 0): Emails delivered.
  - `opened` (`integer`, at least 0): Emails opened. Many mail apps hide opens, so read it as a floor.
  - `clicked` (`integer`, at least 0): Emails with a click.
  - `bounced` (`integer`, at least 0): Emails that bounced.
  - `complained` (`integer`, at least 0): Emails marked as spam.
  - `unsubscribed` (`integer`, at least 0): Contacts that unsubscribed from one of its emails.
- `series` (`object[]`, required): One point for each day on which something happened, oldest first, for the automations you count. Each automation counts its days in its own time zone.
  - `date` (`string`, format `date`): The day as `YYYY-MM-DD`, such as `2026-10-11`.
  - `entered` (`integer`, at least 0): Contacts that entered that day.
  - `completed` (`integer`, at least 0): Contacts that completed that day.
  - `exited` (`integer`, at least 0): Contacts that left early that day.
  - `sent` (`integer`, at least 0): Emails sent that day.
- `automations` (`object[]`, required): Every automation of the workspace, most recently changed first, with its own numbers for the window, whatever `automationIds` names.
  - `id` (`string`)
  - `name` (`string`)
  - `status` (`string`, one of `"draft"`, `"live"`, `"paused"`, `"archived"`)
  - `triggerKind` (`string`, nullable, one of `"audience_joined"`, `"form_submitted"`, `"event"`, `"date"`, `"manual"`, `"email_received"`): What starts it. Null while the draft has no trigger.
  - `timezone` (`string`): The IANA time zone it counts its days in, such as `Europe/London`.
  - `entered` (`integer`, at least 0): Contacts that entered.
  - `active` (`integer`, at least 0): Contacts in it now, whatever the window.
  - `completed` (`integer`, at least 0): Contacts that reached the end of a path.
  - `exited` (`integer`, at least 0): Contacts that left early.
  - `sent` (`integer`, at least 0): Emails sent.
  - `delivered` (`integer`, at least 0): Emails delivered.
  - `opened` (`integer`, at least 0): Emails opened. Many mail apps hide opens, so read it as a floor.
  - `clicked` (`integer`, at least 0): Emails with a click.
  - `bounced` (`integer`, at least 0): Emails that bounced.
  - `complained` (`integer`, at least 0): Emails marked as spam.
  - `unsubscribed` (`integer`, at least 0): Contacts that unsubscribed from one of its emails.

#### `AutomationEnrollment`

`object`

- `object` (`string`, required, one of `"automation_enrollment"`)
- `id` (`string`, required): The id of the enrollment.
- `automationId` (`string`, required)
- `version` (`integer`, required, nullable): The published version the contact entered on and stays on. Null when that version is gone.
- `contact` (`object`, required)
  - `id` (`string`, required): The id of the contact.
  - `email` (`string`, required, format `email`)
  - `name` (`string`, required, nullable)
- `status` (`string`, required, one of `"active"`, `"completed"`, `"exited"`): `active` while the contact is in it, `completed` at the end of a path, `exited` when they left early.
- `source` (`string`, required, one of `"trigger"`, `"manual"`, `"api"`): How they got in: `trigger`, by hand in the app (`manual`), or through this API or an app (`api`).
- `stepKey` (`string`, required, nullable): The `key` of the step the contact is at, or was at when they finished. Null before the first step.
- `waiting` (`boolean`, required): True while the contact sits in a wait step.
- `waitingForEvent` (`string`, required, nullable): The event name a wait step is holding out for. Null otherwise.
- `waitingForReply` (`boolean`, required): True while a wait step is holding out for the contact to write back.
- `heldFor` (`string`, required, nullable, one of `"window"`, `"quota"`, `"lane"`, `"retry"`, `"ai_limit"`): Why a step that is due has not run: `window` for the sending window, `quota` for the monthly sends, `lane` when the broadcast lane of the workspace is paused, `retry` after a failure that is tried again, `ai_limit` when the AI actions of the day are used up. Null when nothing holds it.
- `nextRunAt` (`string`, required, nullable, format `date-time`): When the contact moves next. Null once they finished.
- `exitReason` (`string`, required, nullable, one of `"completed"`, `"exit_step"`, `"unsubscribed"`, `"suppressed"`, `"left_audience"`, `"removed"`, `"archived"`, `"failed"`): How it ended: `completed`, an exit step (`exit_step`), `unsubscribed`, `suppressed`, `left_audience`, taken out by a person or a call (`removed`), the automation was `archived`, or a step `failed` for good. Null while active.
- `lastError` (`string`, required, nullable): The last failure of a step, in a sentence.
- `startedAt` (`string`, required, format `date-time`): When the contact entered.
- `finishedAt` (`string`, required, nullable, format `date-time`): When they completed or left. Null while active.
- `updatedAt` (`string`, required, format `date-time`): The last time anything about the enrollment changed.

#### `AutomationEnrollmentDetail`

`object`

- `object` (`string`, required, one of `"automation_enrollment"`)
- `id` (`string`, required): The id of the enrollment.
- `automationId` (`string`, required)
- `version` (`integer`, required, nullable): The published version the contact entered on and stays on. Null when that version is gone.
- `contact` (`object`, required)
  - `id` (`string`, required): The id of the contact.
  - `email` (`string`, required, format `email`)
  - `name` (`string`, required, nullable)
- `status` (`string`, required, one of `"active"`, `"completed"`, `"exited"`): `active` while the contact is in it, `completed` at the end of a path, `exited` when they left early.
- `source` (`string`, required, one of `"trigger"`, `"manual"`, `"api"`): How they got in: `trigger`, by hand in the app (`manual`), or through this API or an app (`api`).
- `stepKey` (`string`, required, nullable): The `key` of the step the contact is at, or was at when they finished. Null before the first step.
- `waiting` (`boolean`, required): True while the contact sits in a wait step.
- `waitingForEvent` (`string`, required, nullable): The event name a wait step is holding out for. Null otherwise.
- `waitingForReply` (`boolean`, required): True while a wait step is holding out for the contact to write back.
- `heldFor` (`string`, required, nullable, one of `"window"`, `"quota"`, `"lane"`, `"retry"`, `"ai_limit"`): Why a step that is due has not run: `window` for the sending window, `quota` for the monthly sends, `lane` when the broadcast lane of the workspace is paused, `retry` after a failure that is tried again, `ai_limit` when the AI actions of the day are used up. Null when nothing holds it.
- `nextRunAt` (`string`, required, nullable, format `date-time`): When the contact moves next. Null once they finished.
- `exitReason` (`string`, required, nullable, one of `"completed"`, `"exit_step"`, `"unsubscribed"`, `"suppressed"`, `"left_audience"`, `"removed"`, `"archived"`, `"failed"`): How it ended: `completed`, an exit step (`exit_step`), `unsubscribed`, `suppressed`, `left_audience`, taken out by a person or a call (`removed`), the automation was `archived`, or a step `failed` for good. Null while active.
- `lastError` (`string`, required, nullable): The last failure of a step, in a sentence.
- `startedAt` (`string`, required, format `date-time`): When the contact entered.
- `finishedAt` (`string`, required, nullable, format `date-time`): When they completed or left. Null while active.
- `updatedAt` (`string`, required, format `date-time`): The last time anything about the enrollment changed.
- `runs` (`object[]`, required): What each step did for the contact, oldest first.
  - `id` (`string`, required)
  - `stepKey` (`string`, required): The `key` of the step that ran.
  - `kind` (`string`, required, one of `"send_email"`, `"wait"`, `"branch"`, `"add_to_audience"`, `"remove_from_audience"`, `"update_field"`, `"webhook"`, `"exit"`, `"reply"`)
  - `outcome` (`string`, required, one of `"sent"`, `"skipped"`, `"waited"`, `"yes"`, `"no"`, `"added"`, `"removed"`, `"updated"`, `"called"`, `"exited"`, `"failed"`): What happened: an email `sent`, a wait `waited` out, a branch answered `yes` or `no`, the contact `added` to or `removed` from an audience, a field `updated`, a webhook `called`, the path `exited`, the step `skipped`, or it `failed`.
  - `emailId` (`string`, required, nullable): The email a send step sent, as `GET /emails` lists it. Null for every other step.
  - `detail` (`string`, required, nullable): Why a step was skipped or failed, or how a wait ended.
  - `createdAt` (`string`, required, format `date-time`): When the step ran.

#### `AutomationEnrollmentList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`AutomationEnrollment[]`)
- `hasMore` (`boolean`): True when another page follows. Pass `nextCursor` back as `cursor` to read it.
- `nextCursor` (`string`, nullable): The id of the last row on this page, or null on the last page.
- `automationId` (`string`): The automation the enrollments belong to.

#### `AutomationList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`AutomationSummary[]`)
- `hasMore` (`boolean`): True when another page follows. Pass `nextCursor` back as `cursor` to read it.
- `nextCursor` (`string`, nullable): The id of the last row on this page, or null on the last page.

#### `AutomationProblem`

`object`

- `code` (`string`, required, one of `"trigger_missing"`, `"trigger_audience_missing"`, `"trigger_form_missing"`, `"trigger_event_invalid"`, `"trigger_filter_invalid"`, `"no_steps"`, `"too_many_steps"`, `"too_deep"`, `"duplicate_key"`, `"unknown_target"`, `"shared_step"`, `"unreachable"`, `"template_missing"`, `"sender_missing"`, `"sender_invalid"`, `"reply_to_invalid"`, `"wait_invalid"`, `"wait_too_long"`, `"wait_days_missing"`, `"event_name_invalid"`, `"condition_step_missing"`, `"audience_missing"`, `"field_invalid"`, `"value_missing"`, `"webhook_missing"`, `"list_audience_missing"`, `"timezone_invalid"`, `"window_invalid"`, `"template_not_found"`, `"template_not_published"`, `"template_unsubscribe_missing"`, `"template_prop_missing"`, `"template_name_required"`, `"sender_refused"`, `"audience_not_found"`, `"audience_is_everyone"`, `"form_not_found"`, `"webhook_not_found"`, `"opens_unreliable"`, `"trigger_address_invalid"`, `"address_not_found"`, `"domain_not_found"`, `"thread_not_found"`, `"trigger_scope_refused"`, `"question_missing"`, `"reply_missing"`, `"email_missing"`, `"reply_wait_missing"`, `"reentry_once"`): What is wrong, for a program to branch on.
- `path` (`string`, required): The field at fault, dotted, such as `definition.steps.2.templateId` or `settings.timezone`.
- `stepKey` (`string`, required, nullable): The `key` of the step at fault. Null when it is the trigger or a setting.
- `message` (`string`, required): The problem in a sentence a person can act on.
- `blocking` (`boolean`, required): True when it stops a publish. False for a warning, such as a branch on opens.

#### `AutomationRun`

`object`

- `object` (`string`, required, one of `"automation_run"`)
- `id` (`string`, required): The id of the entry: the id of the step run for `step`, or the enrollment id followed by `:entered` or `:finished`. Pass the last one back as `cursor` to read on.
- `automationId` (`string`, required)
- `enrollmentId` (`string`, required): The contact's way through the automation, as `GET /automations/{id}/enrollments/{enrollmentId}` returns it.
- `contact` (`object`, required)
  - `id` (`string`, required): The id of the contact.
  - `email` (`string`, required, format `email`)
  - `name` (`string`, required, nullable)
- `event` (`string`, required, one of `"entered"`, `"step"`, `"completed"`, `"exited"`): What happened: the contact `entered`, a `step` ran for them, or they `completed` the automation or `exited` it early.
- `stepKey` (`string`, required, nullable): For `step`, the `key` of the step that ran. For `completed` and `exited`, the step the contact was at. Null for `entered`.
- `kind` (`string`, required, nullable, one of `"send_email"`, `"wait"`, `"branch"`, `"add_to_audience"`, `"remove_from_audience"`, `"update_field"`, `"webhook"`, `"exit"`, `"reply"`): The kind of the step, for `step`. Null otherwise.
- `outcome` (`string`, required, nullable, one of `"sent"`, `"skipped"`, `"waited"`, `"yes"`, `"no"`, `"added"`, `"removed"`, `"updated"`, `"called"`, `"exited"`, `"failed"`): For `step`, what the step did, as the `runs` of an enrollment say it. Null otherwise.
- `source` (`string`, required, nullable, one of `"trigger"`, `"manual"`, `"api"`): For `entered`, how the contact got in. Null otherwise.
- `exitReason` (`string`, required, nullable, one of `"completed"`, `"exit_step"`, `"unsubscribed"`, `"suppressed"`, `"left_audience"`, `"removed"`, `"archived"`, `"failed"`): For `completed` and `exited`, why the contact finished. Null otherwise.
- `emailId` (`string`, required, nullable): The email a send step sent, as `GET /emails` lists it. Null otherwise.
- `detail` (`string`, required, nullable): Why a step was skipped or failed, how a wait ended, or the last error of a contact that left because of one.
- `at` (`string`, required, format `date-time`): When it happened.

#### `AutomationRunList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`AutomationRun[]`)
- `hasMore` (`boolean`): True when another page follows. Pass `nextCursor` back as `cursor` to read it.
- `nextCursor` (`string`, nullable): The id of the last row on this page, or null on the last page.
- `automationId` (`string`): The automation the entries belong to.

#### `AutomationStarter`

`object`

- `object` (`string`, required, one of `"automation_starter"`)
- `slug` (`string`, required): What `POST /automations` takes as `starter`.
- `name` (`string`, required)
- `description` (`string`, required): What the starter is for, in a sentence.
- `definition` (`object`, required): What starts an automation and what it then does. Paths never join or loop: every step is reached from exactly one place, and a definition holds at most 50 steps.
  - `trigger` (`object`, required, nullable): What puts a contact into the automation. Null in a draft that has none yet, and a draft cannot be published without one.
    - `kind` (`string`, required, one of `"audience_joined"`)
    - `audienceId` (`string`, required, up to 64 characters)
    - `includeImported` (`boolean`, required)
  - `entry` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`): The `key` of the first step, or null while the draft has no steps.
  - `steps` (`object[]`, required, up to 50 items): Every step, in any order. Each has a unique `key`, and names the step after it by key in `next`, or in `yes` and `no` for a branch. Null ends the path there.
    - `key` (`string`, required, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `name` (`string`, up to 80 characters)
    - `kind` (`string`, required, one of `"send_email"`)
    - `next` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `templateId` (`string`, required, up to 64 characters)
    - `templateVersion` (`integer`, required, nullable, at least 1)
    - `from` (`object`, required)
      - `email` (`string`, required, up to 320 characters)
      - `name` (`string`, up to 120 characters)
    - `replyTo` (`string`, required, nullable, up to 320 characters)
    - `subject` (`string`, required, nullable, up to 300 characters)
    - `props` (`Record<string, object>`, required)

#### `AutomationStarterList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`AutomationStarter[]`)

#### `AutomationStats`

`object`

- `object` (`string`, required, one of `"automation_stats"`)
- `automationId` (`string`, required)
- `timezone` (`string`, required): The IANA time zone the days of `series` are in, such as `Europe/London`. It is the `timezone` of the automation settings.
- `since` (`string`, required, format `date-time`): Where the window starts.
- `until` (`string`, required, format `date-time`): Where the window ends.
- `totals` (`object`, required): The whole automation over the window.
  - `entered` (`integer`, at least 0): Contacts that entered.
  - `active` (`integer`, at least 0): Contacts in it now, whatever the window.
  - `completed` (`integer`, at least 0): Contacts that reached the end of a path.
  - `exited` (`integer`, at least 0): Contacts that left early.
  - `sent` (`integer`, at least 0): Emails sent.
  - `delivered` (`integer`, at least 0): Emails delivered.
  - `opened` (`integer`, at least 0): Emails opened. Many mail apps hide opens, so read it as a floor.
  - `clicked` (`integer`, at least 0): Emails with a click.
  - `bounced` (`integer`, at least 0): Emails that bounced.
  - `complained` (`integer`, at least 0): Emails marked as spam.
  - `unsubscribed` (`integer`, at least 0): Contacts that unsubscribed from one of its emails.
- `steps` (`object[]`, required): The same numbers for each step.
  - `stepKey` (`string`): The `key` of the step.
  - `kind` (`string`, one of `"send_email"`, `"wait"`, `"branch"`, `"add_to_audience"`, `"remove_from_audience"`, `"update_field"`, `"webhook"`, `"exit"`, `"reply"`)
  - `entered` (`integer`, at least 0): Contacts that reached the step.
  - `waiting` (`integer`, at least 0): Contacts sitting at the step now.
  - `completed` (`integer`, at least 0): Contacts whose path ended at the step.
  - `exited` (`integer`, at least 0): Contacts that left early at the step.
  - `sent` (`integer`, at least 0): Emails the step sent.
  - `skipped` (`integer`, at least 0): Times the step did nothing, such as an address that cannot receive mail.
  - `failed` (`integer`, at least 0): Times the step failed for good.
  - `yes` (`integer`, at least 0): Contacts a branch sent down yes.
  - `no` (`integer`, at least 0): Contacts a branch sent down no.
  - `delivered` (`integer`, at least 0): Emails of the step that were delivered.
  - `opened` (`integer`, at least 0): Emails of the step that were opened.
  - `clicked` (`integer`, at least 0): Emails of the step with a click.
  - `bounced` (`integer`, at least 0): Emails of the step that bounced.
  - `complained` (`integer`, at least 0): Emails of the step marked as spam.
  - `unsubscribed` (`integer`, at least 0): Contacts that unsubscribed from an email of the step.
- `series` (`object[]`, required): One point for each day in the window on which something happened, oldest first. A day is a calendar day in `timezone`, the time zone of the automation.
  - `day` (`string`, format `date-time`): The instant that day starts in `timezone`.
  - `date` (`string`, format `date`): The day as `YYYY-MM-DD` in `timezone`, such as `2026-10-11`.
  - `entered` (`integer`, at least 0): Contacts that entered that day.
  - `completed` (`integer`, at least 0): Contacts that completed that day.
  - `exited` (`integer`, at least 0): Contacts that left early that day.
  - `sent` (`integer`, at least 0): Emails sent that day.

#### `AutomationSummary`

`object`

- `object` (`string`, required, one of `"automation"`)
- `id` (`string`, required): The id of the automation. It never changes.
- `name` (`string`, required): What the workspace calls it. Contacts never see it.
- `description` (`string`, required, nullable): A note for the workspace.
- `status` (`string`, required, one of `"draft"`, `"live"`, `"paused"`, `"archived"`): `draft` until the first publish. `live` takes contacts in and moves them along. `paused` takes nobody in and holds everyone where they are. `archived` is retired for good and everyone in it has left.
- `triggerKind` (`string`, required, nullable, one of `"audience_joined"`, `"form_submitted"`, `"event"`, `"date"`, `"manual"`, `"email_received"`): What starts the draft, or null while it has no trigger.
- `stepCount` (`integer`, required, at least 0): How many steps the draft holds.
- `emailCount` (`integer`, required, at least 0): How many of those steps send an email.
- `hasUnpublishedChanges` (`boolean`, required): True when the draft differs from the version that is running.
- `publishedVersion` (`integer`, required, nullable): The number of the version that is running. Null until the first publish.
- `pausedReason` (`string`, required, nullable, one of `"manual"`, `"sender_refused"`, `"key_revoked"`, `"template_unavailable"`, `"audience_missing"`, `"plan_limit"`): Why it is paused. `manual` is a person. The others are Nextmail stopping it: `sender_refused` when its from address can no longer send, `key_revoked` when the API key that published it was revoked, expired or turned off, `template_unavailable` when one of its templates can no longer be sent, `audience_missing` when an audience it depends on is gone, and `plan_limit` when the plan no longer covers this many live automations. Null while it is not paused.
- `lastError` (`string`, required, nullable): What went wrong the last time Nextmail paused it, in a sentence. Null otherwise.
- `counts` (`object`, required): Contacts, counted at the moment of the read.
  - `active` (`integer`, required, at least 0): In the automation now.
  - `completed` (`integer`, required, at least 0): Reached the end of a path, in all its time.
  - `exited` (`integer`, required, at least 0): Left before the end, in all its time.
- `createdBy` (`string`, required, nullable): The user id of the person who made it. Null when that account is gone.
- `publishedAt` (`string`, required, nullable, format `date-time`): The last publish. Null until the first.
- `pausedAt` (`string`, required, nullable, format `date-time`): When it was paused. Null while it is not.
- `archivedAt` (`string`, required, nullable, format `date-time`): When it was archived. Null otherwise.
- `createdAt` (`string`, required, format `date-time`): When it was made.
- `updatedAt` (`string`, required, format `date-time`): The last save. Send it back as `expectedUpdatedAt` so a change never overwrites one you have not seen.

#### `AutomationTest`

`object`

- `object` (`string`, required, one of `"automation_test"`)
- `automationId` (`string`, required)
- `emailId` (`string`, required): The test email, as `GET /emails/{id}` returns it.
- `to` (`string`, required, format `email`): Where it went.
- `stepKey` (`string`, required): The step that was sent.

#### `AutomationVersion`

`object`

- `object` (`string`, required, one of `"automation_version"`)
- `id` (`string`, required)
- `automationId` (`string`, required)
- `version` (`integer`, required, at least 1): Counts up from 1 with each publish that changed the definition.
- `definition` (`object`, required): What starts an automation and what it then does. Paths never join or loop: every step is reached from exactly one place, and a definition holds at most 50 steps.
  - `trigger` (`object`, required, nullable): What puts a contact into the automation. Null in a draft that has none yet, and a draft cannot be published without one.
    - `kind` (`string`, required, one of `"audience_joined"`)
    - `audienceId` (`string`, required, up to 64 characters)
    - `includeImported` (`boolean`, required)
  - `entry` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`): The `key` of the first step, or null while the draft has no steps.
  - `steps` (`object[]`, required, up to 50 items): Every step, in any order. Each has a unique `key`, and names the step after it by key in `next`, or in `yes` and `no` for a branch. Null ends the path there.
    - `key` (`string`, required, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `name` (`string`, up to 80 characters)
    - `kind` (`string`, required, one of `"send_email"`)
    - `next` (`string`, required, nullable, pattern `^[a-z][a-z0-9]{2,23}$`)
    - `templateId` (`string`, required, up to 64 characters)
    - `templateVersion` (`integer`, required, nullable, at least 1)
    - `from` (`object`, required)
      - `email` (`string`, required, up to 320 characters)
      - `name` (`string`, up to 120 characters)
    - `replyTo` (`string`, required, nullable, up to 320 characters)
    - `subject` (`string`, required, nullable, up to 300 characters)
    - `props` (`Record<string, object>`, required)
- `current` (`boolean`, required): True for the version that is running.
- `createdBy` (`string`, required, nullable): The user id of whoever published it.
- `createdAt` (`string`, required, format `date-time`): When it was published.

#### `AutomationVersionList`

`object`

- `object` (`string`, one of `"list"`)
- `data` (`AutomationVersion[]`)

#### `DeletedAutomation`

`object`

- `object` (`string`, required, one of `"automation"`)
- `id` (`string`, required)
- `deleted` (`boolean`, required, one of `true`)
