---
title: "openemail automations"
description: "Every command in this namespace, with its arguments, flags and examples."
url: "https://openemail.uk/docs/cli/reference/automations"
area: "CLI"
category: "Reference"
---

# openemail automations

Every command in this namespace, with its arguments, flags and examples.

## Commands

### `openemail automations list`

List one page of the automations in the workspace

```bash
openemail automations list [flags]
```

Returns one page of the automations the caller can reach, the most recently saved first, without their definitions or settings. Paging is keyset: `--limit` takes 1 to 100 and defaults to 50, and `nextCursor` goes back as `--cursor` while `hasMore` is true.

Each automation carries its `status`, `triggerKind`, how many steps and emails the draft holds, `hasUnpublishedChanges`, `publishedVersion` and `counts`: the contacts in it now, and the ones that completed or left in all its time, counted at the moment of the read. A paused automation says why in `pausedReason`.

Read one with `get` for the draft `definition`, the `published` one, the `settings` and the `problems` that would stop a publish.

Add `--all` to walk every page: a table on a terminal, one JSON object per line when piped or with `--ndjson`, and one `{ items, hasMore, nextCursor }` document with `--json`. `--max <n>` stops after that many items.

- Scopes: `automations:read`.
- Needs a sign-in.
- Aliases: `ls`.

**Flags**

- `--status <value>`: Only automations in this state: `draft`, `live`, `paused` or `archived`.
- `--limit <n>` (default `50`): Rows per page, a whole number from 1 to 100. The server defaults to 50.
- `--cursor <value>`: The `nextCursor` from the previous page, passed back exactly as it came. One that names no automation is a 400 `invalid_cursor`.
- `--all`: Fetch every page and stream the items as they arrive.
- `--max <n>`: Stop after this many items. Implies `--all`.
- `--ndjson`: Print every item as one JSON object per line. Implies `--all`

**Examples**

```bash
openemail automations list
```

With optional flags

```bash
openemail automations list --status live
```

Walk every page and stop after 100 items

```bash
openemail automations list --all --max 100
```

One JSON object per line when piped

```bash
openemail automations list --all > automations.ndjson
```

