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

# Add Sequence Step

`POST /api/v1/campaigns/{campaign_id}/sequence/nodes`

## Request

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

Adds a step to the campaign's draft sequence and returns it. Appends to the end by default; pass `after` (a `node_id`) to insert after a specific step.

`type` is a catalog `id` from List Sequence Step Types. `config` is merged over that type's `default_config` — required fields must end up set (a `send` step needs `subject` and `body`).

Wait steps between steps are managed automatically and cannot be added directly; patch a wait step's `config` to change a delay.

**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

## Request body

- object
  - `type` 'send' | 'manual_email' | 'manual_task' | 'phone_call_task' | 'linkedin_message_task', required: Step type — a catalog `id` from List Sequence Step Types
  - `after` string: Insert immediately after this `node_id`. Omit to append to the end of the sequence.
  - `config` object: Step configuration, merged over the type's `default_config`
  - `name` string: Custom display name for this step

## Response `201`

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`: Unknown step type or invalid config, or `after` names a step that is not connected to the sequence
- `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 `after` 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)
