# Automations API

Create automations, change their name or flow, publish or pause them, and read who is enrolled. All routes need a bearer API key (see [API Overview](/docs/api/overview)).

The flow itself is easiest to build in the visual builder (see [Automations](/docs/platform/automations)). The API is for listing, publishing, pausing and for programmatic edits.

## The automation object

```json
{
  "id": "clx...",
  "name": "Welcome series",
  "status": "LIVE",
  "createdAt": "2026-10-01T09:00:00.000Z",
  "updatedAt": "2026-10-02T09:00:00.000Z",
  "activeEnrollments": 14
}
```

`status` is `DRAFT`, `LIVE` or `PAUSED`. `activeEnrollments` counts enrollments that are still running. The record also carries a few other stored fields, but the flow is never included in list or detail responses. Fetch it from the builder.

## List automations

```text
GET /api/v1/automations
```

Query: `limit`, `after`, and `status` (`DRAFT`, `LIVE` or `PAUSED`; anything else is a `422`).

## Create an automation

```text
POST /api/v1/automations
```

```json
{ "name": "Welcome series" }
```

`name` is optional and defaults to "Untitled automation". The new automation is a `DRAFT` with one trigger node, "New subscriber joins". Returns `201`.

## Get, update and delete

```text
GET    /api/v1/automations/:id
PATCH  /api/v1/automations/:id
DELETE /api/v1/automations/:id
```

`PATCH` accepts any of:

| Field      | Notes                                                        |
| ---------- | ------------------------------------------------------------ |
| `name`     | An empty name becomes "Untitled automation"                  |
| `flowJson` | The flow, as `{ "nodes": [...], "edges": [...] }`. See below |
| `status`   | `LIVE`, `PAUSED` or `DRAFT`. See the transitions below       |

`flowJson` is checked before it is saved. Every node needs a string `id`, a string `type` and an object `data`. Every edge needs a string `source` and `target`. The engine uses node types `trigger`, `wait`, `condition`, `action` and `end`. Anything that does not match this shape returns `422`.

Status changes:

| To       | Allowed from        | Otherwise                                      |
| -------- | ------------------- | ---------------------------------------------- |
| `LIVE`   | `DRAFT` or `PAUSED` | `422` with code `AUTOMATION_WRONG_STATE`       |
| `PAUSED` | `LIVE`              | `422` with code `AUTOMATION_WRONG_STATE`       |
| `DRAFT`  | `DRAFT` only        | A published automation cannot go back to draft |

`DELETE` returns `204`.

## List enrollments

```text
GET /api/v1/automations/:id/enrollments
```

Query: `limit`, `after`, and `status` (`ACTIVE`, `COMPLETED` or `FAILED`).

```json
{
  "data": [
    {
      "id": "clx...",
      "contactId": "clx...",
      "currentNodeId": "node_3",
      "status": "ACTIVE",
      "nextRunAt": "2026-10-05T09:00:00.000Z",
      "enrolledAt": "2026-10-04T09:00:00.000Z",
      "completedAt": null,
      "errorMessage": null
    }
  ],
  "pagination": { "total": 1, "limit": 20, "hasMore": false, "nextCursor": null }
}
```

Results are newest first by `enrolledAt`. `errorMessage` is set when an enrollment failed.

## Starting automations from your app

Contacts enter an automation through its trigger. To start one from your own system, record an event with the [Events API](/docs/api/events) and use a custom event trigger.