Also available in: API [`GET /automations`](https://openemail.uk/docs/api/reference/automations#get-automations); TypeScript [`automations.list()`](https://openemail.uk/docs/sdk/reference/automations#list); Python [`automations.list()`](https://openemail.uk/docs/python/reference/automations#list); Ruby [`automations.list`](https://openemail.uk/docs/ruby/reference/automations#list); PHP [`automations->list`](https://openemail.uk/docs/php/reference/automations#list); Go [`Automations.List`](https://openemail.uk/docs/go/reference/automations#list); Java [`automations().list`](https://openemail.uk/docs/java/reference/automations#list); C# [`Automations.ListAsync`](https://openemail.uk/docs/csharp/reference/automations#list).

### `openemail automations create`

Create an automation as a draft

```bash
openemail automations create --name <value> [flags]
openemail automations create --data <json|@file|-> [flags]
```

Makes a draft automation and returns it whole, in the shape `get` returns. Its trigger and steps come from `definition` when you send one, from the starter named in `starter` when you do not, and otherwise the draft starts empty. `settings` changes any of the defaults.

A draft may be incomplete: `problems` in the answer lists what is still missing, such as a template or a from address a starter leaves for you. Nothing runs until `publish`, which needs a complete draft and `emails:send`.

- Scopes: `automations:write`.
- Needs a sign-in.
- Aliases: `new`, `add`.

**Flags**

- `--name <value>`: What the workspace calls the automation, trimmed, 1 to 120 characters. Contacts never see it, and it need not be unique. Required, here or in `--data`.
- `--description <value>`: A note for the workspace, at most 500 characters. Contacts never see it.
- `--starter <value>`: Begin from a starter, by the `slug` `listStarters` returns: `welcome-series`, `trial-follow-up`, `birthday` or `win-back`. Ignored when `definition` is sent. An unknown slug is 422 `invalid_automation`.
- `--definition <json|@file|->`: The trigger and the steps, in the shape `get` returns as `definition`. `trigger` says what starts the automation: `audience_joined` with `audienceId` and `includeImported`, `form_submitted` with `formId`, `event` with `eventName` and `filters`, `date` with `field`, `audienceId` and `offsetDays`, or `manual`. `entry` is the key of the first step, and `steps` holds every step: `send_email`, `wait`, `branch`, `add_to_audience`, `remove_from_audience`, `update_field`, `webhook` or `exit`. Each step has a unique `key` of 3 to 24 lowercase letters and digits starting with a letter, and names the next step by key in `next`, or in `yes` and `no` for a branch. Null ends the path. Paths never join or loop, and a definition holds at most 50 steps. Leave it out to use `starter` or an empty draft. JSON shaped as `AutomationDefinition`, inline or from a file with @path.
- `--settings-timezone <value>`: The IANA time zone the sending window and waits until a day and time are read in, such as `Europe/London`. Defaults to `UTC`.
- `--settings-send-window <json|@file|->`: When emails may go out: `days` of the week, where 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, the default, sends at any time. JSON shaped as `AutomationSendWindow | null`, inline or from a file with @path.
- `--settings-reentry-days <n>`: How many days after a contact finishes before they may enter again, from 1 to 3650. Null, the default, lets each contact through once only.
- `--settings-exit-on-leave`: Take a contact out when they leave the audience that started the automation. Defaults to true.
- `--settings-list-audience-id <value>`: The audience an unsubscribe from one of these emails is recorded in. Null, the default, uses the audience that starts the automation, or the built-in audience of every contact when no audience starts it. An id that is not an audience of the workspace is 422 `invalid_automation`.
- `--data <json|@file|->`: The whole `body` as JSON, inline, from a file with @path, or - for standard input. Flags override its keys.

**Examples**

The required values only

```bash
openemail automations create --name 'Welcome series'
```

With optional flags

```bash
openemail automations create --name 'Welcome series' --starter welcome-series --settings-timezone Europe/London
```

Read the whole body from a JSON file

```bash
openemail automations create --data @automation.json
```

Also available in: API [`POST /automations`](https://openemail.uk/docs/api/reference/automations#post-automations); TypeScript [`automations.create()`](https://openemail.uk/docs/sdk/reference/automations#create); Python [`automations.create()`](https://openemail.uk/docs/python/reference/automations#create); Ruby [`automations.create`](https://openemail.uk/docs/ruby/reference/automations#create); PHP [`automations->create`](https://openemail.uk/docs/php/reference/automations#create); Go [`Automations.Create`](https://openemail.uk/docs/go/reference/automations#create); Java [`automations().create`](https://openemail.uk/docs/java/reference/automations#create); C# [`Automations.CreateAsync`](https://openemail.uk/docs/csharp/reference/automations#create).

### `openemail automations list-starters`

List the ready-made automations to start from

```bash
openemail automations list-starters [flags]
```

Returns the starting points the app offers when somebody makes an automation: a welcome series, a trial follow-up, a birthday note and a win-back. Each comes with its whole `definition`, so you can read it, change it and send it to `create`, or pass its `slug` to `create` as `starter`.

A starter leaves the audience, the templates and the from address as empty strings for you to fill in. The list is the same for every workspace and is not paginated.

- Scopes: `automations:read`.
- Needs a sign-in.

**Examples**

```bash
openemail automations list-starters
```

Print the raw JSON

```bash
openemail automations list-starters --json
```

Also available in: API [`GET /automations/starters`](https://openemail.uk/docs/api/reference/automations#get-automations-starters); TypeScript [`automations.listStarters()`](https://openemail.uk/docs/sdk/reference/automations#listStarters); Python [`automations.list_starters()`](https://openemail.uk/docs/python/reference/automations#listStarters); Ruby [`automations.list_starters`](https://openemail.uk/docs/ruby/reference/automations#listStarters); PHP [`automations->listStarters`](https://openemail.uk/docs/php/reference/automations#listStarters); Go [`Automations.ListStarters`](https://openemail.uk/docs/go/reference/automations#listStarters); Java [`automations().listStarters`](https://openemail.uk/docs/java/reference/automations#listStarters); C# [`Automations.ListStartersAsync`](https://openemail.uk/docs/csharp/reference/automations#listStarters).

### `openemail automations get`

Retrieve an automation with its definition and settings

```bash
openemail automations get <id> [flags]
```

Returns the whole automation: the draft `definition` you edit, `published`, the definition of the version that is running, `settings`, fresh `counts` and `problems`.

`problems` is what is wrong with the draft at the moment of the read, each with a `code`, the `path` of the field, the `stepKey`, a `message` and `blocking`, which is false for a warning. An empty list means the draft is ready, though `publish` checks more: that every template can be sent and that the caller may send from every from address.

- Scopes: `automations:read`.
- Needs a sign-in.
- Aliases: `show`, `view`.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations get aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Print the raw JSON

```bash
openemail automations get aut_5c1e9a7b3d2f48e6a0b4c7d1 --json
```

Also available in: API [`GET /automations/{id}`](https://openemail.uk/docs/api/reference/automations#get-automations-id); TypeScript [`automations.get()`](https://openemail.uk/docs/sdk/reference/automations#get); Python [`automations.get()`](https://openemail.uk/docs/python/reference/automations#get); Ruby [`automations.get`](https://openemail.uk/docs/ruby/reference/automations#get); PHP [`automations->get`](https://openemail.uk/docs/php/reference/automations#get); Go [`Automations.Get`](https://openemail.uk/docs/go/reference/automations#get); Java [`automations().get`](https://openemail.uk/docs/java/reference/automations#get); C# [`Automations.GetAsync`](https://openemail.uk/docs/csharp/reference/automations#get).

### `openemail automations update`

Change the draft, the settings or the name of an automation

```bash
openemail automations update <id> [flags]
```

A partial update that returns the automation whole. `definition` replaces the draft, and a live automation keeps running its published version until you `publish` again, so an edit never changes the path of a contact who is halfway through. `settings` is merged field by field and takes effect at once.

Read the automation, change it and send `--expected-updated-at` with the `updatedAt` you read. If someone saved it in between, the call is refused with 409 `version_conflict` instead of writing over their change.

- Scopes: `automations:write`.
- Needs a sign-in.
- Aliases: `edit`.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Flags**

- `--name <value>`: New name, trimmed, 1 to 120 characters.
- `--description <value>`: New note, at most 500 characters. Null clears it.
- `--definition <json|@file|->`: The new draft, whole. The trigger and the steps, in the shape `get` returns as `definition`. `trigger` says what starts the automation: `audience_joined` with `audienceId` and `includeImported`, `form_submitted` with `formId`, `event` with `eventName` and `filters`, `date` with `field`, `audienceId` and `offsetDays`, or `manual`. `entry` is the key of the first step, and `steps` holds every step: `send_email`, `wait`, `branch`, `add_to_audience`, `remove_from_audience`, `update_field`, `webhook` or `exit`. Each step has a unique `key` of 3 to 24 lowercase letters and digits starting with a letter, and names the next step by key in `next`, or in `yes` and `no` for a branch. Null ends the path. Paths never join or loop, and a definition holds at most 50 steps. JSON shaped as `AutomationDefinition`, inline or from a file with @path.
- `--settings-timezone <value>`: The IANA time zone the sending window and waits until a day and time are read in, such as `Europe/London`. Defaults to `UTC`.
- `--settings-send-window <json|@file|->`: When emails may go out: `days` of the week, where 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, the default, sends at any time. JSON shaped as `AutomationSendWindow | null`, inline or from a file with @path.
- `--settings-reentry-days <n>`: How many days after a contact finishes before they may enter again, from 1 to 3650. Null, the default, lets each contact through once only.
- `--settings-exit-on-leave`: Take a contact out when they leave the audience that started the automation. Defaults to true.
- `--settings-list-audience-id <value>`: The audience an unsubscribe from one of these emails is recorded in. Null, the default, uses the audience that starts the automation, or the built-in audience of every contact when no audience starts it. An id that is not an audience of the workspace is 422 `invalid_automation`.
- `--expected-updated-at <value>`: The `updatedAt` you read, as an ISO 8601 instant. When the automation was saved since, the call is refused with 409 `version_conflict` and nothing is written.
- `--data <json|@file|->`: The whole `patch` as JSON, inline, from a file with @path, or - for standard input. Flags override its keys.

**Examples**

```bash
openemail automations update aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Print the raw JSON

```bash
openemail automations update aut_5c1e9a7b3d2f48e6a0b4c7d1 --json
```

Also available in: API [`PATCH /automations/{id}`](https://openemail.uk/docs/api/reference/automations#patch-automations-id); TypeScript [`automations.update()`](https://openemail.uk/docs/sdk/reference/automations#update); Python [`automations.update()`](https://openemail.uk/docs/python/reference/automations#update); Ruby [`automations.update`](https://openemail.uk/docs/ruby/reference/automations#update); PHP [`automations->update`](https://openemail.uk/docs/php/reference/automations#update); Go [`Automations.Update`](https://openemail.uk/docs/go/reference/automations#update); Java [`automations().update`](https://openemail.uk/docs/java/reference/automations#update); C# [`Automations.UpdateAsync`](https://openemail.uk/docs/csharp/reference/automations#update).

### `openemail automations delete`

Delete an automation with its versions and history

```bash
openemail automations delete <id> [flags]
```

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 `emails.list`.

There is no undo. To retire an automation and keep its history, use `archive`.

- Scopes: `automations:write`.
- Needs a sign-in.
- Asks you to confirm.
- Aliases: `rm`, `del`, `remove`.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations delete aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Skip the confirmation, for scripts

```bash
openemail automations delete aut_5c1e9a7b3d2f48e6a0b4c7d1 --yes
```

Also available in: API [`DELETE /automations/{id}`](https://openemail.uk/docs/api/reference/automations#delete-automations-id); TypeScript [`automations.delete()`](https://openemail.uk/docs/sdk/reference/automations#delete); Python [`automations.delete()`](https://openemail.uk/docs/python/reference/automations#delete); Ruby [`automations.delete`](https://openemail.uk/docs/ruby/reference/automations#delete); PHP [`automations->delete`](https://openemail.uk/docs/php/reference/automations#delete); Go [`Automations.Delete`](https://openemail.uk/docs/go/reference/automations#delete); Java [`automations().delete`](https://openemail.uk/docs/java/reference/automations#delete); C# [`Automations.DeleteAsync`](https://openemail.uk/docs/csharp/reference/automations#delete).

### `openemail automations publish`

Publish the draft and turn the automation on

```bash
openemail automations publish <id> [flags]
```

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. It takes no body.

The draft has to be complete: a trigger, at least one step, every email with a published template that declares `unsubscribeUrl` and a from address the caller may send as, and every audience, form and webhook it names still there. Anything else is 422 `invalid_automation`, and the error's `body` lists every problem that blocks it under `error.problems`.

The automation sends as whoever published it. When that API key is revoked, expires or is turned off, the automation pauses itself with `pausedReason` `key_revoked`.

- Scopes: `automations:write`, `emails:send`.
- Needs a sign-in.
- Asks you to confirm.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations publish aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Skip the confirmation, for scripts

```bash
openemail automations publish aut_5c1e9a7b3d2f48e6a0b4c7d1 --yes
```

Also available in: API [`POST /automations/{id}/publish`](https://openemail.uk/docs/api/reference/automations#post-automations-id-publish); TypeScript [`automations.publish()`](https://openemail.uk/docs/sdk/reference/automations#publish); Python [`automations.publish()`](https://openemail.uk/docs/python/reference/automations#publish); Ruby [`automations.publish`](https://openemail.uk/docs/ruby/reference/automations#publish); PHP [`automations->publish`](https://openemail.uk/docs/php/reference/automations#publish); Go [`Automations.Publish`](https://openemail.uk/docs/go/reference/automations#publish); Java [`automations().publish`](https://openemail.uk/docs/java/reference/automations#publish); C# [`Automations.PublishAsync`](https://openemail.uk/docs/csharp/reference/automations#publish).

### `openemail automations pause`

Stop a live automation without losing anybody

```bash
openemail automations pause <id> [flags]
```

Stops a live automation. Nobody new enters, and everyone in it stays where they are and moves on when it is resumed. The `automation.paused` webhook event fires. Pausing a paused automation changes nothing. It takes no body.

- Scopes: `automations:write`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations pause aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Print the raw JSON

```bash
openemail automations pause aut_5c1e9a7b3d2f48e6a0b4c7d1 --json
```

Also available in: API [`POST /automations/{id}/pause`](https://openemail.uk/docs/api/reference/automations#post-automations-id-pause); TypeScript [`automations.pause()`](https://openemail.uk/docs/sdk/reference/automations#pause); Python [`automations.pause()`](https://openemail.uk/docs/python/reference/automations#pause); Ruby [`automations.pause`](https://openemail.uk/docs/ruby/reference/automations#pause); PHP [`automations->pause`](https://openemail.uk/docs/php/reference/automations#pause); Go [`Automations.Pause`](https://openemail.uk/docs/go/reference/automations#pause); Java [`automations().pause`](https://openemail.uk/docs/java/reference/automations#pause); C# [`Automations.PauseAsync`](https://openemail.uk/docs/csharp/reference/automations#pause).

### `openemail automations resume`

Turn a paused automation back on

```bash
openemail automations resume <id> [flags]
```

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. Resuming a live automation changes nothing. It takes no body.

The published version is checked again first, exactly as `publish` checks a draft. An automation OpenEmail paused, because its from address, its templates or an audience went away, stays paused with 422 `invalid_automation` until what stopped it is fixed.

- Scopes: `automations:write`, `emails:send`.
- Needs a sign-in.
- Asks you to confirm.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations resume aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Skip the confirmation, for scripts

```bash
openemail automations resume aut_5c1e9a7b3d2f48e6a0b4c7d1 --yes
```

Also available in: API [`POST /automations/{id}/resume`](https://openemail.uk/docs/api/reference/automations#post-automations-id-resume); TypeScript [`automations.resume()`](https://openemail.uk/docs/sdk/reference/automations#resume); Python [`automations.resume()`](https://openemail.uk/docs/python/reference/automations#resume); Ruby [`automations.resume`](https://openemail.uk/docs/ruby/reference/automations#resume); PHP [`automations->resume`](https://openemail.uk/docs/php/reference/automations#resume); Go [`Automations.Resume`](https://openemail.uk/docs/go/reference/automations#resume); Java [`automations().resume`](https://openemail.uk/docs/java/reference/automations#resume); C# [`Automations.ResumeAsync`](https://openemail.uk/docs/csharp/reference/automations#resume).

### `openemail automations archive`

Retire an automation for good and keep its history

```bash
openemail automations archive <id> [flags]
```

Retires an automation. 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. It takes no body.

An automation with many contacts in it empties in the background over the next minutes. To start again from its steps, use `duplicate`.

- Scopes: `automations:write`.
- Needs a sign-in.
- Asks you to confirm.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations archive aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Skip the confirmation, for scripts

```bash
openemail automations archive aut_5c1e9a7b3d2f48e6a0b4c7d1 --yes
```

Also available in: API [`POST /automations/{id}/archive`](https://openemail.uk/docs/api/reference/automations#post-automations-id-archive); TypeScript [`automations.archive()`](https://openemail.uk/docs/sdk/reference/automations#archive); Python [`automations.archive()`](https://openemail.uk/docs/python/reference/automations#archive); Ruby [`automations.archive`](https://openemail.uk/docs/ruby/reference/automations#archive); PHP [`automations->archive`](https://openemail.uk/docs/php/reference/automations#archive); Go [`Automations.Archive`](https://openemail.uk/docs/go/reference/automations#archive); Java [`automations().archive`](https://openemail.uk/docs/java/reference/automations#archive); C# [`Automations.ArchiveAsync`](https://openemail.uk/docs/csharp/reference/automations#archive).

### `openemail automations duplicate`

Copy an automation into a new draft

```bash
openemail automations duplicate <id> [flags]
```

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, and it works on an archived automation too. It takes no body.

- Scopes: `automations:write`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations duplicate aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Print the raw JSON

```bash
openemail automations duplicate aut_5c1e9a7b3d2f48e6a0b4c7d1 --json
```

Also available in: API [`POST /automations/{id}/duplicate`](https://openemail.uk/docs/api/reference/automations#post-automations-id-duplicate); TypeScript [`automations.duplicate()`](https://openemail.uk/docs/sdk/reference/automations#duplicate); Python [`automations.duplicate()`](https://openemail.uk/docs/python/reference/automations#duplicate); Ruby [`automations.duplicate`](https://openemail.uk/docs/ruby/reference/automations#duplicate); PHP [`automations->duplicate`](https://openemail.uk/docs/php/reference/automations#duplicate); Go [`Automations.Duplicate`](https://openemail.uk/docs/go/reference/automations#duplicate); Java [`automations().duplicate`](https://openemail.uk/docs/java/reference/automations#duplicate); C# [`Automations.DuplicateAsync`](https://openemail.uk/docs/csharp/reference/automations#duplicate).

### `openemail automations send-test`

Send yourself the email of one step

```bash
openemail automations send-test <id> --step-key <value> [flags]
openemail automations send-test <id> --data <json|@file|-> [flags]
```

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.

- Scopes: `automations:write`, `emails:send`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Flags**

- `--step-key <value>`: The `key` of the email step to send, from the draft `definition`. Required, here or in `--data`.
- `--to <value>`: Where the test goes. Left out, it goes to the account email of the person the key or app acts for: the workspace owner for an API key.
- `--data <json|@file|->`: The whole `body` as JSON, inline, from a file with @path, or - for standard input. Flags override its keys.

**Examples**

The required values only

```bash
openemail automations send-test aut_5c1e9a7b3d2f48e6a0b4c7d1 --step-key welcome
```

With optional flags

```bash
openemail automations send-test aut_5c1e9a7b3d2f48e6a0b4c7d1 --step-key welcome --to ada@example.com
```

Read the whole body from a JSON file

```bash
openemail automations send-test aut_5c1e9a7b3d2f48e6a0b4c7d1 --data @automation.json
```

Also available in: API [`POST /automations/{id}/test`](https://openemail.uk/docs/api/reference/automations#post-automations-id-test); TypeScript [`automations.sendTest()`](https://openemail.uk/docs/sdk/reference/automations#sendTest); Python [`automations.send_test()`](https://openemail.uk/docs/python/reference/automations#sendTest); Ruby [`automations.send_test`](https://openemail.uk/docs/ruby/reference/automations#sendTest); PHP [`automations->sendTest`](https://openemail.uk/docs/php/reference/automations#sendTest); Go [`Automations.SendTest`](https://openemail.uk/docs/go/reference/automations#sendTest); Java [`automations().sendTest`](https://openemail.uk/docs/java/reference/automations#sendTest); C# [`Automations.SendTestAsync`](https://openemail.uk/docs/csharp/reference/automations#sendTest).

### `openemail automations list-versions`

List the published versions of an automation

```bash
openemail automations list-versions <id> [flags]
```

Returns every published version, the newest first, each with its whole definition. `current` marks the one that is running. A publish that changed the definition adds a version, and each contact stays on the version they entered on. A draft that was never published has none. The list is not paginated.

- Scopes: `automations:read`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Examples**

```bash
openemail automations list-versions aut_5c1e9a7b3d2f48e6a0b4c7d1
```

Print the raw JSON

```bash
openemail automations list-versions aut_5c1e9a7b3d2f48e6a0b4c7d1 --json
```

Also available in: API [`GET /automations/{id}/versions`](https://openemail.uk/docs/api/reference/automations#get-automations-id-versions); TypeScript [`automations.listVersions()`](https://openemail.uk/docs/sdk/reference/automations#listVersions); Python [`automations.list_versions()`](https://openemail.uk/docs/python/reference/automations#listVersions); Ruby [`automations.list_versions`](https://openemail.uk/docs/ruby/reference/automations#listVersions); PHP [`automations->listVersions`](https://openemail.uk/docs/php/reference/automations#listVersions); Go [`Automations.ListVersions`](https://openemail.uk/docs/go/reference/automations#listVersions); Java [`automations().listVersions`](https://openemail.uk/docs/java/reference/automations#listVersions); C# [`Automations.ListVersionsAsync`](https://openemail.uk/docs/csharp/reference/automations#listVersions).

### `openemail automations restore-version`

Copy an earlier version back into the draft

```bash
openemail automations restore-version <id> <version> [flags]
```

Copies the definition of an earlier version into the draft, replacing what the draft holds. Nothing that is running changes until you `publish`. It takes no body.

- Scopes: `automations:write`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.
- `<version>` (required): The number of the version, from `listVersions`. A whole number from 1 up.

**Examples**

```bash
openemail automations restore-version aut_5c1e9a7b3d2f48e6a0b4c7d1 1
```

Print the raw JSON

```bash
openemail automations restore-version aut_5c1e9a7b3d2f48e6a0b4c7d1 1 --json
```

Also available in: API [`POST /automations/{id}/versions/{version}/restore`](https://openemail.uk/docs/api/reference/automations#post-automations-id-versions-version-restore); TypeScript [`automations.restoreVersion()`](https://openemail.uk/docs/sdk/reference/automations#restoreVersion); Python [`automations.restore_version()`](https://openemail.uk/docs/python/reference/automations#restoreVersion); Ruby [`automations.restore_version`](https://openemail.uk/docs/ruby/reference/automations#restoreVersion); PHP [`automations->restoreVersion`](https://openemail.uk/docs/php/reference/automations#restoreVersion); Go [`Automations.RestoreVersion`](https://openemail.uk/docs/go/reference/automations#restoreVersion); Java [`automations().restoreVersion`](https://openemail.uk/docs/java/reference/automations#restoreVersion); C# [`Automations.RestoreVersionAsync`](https://openemail.uk/docs/csharp/reference/automations#restoreVersion).

### `openemail automations stats`

Read how an automation has performed

```bash
openemail automations stats <id> [flags]
```

Returns the numbers of an automation over a window: `totals` for the whole automation, `steps` with the same numbers step by step, and `series` with a point for each UTC day on which something happened. The window defaults to the last 30 days and reaches back at most 366 days before `until`.

The steps are those of the published version, or of the draft when nothing is published. `totals.active` and the `waiting` of each step are counted at the moment of the read, whatever the window. Opens are a floor, because many mail apps hide them.

- Scopes: `automations:read`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Flags**

- `--since <when>`: Where the window starts, as a `Date` or an ISO 8601 string. Left out, 30 days before `until`.
- `--until <when>`: Where the window ends, as a `Date` or an ISO 8601 string. Left out, now. It has to be later than `since`.

**Examples**

The required values only

```bash
openemail automations stats aut_5c1e9a7b3d2f48e6a0b4c7d1
```

With optional flags

```bash
openemail automations stats aut_5c1e9a7b3d2f48e6a0b4c7d1 --since 2026-09-01T00:00:00Z
```

Print the raw JSON

```bash
openemail automations stats aut_5c1e9a7b3d2f48e6a0b4c7d1 --json
```

Also available in: API [`GET /automations/{id}/stats`](https://openemail.uk/docs/api/reference/automations#get-automations-id-stats); TypeScript [`automations.stats()`](https://openemail.uk/docs/sdk/reference/automations#stats); Python [`automations.stats()`](https://openemail.uk/docs/python/reference/automations#stats); Ruby [`automations.stats`](https://openemail.uk/docs/ruby/reference/automations#stats); PHP [`automations->stats`](https://openemail.uk/docs/php/reference/automations#stats); Go [`Automations.Stats`](https://openemail.uk/docs/go/reference/automations#stats); Java [`automations().stats`](https://openemail.uk/docs/java/reference/automations#stats); C# [`Automations.StatsAsync`](https://openemail.uk/docs/csharp/reference/automations#stats).

### `openemail automations list-enrollments`

List one page of the contacts in an automation

```bash
openemail automations list-enrollments <id> [flags]
```

Returns one page of everyone who is in the automation or has been, the most recent entry first. Each enrollment says who the `contact` is, the `--step-key` they are at, whether they are `waiting` and for which event, what holds a step that is due in `heldFor`, when they move next in `nextRunAt`, and how it ended in `exitReason`.

`--limit` takes 1 to 200 and defaults to 50. Pass `nextCursor` back as `--cursor`, with the same filters, while `hasMore` is true.

Add `--all` to walk every page: a table on a terminal, one JSON object per line when piped or with `--ndjson`, and one `{ items, hasMore, nextCursor }` document with `--json`. `--max <n>` stops after that many items.

- Scopes: `automations:read`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Flags**

- `--status <value>`: Only enrollments in this state: `active`, `completed` or `exited`.
- `--step-key <value>`: Only contacts at the step with this `key`.
- `--q <value>`: Only contacts whose address or name contains this text, compared without case, up to 200 characters.
- `--limit <n>` (default `50`): Rows per page, a whole number from 1 to 200. The server defaults to 50.
- `--cursor <value>`: The `nextCursor` from the previous page, passed back exactly as it came. One that names no enrollment of this automation is a 400 `invalid_cursor`.
- `--all`: Fetch every page and stream the items as they arrive.
- `--max <n>`: Stop after this many items. Implies `--all`.
- `--ndjson`: Print every item as one JSON object per line. Implies `--all`

**Examples**

The required values only

```bash
openemail automations list-enrollments aut_5c1e9a7b3d2f48e6a0b4c7d1
```

With optional flags

```bash
openemail automations list-enrollments aut_5c1e9a7b3d2f48e6a0b4c7d1 --status active
```

Walk every page and stop after 100 items

```bash
openemail automations list-enrollments aut_5c1e9a7b3d2f48e6a0b4c7d1 --all --max 100
```

One JSON object per line when piped

```bash
openemail automations list-enrollments aut_5c1e9a7b3d2f48e6a0b4c7d1 --all > automations.ndjson
```

Also available in: API [`GET /automations/{id}/enrollments`](https://openemail.uk/docs/api/reference/automations#get-automations-id-enrollments); TypeScript [`automations.listEnrollments()`](https://openemail.uk/docs/sdk/reference/automations#listEnrollments); Python [`automations.list_enrollments()`](https://openemail.uk/docs/python/reference/automations#listEnrollments); Ruby [`automations.list_enrollments`](https://openemail.uk/docs/ruby/reference/automations#listEnrollments); PHP [`automations->listEnrollments`](https://openemail.uk/docs/php/reference/automations#listEnrollments); Go [`Automations.ListEnrollments`](https://openemail.uk/docs/go/reference/automations#listEnrollments); Java [`automations().listEnrollments`](https://openemail.uk/docs/java/reference/automations#listEnrollments); C# [`Automations.ListEnrollmentsAsync`](https://openemail.uk/docs/csharp/reference/automations#listEnrollments).

### `openemail automations get-enrollment`

Retrieve one contact's way through an automation

```bash
openemail automations get-enrollment <id> <enrollment-id> [flags]
```

Returns one enrollment with `runs`: what each step did for the contact, oldest first, up to 200. A run has the `stepKey`, the `kind` of step, an `outcome` such as `sent`, `waited`, `yes`, `no`, `skipped` or `failed`, the `emailId` a send step produced and a `detail` that says why a step was skipped or failed.

- Scopes: `automations:read`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.
- `<enrollment-id>` (required): Enrollment id such as `aen_2b8d4f6a1c3e5079b6d8f0a2`, from `listEnrollments`.

**Examples**

```bash
openemail automations get-enrollment aut_5c1e9a7b3d2f48e6a0b4c7d1 aen_2b8d4f6a1c3e5079b6d8f0a2
```

Print the raw JSON

```bash
openemail automations get-enrollment aut_5c1e9a7b3d2f48e6a0b4c7d1 aen_2b8d4f6a1c3e5079b6d8f0a2 --json
```

Also available in: API [`GET /automations/{id}/enrollments/{enrollmentId}`](https://openemail.uk/docs/api/reference/automations#get-automations-id-enrollments-enrollmentid); TypeScript [`automations.getEnrollment()`](https://openemail.uk/docs/sdk/reference/automations#getEnrollment); Python [`automations.get_enrollment()`](https://openemail.uk/docs/python/reference/automations#getEnrollment); Ruby [`automations.get_enrollment`](https://openemail.uk/docs/ruby/reference/automations#getEnrollment); PHP [`automations->getEnrollment`](https://openemail.uk/docs/php/reference/automations#getEnrollment); Go [`Automations.GetEnrollment`](https://openemail.uk/docs/go/reference/automations#getEnrollment); Java [`automations().getEnrollment`](https://openemail.uk/docs/java/reference/automations#getEnrollment); C# [`Automations.GetEnrollmentAsync`](https://openemail.uk/docs/csharp/reference/automations#getEnrollment).

### `openemail automations enroll`

Put a contact into a live automation

```bash
openemail automations enroll <id> [flags]
```

Puts one contact into a live automation at its first step, whatever its trigger is. Name the contact with `email` or `--contact-id`, never both. The contact has to exist already: save one with `contacts.create` first. `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.

- Scopes: `automations:write`.
- Needs a sign-in.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.

**Flags**

- `--email <value>`: The contact, by email address. Send this or `--contact-id`.
- `--contact-id <value>`: The contact, by id, as an event or another enrollment carries it. Send this or `email`.
- `--body-data <json|@file|->`: 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. JSON shaped as `Record<string, unknown>`, inline or from a file with @path.
- `--data <json|@file|->`: The whole `body` as JSON, inline, from a file with @path, or - for standard input. Flags override its keys.

**Examples**

The required values only

```bash
openemail automations enroll aut_5c1e9a7b3d2f48e6a0b4c7d1
```

With optional flags

```bash
openemail automations enroll aut_5c1e9a7b3d2f48e6a0b4c7d1 --email ada@example.com
```

Also available in: API [`POST /automations/{id}/enrollments`](https://openemail.uk/docs/api/reference/automations#post-automations-id-enrollments); TypeScript [`automations.enroll()`](https://openemail.uk/docs/sdk/reference/automations#enroll); Python [`automations.enroll()`](https://openemail.uk/docs/python/reference/automations#enroll); Ruby [`automations.enroll`](https://openemail.uk/docs/ruby/reference/automations#enroll); PHP [`automations->enroll`](https://openemail.uk/docs/php/reference/automations#enroll); Go [`Automations.Enroll`](https://openemail.uk/docs/go/reference/automations#enroll); Java [`automations().enroll`](https://openemail.uk/docs/java/reference/automations#enroll); C# [`Automations.EnrollAsync`](https://openemail.uk/docs/csharp/reference/automations#enroll).

### `openemail automations exit-enrollment`

Take a contact out of an automation

```bash
openemail automations exit-enrollment <id> <enrollment-id> [flags]
```

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. It takes no body.

- Scopes: `automations:write`.
- Needs a sign-in.
- Asks you to confirm.

**Arguments**

- `<id>` (required): Automation id such as `aut_5c1e9a7b3d2f48e6a0b4c7d1`.
- `<enrollment-id>` (required): Enrollment id such as `aen_2b8d4f6a1c3e5079b6d8f0a2`, from `listEnrollments`.

**Examples**

```bash
openemail automations exit-enrollment aut_5c1e9a7b3d2f48e6a0b4c7d1 aen_2b8d4f6a1c3e5079b6d8f0a2
```

Skip the confirmation, for scripts

```bash
openemail automations exit-enrollment aut_5c1e9a7b3d2f48e6a0b4c7d1 aen_2b8d4f6a1c3e5079b6d8f0a2 --yes
```

Also available in: API [`POST /automations/{id}/enrollments/{enrollmentId}/exit`](https://openemail.uk/docs/api/reference/automations#post-automations-id-enrollments-enrollmentid-exit); TypeScript [`automations.exitEnrollment()`](https://openemail.uk/docs/sdk/reference/automations#exitEnrollment); Python [`automations.exit_enrollment()`](https://openemail.uk/docs/python/reference/automations#exitEnrollment); Ruby [`automations.exit_enrollment`](https://openemail.uk/docs/ruby/reference/automations#exitEnrollment); PHP [`automations->exitEnrollment`](https://openemail.uk/docs/php/reference/automations#exitEnrollment); Go [`Automations.ExitEnrollment`](https://openemail.uk/docs/go/reference/automations#exitEnrollment); Java [`automations().exitEnrollment`](https://openemail.uk/docs/java/reference/automations#exitEnrollment); C# [`Automations.ExitEnrollmentAsync`](https://openemail.uk/docs/csharp/reference/automations#exitEnrollment).
