Topolo Docs Topolo Platform
Open workspace

Create sequence draft version

Start the next draft from the latest published sequence version.

Outcome

Start the next draft from the latest published sequence version.

Before you start

  • Verify the environment, credential, authorized organization and the published action permission workspace:write.
  • Discover an accessible Engage workspace and bind resourceType=workspace and its resourceId separately from action input. Fixture identifiers grant no access.
  • Approve the exact mutation and its effects before CLI --confirm or MCP confirm:true. This documentation does not authorize outreach.

Discover the target

  • Discover the sequence through sequences.list using the retained campaignId, then read sequences.get in the same authorized workspace. Inspect sequence.status, draft, published and versions before planning.
topolo whoami --json
topolo actions get app_topolo_engage.sequences.versions.create --json
topolo workspaces list topolo-engage --json

Input fields

FieldRequiredMeaning and constraints
idYesRequired sequence identifier discovered through sequences.list in the selected workspace, trimmed non-empty string up to 128 characters.

Validate, plan and execute

Set ENGAGE_WORKSPACE_ID to the identifier of your selected workspace. Prepare payload.json from the current input schema and discovered identifiers. Use the same payload for validation, planning and execution.

: "${ENGAGE_WORKSPACE_ID:?Set ENGAGE_WORKSPACE_ID to your selected workspace identifier}"
topolo actions validate app_topolo_engage.sequences.versions.create --data @payload.json --json
topolo actions plan app_topolo_engage.sequences.versions.create --resource-type workspace --resource-id "$ENGAGE_WORKSPACE_ID" --data @payload.json --confirm --json

Review the plan and obtain approval for the exact effects before executing the unchanged request.

: "${ENGAGE_WORKSPACE_ID:?Set ENGAGE_WORKSPACE_ID to your selected workspace identifier}"
topolo actions call app_topolo_engage.sequences.versions.create --resource-type workspace --resource-id "$ENGAGE_WORKSPACE_ID" --data @payload.json --confirm --json

For MCP, use topolo_get_action, topolo_validate_action, topolo_plan_action and topolo_call_action. Pass the selected resource context separately; confirm:true is required for mutations.

Worked requests and responses

Captured sequences.versions.create · HTTP 201

Action input

{
  "id": "eng_seq_1"
}

Actual local response

{
  "version": {
    "id": "eng_seqv_2",
    "sequenceId": "eng_seq_1",
    "version": 2,
    "status": "draft",
    "publishedAt": null,
    "createdAt": "2026-10-06T08:30:00.000Z",
    "steps": [
      {
        "id": "eng_stp_4",
        "position": 1,
        "type": "linkedin_task",
        "delayDays": 0,
        "subjectTemplate": "",
        "bodyTemplate": "",
        "threadWithPrevious": false,
        "instructions": "Send a connection request mentioning the webinar.",
        "dueDays": 2
      },
      {
        "id": "eng_stp_5",
        "position": 2,
        "type": "email",
        "delayDays": 3,
        "subjectTemplate": "Hello {{first_name}}",
        "bodyTemplate": "Hi {{first_name}}",
        "threadWithPrevious": false,
        "instructions": "",
        "dueDays": 0
      },
      {
        "id": "eng_stp_6",
        "position": 3,
        "type": "call_task",
        "delayDays": 2,
        "subjectTemplate": "",
        "bodyTemplate": "",
        "threadWithPrevious": false,
        "instructions": "Call the main office.",
        "dueDays": 0
      }
    ]
  }
}

Source test: task steps in sequences > stores linkedin_task and call_task steps with instructions and a due offset, and copies them into a new version. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured sequences.versions.create · HTTP 201

Action input

{
  "id": "eng_seq_1"
}

Actual local response

{
  "version": {
    "id": "eng_seqv_2",
    "sequenceId": "eng_seq_1",
    "version": 2,
    "status": "draft",
    "publishedAt": null,
    "createdAt": "2026-10-06T08:30:00.000Z",
    "steps": [
      {
        "id": "eng_stp_3",
        "position": 1,
        "type": "email",
        "delayDays": 0,
        "subjectTemplate": "Quick question, {{first_name}}",
        "bodyTemplate": "Hi {{first_name}},\n\nHow is {{company}} handling outreach?\n\n{{sender_name}}",
        "threadWithPrevious": false,
        "instructions": "",
        "dueDays": 0
      },
      {
        "id": "eng_stp_4",
        "position": 2,
        "type": "email",
        "delayDays": 4,
        "subjectTemplate": "",
        "bodyTemplate": "Following up, {{first_name}}.",
        "threadWithPrevious": true,
        "instructions": "",
        "dueDays": 0
      }
    ]
  }
}

