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

# Update Sequence

> Update sequence identity, settings, structure, or existing nodes

# Update Sequence

Updates sequence sending identity, metadata, auto-stop behavior, branch logic,
graph topology, linear steps, and email content. You can insert new linear steps
with `insertSteps`, restructure existing nodes with `graphEdit`, or target
any existing node with `nodeUpdates`.

## Request

<ParamField path="sequenceId" type="string" required>
  Sequence ID.
</ParamField>

<ParamField body="name" type="string">
  Updated sequence name.
</ParamField>

<ParamField body="description" type="string">
  Updated dashboard description.
</ParamField>

<ParamField body="labels" type="string[]">
  Replacement dashboard label names. Missing labels are created.
</ParamField>

<ParamField body="userCancellable" type="boolean">
  Whether recipients can cancel this sequence from email preferences.
</ParamField>

<ParamField body="trigger" type="string">
  Atomically replace the current trigger with `contact_added`, `tag_added`,
  `segment_entered`, `event_received`, `inbound_webhook`, `inactivity`, or
  `frequency`. Include the matching trigger fields (`listId`, `tagName`,
  `segmentId`, `eventName`, `propertyFilters`, `integrationSlug`,
  `integrationEventKey`, `customIntegration`, `inactiveDays`,
  `inactivityBaseline`, `minCount`, or `timeWindowDays`) in the same request.
  Active sequences require `confirmLiveChange: true`. Trigger replacement cannot
  be combined with node, content, or structural graph changes.
</ParamField>

<ParamField body="fromEmail" type="string">
  From address for every sequence email. Its domain must be configured and
  verified. Mutually exclusive with `senderProfileId`.
</ParamField>

<ParamField body="fromName" type="string">
  Display name for a newly created sender profile. Requires `fromEmail`.
</ParamField>

<ParamField body="senderProfileId" type="string">
  Existing sender profile ID. Mutually exclusive with `fromEmail`.
</ParamField>

<ParamField body="replyTo" type="string">
  Reply-To address for every sequence email. Mutually exclusive with
  `replyProfileId`.
</ParamField>

<ParamField body="replyToName" type="string">
  Display name for a newly created reply profile. Requires `replyTo`.
</ParamField>

<ParamField body="replyProfileId" type="string">
  Existing reply profile ID. Mutually exclusive with `replyTo`.
</ParamField>

<ParamField body="enrollmentMode" type="string">
  Updated re-entry mode: `unlimited`, `one_time`, or `matching_field`.
  `matching_field` is only valid for event-based sequence triggers.
</ParamField>

<ParamField body="enrollmentFieldPath" type="string">
  Dot-path event property used by `matching_field`. Set to `null` or omit it to
  use the built-in defaults.
</ParamField>

For example, use `{"enrollmentMode":"matching_field","enrollmentFieldPath":"order.id"}` to allow one active run per order while blocking duplicate active runs for the same subscriber and order.

<ParamField body="enrollmentPaused" type="boolean">
  Set to `true` to stop new enrollments for an active sequence while current
  recipients continue. Set to `false` to reopen new enrollments.
</ParamField>

<ParamField body="sendingWindow" type="object | null">
  Updated local-time sending window for every email step. Set to `null` to
  remove the sending restriction. When set, email steps that become due outside
  the window wait until the next allowed local time.
</ParamField>

<ParamField body="bccEmails" type="string[] | null">
  Email addresses that receive a blind copy of every email this sequence sends,
  such as a customer support inbox (max 10). BCC recipients are invisible to the
  subscriber. Set to `null` to remove them.
</ParamField>

<ParamField body="stopCondition" type="object">
  Updated auto-stop condition. Use `has_tag`, `does_not_have_tag`,
  `added_to_list`, `removed_from_list`, `entered_segment`, `field_changed`,
  `event_received`, or `none`. `event_received` can use typed `event_property`
  match rules and `field_changed` can use a typed `field_value` comparison.
</ParamField>

