---
title: "Replace a campaign's playbook"
method: PUT
path: "/api/v1/campaigns/{id}/sequence"
---

# Replace a campaign's playbook

`PUT /api/v1/campaigns/{id}/sequence`

## Request

- Base URL: `https://www.easeclaw.com`
- URL: `https://www.easeclaw.com/api/v1/campaigns/{id}/sequence`
- Auth: HTTP bearer

Replaces the WHOLE playbook with the graph posted. Read the current one first and post it back changed; this does not merge. Shaping a playbook configures what the campaign will send once the owner approves it or their autopilot limits allow it: it approves nothing, sends nothing, and recalls nobody already queued. A graph that could not run answers 422 carrying `issues`, one per fault, in the validator's stable order. A finished campaign answers 409 (its playbook is the record of what it ran with), and so does an edit that removes a step people are currently standing on. Rate-limited to 60/hour per account, shared with the dashboard's builder. Requires an outreach-scope API key (Pro plan or higher).

## Path parameters

- `id` string, uuid, required

## Request body

- object
  - `graph` SequenceGraph, required: A campaign's whole playbook: the steps it runs and how they connect. Posting one REPLACES the playbook. It does not merge.
    - `version` 1
    - `root` string, nullable: The first node, or null for an empty playbook.
    - `nodes` object

## Response `200`

The saved playbook, its server-side ids, and any warnings it still carries

- object
  - `graph` SequenceGraph: A campaign's whole playbook: the steps it runs and how they connect. Posting one REPLACES the playbook. It does not merge.
    - `version` 1
    - `root` string, nullable: The first node, or null for an empty playbook.
    - `nodes` object
  - `step_count` integer
  - `newest_step_at` string, date-time, nullable
  - `ids` object: Posted node id → the id it now has on the server. Adopt these rather than re-posting your own.
  - `issues` GraphIssue[]: Warnings only: a save that landed can still name people the engine will hold back.
    - `severity` 'error' | 'warning'
    - `code` string: Stable kebab-case identity. Switch on this; the message is what a person reads.
    - `nodeId` string: The step it belongs to. Absent on issues about the playbook itself.
    - `message` string: A sentence naming the mistake AND the fix.

## Other responses

- `400`: Error
- `401`: Error
- `402`: Error
- `403`: The key is not outreach-scoped (code outreach_scope_required). Campaign paths need a key minted with the outreach scope at https://www.easeclaw.com/leads/api. The scope cannot be widened on an existing key.
- `404`: Error
- `409`: Error
- `422`: The request is well-formed but the SEQUENCE is not runnable (code invalid_graph). `issues` carries every error and every warning at once, each naming the fault and its fix, so the whole graph can be repaired in one pass.
- `429`: Rate limited (300/hour per account; drafting also 30/hour + daily AI budget). Retry-After header set when known.
- `500`: Error

---

[API](https://skmtc.dev/easeclaw/apis/easeclaw-api.md) · [All operations](https://skmtc.dev/easeclaw/apis/easeclaw-api/llms.txt) · [OpenAPI document](https://skmtc.dev/easeclaw/apis/easeclaw-api/revisions/79a190b20f61?raw)
