---
title: "Update Sequence Step"
method: PATCH
path: "/api/v1/campaigns/{campaign_id}/sequence/nodes/{node_id}"
tags: ["Campaigns"]
---

# Update Sequence Step

`PATCH /api/v1/campaigns/{campaign_id}/sequence/nodes/{node_id}`

## Request

- Base URL: `http://localhost:3009`
- URL: `http://localhost:3009/api/v1/campaigns/{campaign_id}/sequence/nodes/{node_id}`
- Auth: HTTP bearer

Updates a step's configuration or display name in the draft sequence. `config` is merged over the existing config — send only the keys you're changing. Patch a `wait` step's `delay` and `unit` to change the gap between two steps.

**This writes the draft.** Call Publish Sequence to make it live.

**Concurrent writes are safe** — overlapping calls to one campaign serialize, and every change is kept. A sequence builder open in the browser saves its own copy of the whole graph, so an edit made through the API while that canvas is open is overwritten by the next canvas save.

## Path parameters

- `campaign_id` string, required
- `node_id` string, required

## Request body

- object
  - `config` object: Config keys to merge over the step's existing config
  - `name` string, nullable: Display name; pass null to clear it

## Response `200`

Default Response

- object
  - `status` integer
  - `message` string
  - `data` CampaignSequenceNode: A step in the sequence. Nodes form a single linear chain from the `start` node via `next_node_id`; `wait` nodes between steps are managed automatically.
    - `node_id` string: Node ID — stable for the life of the node
    - `type` 'start' | 'wait' | 'send' | 'manual_task' | 'phone_call_task' | 'linkedin_message_task' | 'note': Persisted node type. A `manual_email` added via the catalog persists as `send` with `config.send_mode = "manual"`.
    - `display_name` string, nullable: Custom step name; falls back to the type label
    - `config` object: Step configuration, stored and returned verbatim in the sending engine's own vocabulary — so key casing is mixed (`sender_mode` next to `trackOpens`) and it is passed through rather than renamed, because these are the exact keys the sender reads. **send**: `subject`, `body` (required), plus `send_mode` (`manual`), `thread_mode` (`reply`|`new`), `cc`, `bcc`, `trackOpens`, `sender_mode` (`pool`|`mailbox`|`member`), `sender_mailbox_id`, `sender_member_email`, `replyTaskPriority`. **wait**: `delay`, `unit` (`minutes`|`hours`|`days`). **task steps**: `priority`, `note`, `assignee_mode` (`mailbox_owner`|`member`), `assignee_email`. **start**: `leadFields` — the campaign's lead schema, in the same shape as `lead_schema` on Get Campaign.
    - `next_node_id` string, nullable: The next step in the chain; null on the final step

## Other responses

- `400`: Invalid config for this step type, or `config.leadFields` (use Update Lead Schema instead)
- `401`: Unauthorized — missing or invalid API key
- `403`: Forbidden. `code` says which permission refused: ROLE_FORBIDDEN (your role), INSUFFICIENT_SCOPE (the API key's scopes), WORKFLOW_FORBIDDEN (no access to the workflow), KEY_WORKFLOW_FORBIDDEN (the API key's workflow restriction).
- `404`: Campaign or step not found
- `429`: Too Many Requests — rate limit exceeded. Check `Retry-After` header for seconds until the limit resets.

---

[API](https://skmtc.dev/floqer/apis/floqer-public-api.md) - [All operations](https://skmtc.dev/floqer/apis/floqer-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/floqer/apis/floqer-public-api/revisions/fce50dc07b20?raw)