<ParamField body="branch" type="object">
  Insert an if/else branch after an existing node. Provide `afterNodeId` and a
  `branches` array. Each conditional path can create `steps`, route directly to
  an existing `targetNodeId`, or run steps and then reach that target. The else
  path uses `elseSteps` and/or `elseTargetNodeId`. Use the completion node ID
  returned by the sequence GET endpoint to end one path immediately. Empty
  branch paths are rejected unless you set `allowEmptyPaths: true`. Branch
  `conditionType` values include `has_tag`, `does_not_have_tag`, `in_list`,
  `in_segment`, `event_received`, `link_clicked`, and field comparisons. For
  `has_tag` and `does_not_have_tag`, provide `tagId` or `tagName`. For
  `event_received` and `link_clicked`, set `activityScope` to `this_sequence`,
  `previous_email`, or `ever`; omitting it checks `ever`.
</ParamField>

<ParamField body="insertSteps" type="object">
  Insert one or more new linear steps into the sequence. Provide `afterNodeId`
  to insert after a specific node from `GET /api/v1/sequences/{sequenceId}`. If
  `afterNodeId` is omitted, the steps are appended only when the sequence has
  exactly one linear tail. Linear insertion supports every non-trigger addable
  step type that does not require companion records: email, SMS, delay, tag/list
  actions, attribute updates, discounts, conditions, wait-for-event steps, and
  webhooks. SMS steps use `type: "sms"` with a plain-text `text` field (optional
  `label`, `ineligibleAction`, `imageUrls`); generate copy with the [Generate
  SMS endpoint](/api-reference/generate/sms). Email and delay steps can use
  fixed `delay`/`delayMs` waits or dynamic `waitUntil` date-field waits. Use
  `nodeType: "logic_wait_for_event"` with a config containing `eventName`,
  `timeoutDays` (1-365), `timeoutAction` (`continue` or `exit`), and an optional
  `label` to insert an event gate. Event receipt and a continuing timeout both
  use the gate's single next path; `timeoutAction: "exit"` completes the
  enrollment on timeout. Use `branch` for if/else paths. Provide only one of
  `branch`, `insertSteps`, or `graphEdit` in a request. Inserted email steps
  inherit the effective sender identity (sender profile, display name, and
  Reply-To) of the nearest sequence email. Across a branch merge, only identity
  fields shared by every incoming path are inherited; conflicting fields use the
  sequence or company defaults. Set `senderProfileId`/`fromEmail` or
  `replyProfileId`/`replyTo` on a step to override the inherited identity.
</ParamField>

<ParamField body="graphEdit" type="object">
  Restructure existing sequence nodes. Set `action` to `move_node`,
  `duplicate_node`, `delete_node`, or `replace_edges`, and include the
  `expectedRevision` returned as `graphRevision` by the latest
  `GET /api/v1/sequences/{sequenceId}` response. A stale revision is rejected.

  `move_node` and `duplicate_node` require `nodeId` plus exactly one of
  `afterNodeId` or `beforeNodeId`. `beforeNodeId` funnels every incoming path
  through the moved or copied node, so it can relocate an A/B test below paths
  that converge at a shared continuation. Duplicated email and A/B test steps
  receive independent content records; A/B metrics and winner state reset.

  `delete_node` automatically reconnects a linear step. To delete a split node,
  also provide the complete replacement `edges`. `replace_edges` always requires
  the complete normalized topology returned by the sequence GET endpoint and
  supports atomic path reconnects or multi-node reorders. Deleting an A/B test
  step also removes its test, variants, and variant localizations unless the test
  is currently in progress or replacement variants are still being generated.

  Preserve `condition.branchId` on every edge leaving a branch node. Graph edits
  reject cycles, disconnected nodes, invalid branch lanes, changes that remove
  the trigger/end path, and deletion of a node that currently holds an active or
  waiting recipient.
</ParamField>

<ParamField body="confirmStructuralChange" type="boolean">
  Required when inserting linear steps, branches, or applying `graphEdit` to an
  active sequence. Set it to `true` only after confirming the live-flow impact
  for current and future recipients. Content-only email edits do not require
  this flag.
</ParamField>

