---
title: "Replace a sequence's steps as a new revision"
method: PUT
path: "/sequences/{id}"
tags: ["Sequences"]
---

# Replace a sequence's steps as a new revision

`PUT /sequences/{id}`

## Request

- Base URL: `https://app.pumpgtm.com/api/v1`
- URL: `https://app.pumpgtm.com/api/v1/sequences/{id}`
- Auth: HTTP bearer

Complete revisioned replacement: read GET /sequences/{id} first and send the full step list (stepIndex, messageTmpl) with the current revision from that response; the compact list shape is not accepted. With a customer credential the new revision is re-approved and the sequence returns to its previous status (active stays active, paused stays paused, a draft goes live). Omitted executionModel keeps the current one and may change only on a draft nobody has been worked through. 409 with nothing changed: sequence_revision_conflict, sequence_edit_request_conflict, sequence_has_progress, archived_sequence_is_read_only, sequence_must_be_draft, sequence_steps_invalid; the body carries update.currentRevision where known.

## Path parameters

- `id` string, uuid, required

## Headers

- `X-PumpGTM-Client` string, uuid
- `X-PumpGTM-User` string

## Request body

- object
  - `requestId` string: Optional idempotency key; reuse it only to retry this exact request. Omitted means a fresh request.
  - `expectedRevision` integer, required: Current saved revision. Fetch again after a 409; do not silently retry a changed plan.
  - `name` string
  - `steps` object[], required: The complete ordered list. With any LinkedIn step, step 0 must be connect.
    - `stepIndex` integer: Optional zero-based position; when supplied it must match the array index.
    - `kind` 'connect' | 'message' | 'engage' | 'email' | 'x_dm' | 'x_engage' | 'instagram_dm', required
    - `delayDays` integer, required: Days after the previous step; the step after connect waits for acceptance.
    - `subject` string, nullable: Email steps only; required on the first email.
    - `messageTmpl` string, nullable: Required for email, x_dm and instagram_dm; a LinkedIn message may instead put text on every variant. {{firstName}} {{fullName}} {{company}} {{title}} render on every channel.
    - `sendIf` 'followed_back' | 'not_followed_back', nullable: x_dm only: DM only people who followed back after an earlier x_engage follow, or only those who did not.
    - `actions` object[]: Required and non-empty for engage or x_engage; x_engage supports follow and unfollow only.
      - `type` 'follow' | 'unfollow' | 'view_profile' | 'like_last_post' | 'endorse_first_skill' | 'comment_last_post', required
      - `count` integer
      - `reaction` 'like' | 'celebrate' | 'support' | 'love' | 'insightful' | 'funny'
      - `text` string
    - `variants` object[], nullable
      - `key` string, required
      - `weight` integer, required
      - `messageTmpl` string
    - `tool` object, nullable: Message steps only. Either { kind: "customer_input", tokens: ["video_url"] } (1-5 lowercase tokens the customer supplies per person through POST /leads/{id}/input) or a personalised video generated by the connected video tool: { kind: "sendspark", params, outputToken?: "video_url", timeoutHours?: 1-168, fallback?: "send_without" | "skip_step" }.
      - `kind` 'customer_input' | 'sendspark', required
  - `executionModel` 'linear' | 'tracks': linear (default) runs steps in order; tracks runs LinkedIn, email and X steps as parallel lanes per person and needs the multichannel_tracks feature.
  - `xThreadCheck` boolean: Workspace-wide X setting, applies to every sequence: check the conversation before each X DM so nobody the customer already talks to is messaged (5 Energy per DM instead of 0.6). Default off.

## Response `200`

Successful response. Read outcome fields; success does not imply delivery.

- object
  - `update` object, required: { ok: true, replayed, sequence, live, change: { previousRevision, revision, currentRevision, previousStatus, nameChanged, stepCountBefore, stepCountAfter, changedStepIndexes, approvalInvalidated } }
  - `reviewUrl` string, required

## Other responses

- `400`: Invalid input; for partner keys also user_header_required when the account requires X-PumpGTM-User
- `401`: Missing, invalid or revoked key
- `403`: Workspace mismatch, channel or feature disabled; for partner keys also enterprise_required and user_disabled
- `404`: Resource unavailable in this workspace
- `409`: Revision, identity or state conflict: { error, message } and nothing changed
- `429`: Rate limit; respect Retry-After when provided
- `500`: internal_error: an unexpected failure on our side; retry, then contact PumpGTM
- `503`: Dependency unavailable; identity may be unknown

## Changes

- **2026-10-12** `06d2e4d0e84b`: 8 info
  - the response property `error` became required for the status `400`
  - the response property `error` became required for the status `401`
  - the response property `error` became required for the status `403`
  - the response property `error` became required for the status `404`
  - …4 more
- **2026-10-12** `08c80059d483`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/pumpgtm/apis/pumpgtm-api/changes/sequences/:id/put.md)

---

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