---
title: "Automations"
description: "`automations.list`, `get`, `create`, `update`, `publish`, `pause`, `resume`, `archive`, `duplicate`, `delete`, `sendTest`, `stats`, `analytics`, `listRuns`, `listVersions`, `restoreVersion`, `listStarters`, `listEnrollments`, `getEnrollment`, `enroll` and `exitEnrollment`, with `events.send`, `sendBatch` and `listNames`."
url: "https://nextmail.sh/docs/sdk/automations"
area: "TypeScript"
category: "Mailbox"
---

# Automations

`automations.list`, `get`, `create`, `update`, `publish`, `pause`, `resume`, `archive`, `duplicate`, `delete`, `sendTest`, `stats`, `analytics`, `listRuns`, `listVersions`, `restoreVersion`, `listStarters`, `listEnrollments`, `getEnrollment`, `enroll` and `exitEnrollment`, with `events.send`, `sendBatch` and `listNames`.

## Every method

**automations.ts**

```
const automation = await nextmail.automations.create({
  name: 'Welcome series',
  starter: 'welcome-series',
  settings: { timezone: 'Europe/London' },
})

const saved = await nextmail.automations.update(automation.id, {
  definition: { ...automation.definition, trigger: { kind: 'event', eventName: 'trial.started', filters: [] } },
  expectedUpdatedAt: automation.updatedAt,
})

if (saved.problems.some((problem) => problem.blocking)) throw new Error(saved.problems[0]?.message)

await nextmail.automations.sendTest(saved.id, { stepKey: saved.definition.entry ?? '' })
const live = await nextmail.automations.publish(saved.id)

const sent = await nextmail.events.send(
  { name: 'trial.started', email: 'ann@example.com', properties: { plan: 'starter' }, createContact: true },
  { idempotencyKey: 'trial:ann@example.com' },
)

for await (const enrollment of nextmail.automations.iterateEnrollments(live.id, { status: 'active' })) {
  if (enrollment.heldFor) console.log(enrollment.contact.email, enrollment.heldFor)
}

const stats = await nextmail.automations.stats(live.id)
const history = await nextmail.contacts.listEvents('ann@example.com', { name: 'trial.started' })

await nextmail.automations.pause(live.id)
await nextmail.automations.resume(live.id)

console.log(sent.enrolled, stats.totals.entered, history.items.length)
```

An automation keeps a draft `definition` and the `published` version that runs. `update` changes the draft and the settings, and `publish` freezes the draft as the next version and turns the automation on. `problems` says what still stops a draft from being published, and `expectedUpdatedAt` refuses a save that would overwrite someone else’s with 409 `version_conflict`.

Reading needs `automations:read` and changing needs `automations:write`. `publish`, `resume` and `sendTest` also need `emails:send`. `events.send` and `events.sendBatch` need `contacts:write`, and `contacts.listEvents` needs `contacts:read`. `delete` asks an OAuth access token for a verification code, and an API key never.

`events.sendBatch` takes up to 100 events and never throws for one bad event: the answer lists `accepted` and `failed`, each with the `index` of the event in the array you sent.

## Reports and the run log

**reports.ts**

```
const all = await nextmail.automations.analytics({ since: '2026-10-01T00:00:00Z' })

for (const row of all.automations) console.log(row.name, row.entered, row.active, row.clicked)

for await (const run of nextmail.automations.iterateRuns('aut_7c2e9a1f4b8d30c65e1a9f27', { outcome: 'failed' })) {
  console.log(run.at, run.contact.email, run.stepKey, run.detail)
}
```

`analytics` puts every automation of the workspace side by side, and `automationIds` narrows the totals to some of them. `listRuns`, `listAllRuns` and `iterateRuns` read what one automation did, newest first: each person entering, every step it ran with its `outcome`, and each person finishing. Both need `automations:read`.