<ParamField body="nodeUpdates" type="array">
  Atomic, type-aware patches for existing nodes. Each item requires `nodeId`
  and a non-empty `changes` object. Pass the `updatedAt` returned for that node
  by `GET /api/v1/sequences/{sequenceId}` as `expectedUpdatedAt` to prevent a
  stale write. A node may appear only once, and `nodeUpdates` cannot be combined
  with legacy email/SMS/subscriber step arrays or structural edits.

  Each node read also includes `updateHints`, which lists that node type's
  editable fields, managed fields, special restrictions, and the exact
  `expectedUpdatedAt` token to return.

  `logic_delay` accepts exactly one of `delay` (`days`, `hours`, `minutes`),
  `delayMs`, or `waitUntil`. `action_email` accepts name/label, subject, preview
  text, HTML or blocks, `emailPreset` (`branded` or `minimal`), transactional mode,
  and per-step sender/reply identity. Setting `emailPreset` transforms that linked
  email's native blocks using the same **Style > Format** behavior as the
  dashboard without changing the company default. Native block emails may include
  supported custom HTML blocks. An email stored entirely as one standalone raw
  HTML block does not support `emailPreset`, and `emailPreset` cannot be combined
  with `html` or `htmlContent`.
  SMS and every other stored node type accept their type-specific editable
  config fields. Omitted fields are preserved. Managed linked-resource IDs,
  node-type conversion, and branch path IDs/count are rejected; use `graphEdit`
  for topology changes. Webhook header patches merge with existing headers, and
  redacted values from the read response cannot be written back.
</ParamField>

<ParamField body="confirmLiveChange" type="boolean">
  Required with `nodeUpdates` when the sequence is active. Set it to `true` only
  after confirming the behavior change. Existing waiting recipients retain their
  already-calculated `scheduledFor`; a new delay applies when recipients reach
  that node after the update.
</ParamField>

<ParamField body="emails" type="array">
  Existing email step updates. Provide `emails` or `steps`, not both. Items
  without `nodeId` or `emailId` are matched by existing step order and do not
  create new steps. `html` and `htmlContent` are preserved as one raw HTML
  block; provide `blocks` for native Sequenzy block content. Each item can also
  set `emailPreset` to `minimal` or `branded` when working with native blocks,
  including emails that contain supported custom HTML blocks. Emails stored
  entirely as one standalone raw HTML block do not support format changes. Each
  item can also set per-step sender identity: `senderProfileId` or `fromEmail`
  (+ optional `fromName`) for the From identity, and `replyProfileId` or
  `replyTo` (+ optional `replyToName`) for the Reply-To. A `fromName` on its own
  only changes the visible display name. Per-step identity overrides the
  sequence-level sender for that step. Email items can also set
  `isTransactional`, `ccEmails`, and `bccEmails` to match the dashboard
  delivery settings, and `attachments` (`[{ filename, path }]`) to configure
  URL-backed file attachments fetched at send time. For event-triggered
  sequences, `path` may use `{{event.file_url}}` and `filename` may also use
  event merge tags; values come from the event that enrolled each subscriber
  (max 10, 7MB total per email; an empty array removes them).
</ParamField>

<ParamField body="steps" type="array">
  Alias for `emails`. Use `insertSteps` to create new steps.
</ParamField>

<ParamField body="smsSteps" type="array">
  Content updates for existing SMS steps, targeted by `nodeId` (an `action_sms`
  node from `GET /api/v1/sequences/{sequenceId}`). Each entry can set `text` (or
  `blocks`), `imageUrls` (with `text`), `label`, and `ineligibleAction` (`skip`
  or `exit`). SMS content edits are content-only and do not require
  `confirmStructuralChange`. Use `insertSteps` to create new SMS steps.
</ParamField>

<ParamField body="subscriberUpdateSteps" type="array">
  Full config replacements for existing Update Subscriber steps, targeted by
  an `action_update_attributes` node ID from
  `GET /api/v1/sequences/{sequenceId}`. Values can use standalone event merge
  tags such as `{{event.plan}}`; number and boolean tags are coerced after
  resolution.
</ParamField>