Source test: sequence routes > creates a sequence with an empty draft, edits steps, publishes and freezes the version. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured sequences.versions.create · HTTP 201

Action input

{
  "id": "eng_seq_1"
}

Actual local response

{
  "version": {
    "id": "eng_seqv_2",
    "sequenceId": "eng_seq_1",
    "version": 2,
    "status": "draft",
    "publishedAt": null,
    "createdAt": "2026-10-06T08:30:00.000Z",
    "steps": [
      {
        "id": "eng_stp_3",
        "position": 1,
        "type": "email",
        "delayDays": 0,
        "subjectTemplate": "Hello {{first_name}}",
        "bodyTemplate": "Hi {{first_name}}, a short note about the webinar.",
        "threadWithPrevious": false,
        "instructions": "",
        "dueDays": 0
      },
      {
        "id": "eng_stp_4",
        "position": 2,
        "type": "whatsapp_template",
        "delayDays": 1,
        "subjectTemplate": "",
        "bodyTemplate": "",
        "threadWithPrevious": false,
        "instructions": "",
        "dueDays": 0,
        "whatsappTemplate": {
          "templateName": "webinar_invite",
          "language": "en_GB",
          "variables": [
            "first_name"
          ]
        }
      }
    ]
  }
}

Source test: WhatsApp template steps in sequences > stores the template with its variables, copies it into a new version and gets no email copy findings. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Effects and response meaning

  • Creates draft version max(version)+1 with HTTP 201. Copies latest published steps with newly generated step ids; if no published version exists, the draft is empty. Only one draft may exist; an existing draft or archived sequence is refused.
  • Published versions and their enrollment pins remain unchanged. This does not publish, enroll or send anything.

Verify the result

  • Read sequences.get and sequences.versions.get using returned version.id. Confirm the intended sequenceId, draft status, version number and copied step contents; do not compare old/new step ids as identical.

Recover

After an uncertain creation, read sequences.get and inspect its draft before retrying. A conflict can mean the draft was already created; compare source contents and sequence identity. Do not publish or replace a draft just to clear a creation conflict.

Refused responses

Captured sequences.versions.create · HTTP 409

Action input

{
  "id": "eng_seq_1"
}

Actual local response

{
  "error": {
    "code": "state_conflict",
    "message": "This sequence already has a draft version."
  }
}

Source test: sequence routes > creates a sequence with an empty draft, edits steps, publishes and freezes the version. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured sequences.versions.create · HTTP 409

Action input

{
  "id": "eng_seq_1"
}

Actual local response

{
  "error": {
    "code": "state_conflict",
    "message": "Archived sequences cannot be changed."
  }
}

Source test: sequence routes > allows one live sequence per campaign and refuses archived campaigns. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Error recovery

  • HTTP 403 permission_denied: Stop and inspect the permission required by this action in the current credential. Do not broaden permissions or switch organization automatically.
  • HTTP 422 invalid_action_input: Correct required fields, enums and nested step bounds against the current input schema, then validate the exact intended payload again.
  • HTTP 409 state_conflict: Read sequences.get and the exact version. Archived sequences cannot change, only one non-archived sequence per campaign and one draft per sequence may exist, and published versions cannot be edited. Re-plan only a legal, separately approved operation.

Evidence and limits

  • contracts/sequences.mjs

  • apps/api/src/sequences/sequences-handlers.ts

  • apps/api/src/sequences/sequences-domain.ts

  • apps/api/src/sequences/sequences-repository.ts

  • apps/api/src/copy-qa/version-steps.ts

  • apps/api/src/copy-qa/copy-qa.ts

  • Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

  • Widget/bootstrap use actual app handler but mocked worker runtime and app identity.

  • No gateway execution, live permissions, external delivery or deployed proof.

The examples are local route captures with synthetic context and simulated providers. They do not prove live authorization, CLI/MCP gateway execution, production state or delivery.