> ## Documentation Index
> Fetch the complete documentation index at: https://docs.levios.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Create, edit, and publish automations

> Complete request and response examples, safe editing, publication, and retries.

This walkthrough creates a draft that sends a guide link when a contact comments
with a keyword. All IDs, timestamps, copy, and URLs below are illustrative.
Replace the account ID with one returned by [List
accounts](/api/v1/accounts/list). Use an API key with the required scopes.

## 1. Create a draft

Send this body to `POST /api/v1/automations` with `Authorization: Bearer <API_KEY>` and `Content-Type: application/json`. Creation requires
`automations:write`. The name allows 1 to 120 Unicode scalars, without
surrounding whitespace or control characters.

```json theme={null}
{
  "account_id": "00000000-0000-4000-8000-000000000001",
  "name": "Guide request",
  "status": "draft",
  "configuration": {
    "contact_filter": "anyone",
    "trigger": {
      "type": "comment",
      "publication": {
        "mode": "all"
      },
      "keywords": {
        "mode": "specific",
        "match_mode": "whole_word",
        "values": [
          "guide"
        ]
      }
    },
    "opening": {
      "public_reply": {
        "enabled": false
      },
      "direct_message": {
        "delay_seconds": 0,
        "message": {
          "text": "Here is the guide you asked for.",
          "buttons": [
            {
              "type": "url",
              "title": "Open the guide",
              "url": "https://example.com/guide"
            }
          ]
        }
      }
    },
    "follow_up": null,
    "extras": {
      "cooldown": {
        "mode": "none"
      }
    }
  }
}
```

### Response: HTTP 201

```json theme={null}
{
  "automation": {
    "id": "00000000-0000-4000-8000-000000000002",
    "account_id": "00000000-0000-4000-8000-000000000001",
    "name": "Guide request",
    "status": "draft",
    "has_unpublished_changes": false,
    "draft_updated_at": null,
    "created_at": "2026-09-01T12:00:00.000000Z",
    "updated_at": "2026-09-01T12:00:00.000000Z",
    "trigger_type": "comment",
    "configuration": {
      "contact_filter": "anyone",
      "trigger": {
        "type": "comment",
        "publication": {
          "mode": "all"
        },
        "keywords": {
          "mode": "specific",
          "match_mode": "whole_word",
          "values": [
            "guide"
          ]
        }
      },
      "opening": {
        "public_reply": {
          "enabled": false
        },
        "direct_message": {
          "delay_seconds": 0,
          "message": {
            "text": "Here is the guide you asked for.",
            "buttons": [
              {
                "type": "url",
                "title": "Open the guide",
                "url": "https://example.com/guide"
              }
            ]
          }
        }
      },
      "follow_up": null,
      "extras": {
        "cooldown": {
          "mode": "none"
        }
      }
    },
    "authoring_compatibility": "public_v1"
  }
}
```

The envelope is `automation`, not `data`. A successful write stores the
automation; it does not prove that a message was sent. Save `id` and the exact
`updated_at` string. Do not round or reformat timestamps.

## 2. Read before editing

Call `GET /api/v1/automations/{automationId}?account_id=...` with
`automations:read`. HTTP `200` returns the same complete envelope shown above.
Always start an edit from a fresh read.

## 3. Rename or replace configuration

For a rename, send this body to `PATCH /api/v1/automations/{automationId}`.
Replace the example timestamp with the value from your fresh read.

```json theme={null}
{
  "account_id": "00000000-0000-4000-8000-000000000001",
  "expected_updated_at": "2026-09-01T12:00:00.000000Z",
  "name": "Updated guide request"
}
```

To change behavior, also send the entire modified `configuration` object. It
replaces the stored configuration; nested objects and arrays are not merged. You
can send the name, the configuration, or both, but not `status`. HTTP `200`
returns the full `automation` envelope, including the new `updated_at`.

On a live automation, inspect `has_unpublished_changes`. When true, the returned
name and configuration describe the draft, while the previously published
version continues running. `draft_updated_at` is informational; concurrency
always uses `updated_at`.

## 4. Publish or pause

After reviewing the stored draft, send the following body to `POST /api/v1/automations/{automationId}/activate`. Use the latest version from a new
read. Activation requires `automations:activate`.

```json theme={null}
{
  "account_id": "00000000-0000-4000-8000-000000000001",
  "expected_updated_at": "2026-09-01T12:00:00.000000Z"
}
```

HTTP `200` returns the complete envelope with `status: "live"` and published
configuration. To pause new trigger processing, send the same body shape with a
fresh version to `POST /api/v1/automations/{automationId}/deactivate`; HTTP
`200` returns `status: "paused"`. Creating with `status: "live"` publishes
immediately and also requires activation scope.

## Recover without duplicate writes

* `409` with `api_automation_version_conflict`: read again, reconcile the newer changes, and rebuild the update.
* `422` with `api_automation_invalid_configuration`: inspect `error.details.issues` and fix the reported paths.
* `api_automation_committed_response_unavailable` with `committed: true` and `retryable: false`: the write committed. Read back, or list after creation, before deciding what to do.
* An uncertain create outcome must not be blindly retried: creation is not idempotent.

## Example conflict response

HTTP `409`.

```json theme={null}
{
  "error": {
    "code": "api_automation_version_conflict",
    "message": "The automation changed after the supplied version."
  }
}
```

Use the [error guide](/guides/errors) for the response envelope, correlation
IDs, authentication failures, and retry decisions.
[Delete](/api/v1/automations/delete) archives the automation and returns HTTP
`204` with no body; do not try to parse it as JSON.