```bash theme={null}
curl -X PUT "https://api.sequenzy.com/api/v1/sequences/seq_abc123" \
  -H "Authorization: Bearer seq_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated Welcome Sequence",
    "stopCondition": {
      "type": "has_tag",
      "value": "customer"
    },
    "sendingWindow": {
      "enabled": true,
      "timezone": "Europe/Kiev",
      "startTime": "08:00",
      "endTime": "20:00",
      "days": ["monday", "tuesday", "wednesday", "thursday", "friday"]
    },
    "insertSteps": {
      "afterNodeId": "node_migration_email",
      "steps": [
        {
          "delay": { "days": 1 },
          "name": "Migration check-in",
          "subject": "Need help migrating?",
          "html": "<p>Here is one more migration resource.</p>"
        }
      ]
    },
    "confirmStructuralChange": true,
    "emails": [
      {
        "nodeId": "node_abc123",
        "subject": "Welcome to Acme",
        "html": "<h1>Welcome</h1><p>Here is your first step.</p>"
      }
    ]
  }'
```

Suppress a follow-up after a reply by routing the matching path to completion
and the else path to the existing second email:

```bash theme={null}
curl -X PUT "https://api.sequenzy.com/api/v1/sequences/seq_abc123" \
  -H "Authorization: Bearer seq_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "branch": {
      "afterNodeId": "node_email_1",
      "label": "Did they reply?",
      "branches": [
        {
          "id": "replied",
          "conditionType": "event_received",
          "eventName": "email.replied",
          "activityScope": "this_sequence",
          "targetNodeId": "node_sequence_complete"
        }
      ],
      "elseTargetNodeId": "node_email_2"
    }
  }'
```

Move an existing A/B test below paths that converge at `node_end`:

```bash theme={null}
curl -X PUT "https://api.sequenzy.com/api/v1/sequences/seq_abc123" \
  -H "Authorization: Bearer seq_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "graphEdit": {
      "action": "move_node",
      "expectedRevision": "48ab6d78a2d4f2b7d2d36d8e1dba9ea3f411bb65059b627a2b8268b4e81d8f7a",
      "nodeId": "node_ab_test",
      "beforeNodeId": "node_end"
    }
  }'
```

Atomically change two existing delays from five minutes to seven days:

```bash theme={null}
curl -X PUT "https://api.sequenzy.com/api/v1/sequences/seq_abc123" \
  -H "Authorization: Bearer seq_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "nodeUpdates": [
      {
        "nodeId": "node_delay_1",
        "expectedUpdatedAt": "2026-07-14T10:00:00.000Z",
        "changes": { "delay": { "days": 7 } }
      },
      {
        "nodeId": "node_delay_2",
        "expectedUpdatedAt": "2026-07-14T10:01:00.000Z",
        "changes": { "delay": { "days": 7 } }
      }
    ]
  }'
```

## Responses

<ResponseExample>
  ```json 200 theme={null}
  {
    "success": true,
    "sequence": {
      "id": "seq_abc123",
      "name": "Updated Welcome Sequence",
      "status": "draft",
      "enrollmentPaused": false,
      "updatedEmailCount": 1,
      "updatedSubscriberStepCount": 1,
      "senderProfileId": "sender_abc123",
      "fromName": "Acme",
      "fromEmail": "hello@example.com",
      "replyProfileId": "reply_abc123",
      "replyToName": "Support",
      "replyToEmail": "support@example.com",
      "stopCondition": {
        "type": "has_tag",
        "value": "customer"
      },
      "sendingWindow": {
        "enabled": true,
        "timezone": "Europe/Kiev",
        "startTime": "08:00",
        "endTime": "20:00",
        "days": ["monday", "tuesday", "wednesday", "thursday", "friday"]
      },
      "insertedNodeIds": ["node_inserted_email"],
      "insertedEmailIds": ["email_inserted"],
      "insertedEmailCount": 1
    }
  }
  ```

  ```json 400 theme={null}
  {
    "error": "Active sequence structural changes require explicit confirmation. Re-run with confirmStructuralChange: true after confirming this can affect current and future sequence recipients."
  }
  ```

  ```json 400 theme={null}
  {
    "error": "insertSteps.afterNodeId is required when the sequence does not have exactly one linear tail"
  }
  ```

  ```json 401 theme={null}
  {
    "error": "Invalid API key"
  }
  ```

  ```json 403 theme={null}
  {
    "error": "No companies found. Create a company first using the create_company tool."
  }
  ```

  ```json 404 theme={null}
  {
    "error": "Sequence not found"
  }
  ```
</ResponseExample>
