---
title: "Update or publish an automation"
method: PATCH
path: "/v1/automations/{automationId}"
tags: ["Automations"]
---

# Update or publish an automation

`PATCH /v1/automations/{automationId}`

One endpoint, two mutually-exclusive modes:

- **Update** — supply one or more of `name`, `description`, `nodes`, `connections`, `triggerEventId`. Graph updates persist a new `automationVersionId` on the same `automationId`. Add `dryRun: true` to validate a graph update without persisting.
- **Lifecycle** — supply `published: true` to promote the stored latest version live (validates the graph first → `409 PUBLISH_VALIDATION_FAILED` on blockers; optionally pin `automationVersionId` to publish a specific version), or `published: false` to unpublish.

Graph updates use the same strict typed filter/split condition contract as create: explicit `type`, canonical snake_case `operator`, no `value` for unary operators, and type-correct values everywhere else.

The two modes cannot be combined: publishing promotes the stored graph, so update first, then PATCH `{ "published": true }`. Returns the bare automation row.

## Path parameters

- `automationId` string, required — Automation id returned by `POST /v1/automations` and listed by `GET /v1/automations`.

## Request body

- AutomationsUpdateRequest
  - `name` string
  - `description` string
  - `nodes` union[]
    - union
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'trigger', required
        - `config` object, required
          - `actionType` string
          - `mode` 'event' | 'manualAudience'
          - `triggerEventId` string
          - `audienceId` string
          - `eventName` string
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'sendEmail', required
        - `config` object, required
          - `actionType` string
          - `emailId` string, required
          - `emailVersionId` string, required
          - `domainId` string, required
          - `subject` string, required
          - `previewText` string, required
          - `messageClass` 'marketing' | 'transactional'
          - `fromName` string
          - `replyTo` string, email
          - `emailTitle` string
          - `fromAddress` string
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'wait', required
        - `config` object, required
          - `actionType` string
          - `duration` number, required
          - `unit` 'ms' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks', required
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'filter', required
        - `config` object, required
          - `actionType` string
          - `logicalOperator` 'AND' | 'OR', required
          - `conditions` union[], required
            - union
              - …
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'split', required
        - `config` union, required
          - object
            - `actionType` string
            - `mode` 'percentage', required
            - `leftLabel` string, required
            - `rightLabel` string, required
            - `leftPercentage` number, required
            - `seed` string
          - object
            - `actionType` string
            - `mode` 'condition', required
            - `leftLabel` string, required
            - `rightLabel` string, required
            - `logicalOperator` 'AND' | 'OR', required
            - `conditions` union[], required
              - …
  - `connections` object[]
    - `from` string, required
    - `to` string, required
    - `branch` 'left' | 'right'
  - `triggerEventId` string
  - `dryRun` boolean
  - `published` boolean
  - `automationVersionId` string
  - `stop_in_flight` boolean
  - `paused` boolean

## Response `200`

Updated / published / unpublished. The bare automation row (or the dry-run result when `dryRun: true`).

- AutomationRow
  - `automationId` string, required
  - `automationVersionId` string, required
  - `triggerEventId` string
  - `name` string, required
  - `description` string
  - `version` union, required
    - integer
    - 'latest'
  - `published` boolean, required
  - `paused` boolean
  - `pausedAt` number
  - `nodes` union[]
    - union
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'trigger', required
        - `config` object, required
          - `actionType` string
          - `mode` 'event' | 'manualAudience'
          - `triggerEventId` string
          - `audienceId` string
          - `eventName` string
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'sendEmail', required
        - `config` object, required
          - `actionType` string
          - `emailId` string
          - `emailVersionId` string
          - `emailTitle` string
          - `subject` string
          - `previewText` string
          - `messageClass` 'marketing' | 'transactional'
          - `fromName` string
          - `fromAddress` string
          - `domainId` string
          - `replyTo` string
          - `to` unknown
          - `html` string
          - `variables` object
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'wait', required
        - `config` object, required
          - `actionType` string
          - `duration` number, required
          - `unit` 'ms' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks', required
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'filter', required
        - `config` object, required
          - `actionType` string
          - `logicalOperator` 'AND' | 'OR', required
          - `conditions` object[], required
            - `field` string, required
            - `operator` string, required
            - `value` union
              - …
            - `type` 'string' | 'number' | 'date' | 'bool'
      - object
        - `id` string, required
        - `label` string, required
        - `description` string
        - `type` 'split', required
        - `config` union, required
          - object
            - `actionType` string
            - `mode` 'percentage', required
            - `leftLabel` string, required
            - `rightLabel` string, required
            - `leftPercentage` number, required
            - `seed` string
          - object
            - `actionType` string
            - `mode` 'condition', required
            - `leftLabel` string, required
            - `rightLabel` string, required
            - `logicalOperator` 'AND' | 'OR', required
            - `conditions` object[], required
              - …
  - `connections` object[]
    - `from` string, required
    - `to` string, required
    - `branch` 'left' | 'right'
  - `emailIds` string[], required
  - `createdBy` string
  - `createdAt` string, date-time
  - `updatedAt` string, date-time
  - `publishedAt` string, date-time
  - `versions` object[]
    - `version` union, required
      - integer
      - 'latest'
    - `automationVersionId` string, required

## Other responses

- `400` — Strict-body violation, no actionable field supplied, `published` combined with update fields, or `AUTOMATION_GRAPH_INVALID` (see `details.issues`).
- `401` — The API key was missing, invalid, or revoked.
- `403` — The caller does not have the required `automations` permission.
- `404` — Automation not found in the API-key brand. Cross-brand ids intentionally surface as 404 (never 403) so the API does not leak cross-brand existence.
- `409` — `PUBLISH_VALIDATION_FAILED` — `published: true` but the graph has blockers (see `details.blockers`).
- `422` — `AUTOMATION_NOT_PUBLISHED` — `published: false` but the automation was never published (nothing to unpublish).
- `429` — The request hit the rolling rate limit window.
- `500` — Unexpected internal error.

---

[API](https://skmtc.net/brew/apis/brew-public-api-v1.md) · [All operations](https://skmtc.net/brew/apis/brew-public-api-v1/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/brew/brew-public-api-v1/versions/db96cfedc6c5/schema)
