> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getsales.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Update agent plan

> The human verb on a plan, four intents in one call: approve it (state active), stop it (state canceled), rewrite its steps (texts included), or end its counting wait now (end_wait). The agent's own token is 403 forbidden (human_verb_only). A step edit replaces only what has not run; done, skipped or failed steps are locked (422). 409 plan_not_editable once completed, superseded or canceled; 409 plan_rewrite_in_flight while steer_agent_plan's rewrite moves.

Contract:
- MCP tool `update_agent_plan`, registry package `mcp.unibox/agent_plans`, mount `unibox.agent`.
- Operation `update`, response envelope `update`.
- Flags: none.



## OpenAPI

````yaml /api-reference/unibox/openapi.yaml patch /api/agent-plans/{sid}
openapi: 3.0.3
info:
  title: 'GetSales public contract: gs.service.unibox'
  description: >-
    The team inbox and the AI SDR: every LinkedIn and email thread in one place
    (conversations, messages, the timeline events), the manual tasks a thread
    spawns, the sender profiles the team speaks through with their LinkedIn
    account and mailboxes, and the one agent per team with its scenarios, plans
    and runs.


    GENERATED. This document is projected from the Zod MCP tool registry in
    `product/mcp/gs.mcp` (one tool per public endpoint, 1:1). Do not edit it by
    hand; edit the tool definition and regenerate with `pnpm openapi:public`.


    Surface: the public `/api` contract of `gs.service.unibox`, 125 operations.
    This is the only OpenAPI document the platform publishes. Internal
    (`/internal`) and health endpoints are deliberately absent: they are not
    part of any contract, they can change without notice, and the service source
    is their only description.


    Conventions:

    - Auth is a bearer JWT, optionally narrowed by the `Team-SID` header.

    - Every success body is an MCP envelope: `success: true` plus one typed
    `operation` shape (`search`, `get`, `create`, `update`, `delete`, `metrics`,
    `group_by`, `action`), and a `meta` block with `trace_id` for support.

    - Every failure is the same `McpError` envelope with a code from a fixed
    16-code taxonomy, so a client maps errors once.

    - Lists page with `page_size` (0 to 500, default 50) plus an opaque forward
    `cursor`; `page_size: 0` returns counts only.

    - On `GET` and `DELETE`, object-valued query parameters (`filter`, `sort`)
    travel as JSON text and array-valued ones repeat as `name[]=value`.

    - The MCP-only `_meta` field (usage analytics) never reaches the backend and
    is not part of this contract.
  version: '1.0'
  contact:
    name: GetSales
    url: https://getsales.io
    email: support@getsales.io
  license:
    name: Proprietary
    url: https://getsales.io/terms
servers:
  - url: https://beta.getsales.io/unibox/v1
    description: >-
      Production (the gateway path on the beta ring; the origin is provisioned
      per DEPLOY_MAP.md)
security:
  - BearerJwt: []
    TeamSid: []
tags:
  - name: agent_answers
    description: >-
      Registry package `mcp.unibox/agent_answers`, served on MCP mount
      `unibox.knowledge`.
  - name: agent_conversation_uploads
    description: >-
      Registry package `mcp.unibox/agent_conversation_uploads`, served on MCP
      mount `unibox.agent-memory`.
  - name: agent_examples
    description: >-
      Registry package `mcp.unibox/agent_examples`, served on MCP mount
      `unibox.agent-memory`.
  - name: agent_hints
    description: >-
      Registry package `mcp.unibox/agent_hints`, served on MCP mount
      `unibox.agent-memory`.
  - name: agent_plans
    description: >-
      Registry package `mcp.unibox/agent_plans`, served on MCP mount
      `unibox.agent`.
  - name: agent_runs
    description: >-
      Registry package `mcp.unibox/agent_runs`, served on MCP mount
      `unibox.agent-memory`.
  - name: agent_scenarios
    description: >-
      Registry package `mcp.unibox/agent_scenarios`, served on MCP mount
      `unibox.agent`.
  - name: agent_source_parses
    description: >-
      Registry package `mcp.unibox/agent_source_parses`, served on MCP mount
      `unibox.knowledge`.
  - name: agent_sources
    description: >-
      Registry package `mcp.unibox/agent_sources`, served on MCP mount
      `unibox.knowledge`.
  - name: agent_tests
    description: >-
      Registry package `mcp.unibox/agent_tests`, served on MCP mount
      `unibox.agent-memory`.
  - name: agents
    description: >-
      Registry package `mcp.unibox/agents`, served on MCP mount
      `unibox.website`.
  - name: conversation_events
    description: >-
      Registry package `mcp.unibox/conversation_events`, served on MCP mount
      `unibox.inbox`.
  - name: conversations
    description: >-
      Registry package `mcp.unibox/conversations`, served on MCP mount
      `unibox.inbox`.
  - name: messages
    description: >-
      Registry package `mcp.unibox/messages`, served on MCP mount
      `unibox.inbox`.
  - name: sender_profiles
    description: >-
      Registry package `mcp.unibox/sender_profiles`, served on MCP mount
      `unibox.sender-profiles`.
  - name: tasks
    description: Registry package `mcp.unibox/tasks`, served on MCP mount `unibox.inbox`.
  - name: timeline
    description: >-
      Registry package `mcp.unibox/timeline`, served on MCP mount
      `unibox.inbox`.
paths:
  /api/agent-plans/{sid}:
    patch:
      tags:
        - agent_plans
      summary: Update agent plan
      description: >-
        The human verb on a plan, four intents in one call: approve it (state
        active), stop it (state canceled), rewrite its steps (texts included),
        or end its counting wait now (end_wait). The agent's own token is 403
        forbidden (human_verb_only). A step edit replaces only what has not run;
        done, skipped or failed steps are locked (422). 409 plan_not_editable
        once completed, superseded or canceled; 409 plan_rewrite_in_flight while
        steer_agent_plan's rewrite moves.


        Contract:

        - MCP tool `update_agent_plan`, registry package
        `mcp.unibox/agent_plans`, mount `unibox.agent`.

        - Operation `update`, response envelope `update`.

        - Flags: none.
      operationId: update_agent_plan
      parameters:
        - name: sid
          in: path
          required: true
          description: Agent plan sid (ub_pl_…).
          schema:
            type: string
            minLength: 18
            maxLength: 18
            pattern: ^ub_pl_
            description: Agent plan sid (ub_pl_…).
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAgentPlanRequest'
      responses:
        '200':
          description: '`update` success envelope.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateAgentPlanResponse'
        4XX:
          $ref: '#/components/responses/McpClientError'
        5XX:
          $ref: '#/components/responses/McpServerError'
components:
  schemas:
    UpdateAgentPlanRequest:
      type: object
      description: Request body of `update_agent_plan`.
      properties:
        state:
          type: string
          enum:
            - active
            - canceled
          description: >-
            active approves a proposed plan (stamps approved_by_user_sid,
            releases the parked steps and arms the first one); canceled stops it
            and hands the thread back. Nothing else is accepted: completed and
            superseded are system-owned and rejected.
        steps:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
                nullable: true
                minimum: 1
                description: >-
                  The id of an existing non-terminal step to keep; omit (or send
                  null) for a new step, which gets a fresh id. Sending the id of
                  a done, skipped or failed step is a 422: terminal steps are
                  locked.
              kind:
                type: string
                enum:
                  - send_message
                  - wait_until
                  - wait_for_reply
                  - create_task
                  - move_stage
                  - find_people
                  - react
                  - like_post
                  - reach_objective
                  - resume_orchestration
                  - stoplist_person
                  - use_playbook
                description: >-
                  What this step does. Required on every entry whenever steps is
                  sent.
              params:
                type: object
                nullable: true
                additionalProperties: {}
                description: >-
                  The per-kind shapes and rules of create, replaced wholesale:
                  carry forward the keys to keep. A person may leave a message's
                  text out (the agent writes it when due) or write it as they
                  like, max 8000; a step sent back as stored is left as it is.
            required:
              - kind
          minItems: 1
          maxItems: 8
          description: >-
            Replaces the NON-TERMINAL tail of the plan, 1 to 8 entries. Done,
            skipped or failed steps stay untouched and may not appear; waits
            re-arm on the new values. Allowed while proposed or active. Leaving
            out a follow-up and its reply wait skips that follow-up.
        end_wait:
          type: boolean
          description: >-
            true: the wait the active plan is counting down ends now, so what
            follows goes at once, through the follow-up caps a wait that ran out
            meets. 409 no_wait_to_end when the next step is not a wait counting
            down. Runs after the other fields.
    UpdateAgentPlanResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - update
        item:
          type: object
          properties:
            sid:
              type: string
              description: Agent plan sid (ub_pl_…).
            team_sid:
              type: string
              description: Owning team (ts_tm_…, external - gs.service.id).
            agent_sid:
              type: string
              nullable: true
              description: >-
                The AI SDR the plan was made by (ub_ag_…, block 10, 2026-10-30);
                null on a row from before.
            conversation_sid:
              type: string
              description: >-
                The thread this plan belongs to (ub_cv_…). At most one plan per
                thread is live (proposed or active).
            state:
              type: string
              enum:
                - proposed
                - active
                - completed
                - superseded
                - canceled
              description: >-
                proposed = waiting for one-click approval, no step runs; active
                = executing or waiting on a timer; completed / superseded /
                canceled are terminal.
            goal:
              type: string
              description: >-
                Human-readable intent of the plan, 1..255 chars, e.g. "Re-engage
                after OOO on Aug 5".
            steps:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: integer
                    minimum: 1
                    description: >-
                      Plan-local step id, stable across edits. Assigned by the
                      server, counting from 1.
                  kind:
                    type: string
                    enum:
                      - send_message
                      - wait_until
                      - wait_for_reply
                      - create_task
                      - move_stage
                      - find_people
                      - react
                      - like_post
                      - reach_objective
                      - resume_orchestration
                      - stoplist_person
                      - use_playbook
                    description: What the step does.
                  params:
                    anyOf:
                      - type: object
                        additionalProperties: {}
                      - type: array
                        items: {}
                    description: >-
                      The step payload, frozen at planning time. Per kind:
                      send_message { intent, text, subject }, the message's
                      direction and, since 2026-10-05, its text exactly as it
                      goes out (an email's subject when it needs one): approving
                      the plan approves the text and the step sends it as
                      written, while a step with no text has its message written
                      when it comes due; wait_until { until, reason };
                      wait_for_reply { timeout_days, until }, until stamped by
                      the server when the wait begins; a message step also
                      carries the playbook's three product parameters since
                      2026-10-12, purpose (reply, follow_up, nudge, closing,
                      holding), link (none, when_natural, always: the text
                      carries the effective booking link, the campaign's or the
                      table's AI SDR setup over the team's) and length (short,
                      normal, full_picture), and the booking link is a
                      send_message with link always, the booking-link kind
                      retired and its stored plans rewritten; create_task {
                      title, due_in_days }; move_stage { target_stage_key }, one
                      of soft_interest, strong_interest, meeting_requested,
                      meeting_scheduled, closed_won, wrong_decision_maker,
                      not_now, unresponsive, not_interested, disqualified;
                      find_people { prompt, per_company_limit, company_sid,
                      company_name, estimated_credits }, where the last three
                      are stamped by the server (the company the search runs on
                      and the credits it is expected to spend; a step the CRM
                      could not price is refused, never stored); react { emoji,
                      message_sid }, the sender profile's reaction on the
                      LinkedIn message of theirs the step names (their newest
                      when the writer named none): the agent plans it on the
                      lead's first reply and when the stage move takes them
                      forward in the pipeline, and on a later reply only when
                      the lead made an effort in it (the heart on a warm reply,
                      a thumbs-up on any other; never on an automatic reply or a
                      do-not-contact); like_post {}, the sender profile's Like
                      on the lead's own latest LinkedIn post, picked when the
                      step runs (no plain repost, at most 90 days old, never one
                      the account liked already); reach_objective {}, the mark
                      of the live dialog's objective, run once the plan is
                      approved; resume_orchestration { reason }; stoplist_person
                      {}; use_playbook { from, outcome }, the stage the Playbook
                      starts the dialog at (engage, discover, bridge, offer,
                      after_yes; 2026-10-19) and, once the step is done, how the
                      Playbook's lead ended (said_yes, booked, signed_up,
                      registered, stalled_out, handed, left, cap).
                  state:
                    type: string
                    enum:
                      - pending
                      - awaiting_approval
                      - waiting
                      - done
                      - skipped
                      - failed
                    description: Where this step stands.
                  executed_at:
                    type: string
                    nullable: true
                    description: >-
                      ISO 8601 UTC, stamped when the step reached a terminal
                      state; null before that.
                  cause:
                    type: string
                    nullable: true
                    description: >-
                      Why the step was skipped or failed, or what a pending step
                      waits for, as a reason token (snake_case, 64 chars at
                      most, never a sentence: say it in your own words); null on
                      a step in any other state, and on one that ended before
                      2026-10-02. A pending step carries one only while the turn
                      that writes its message is held because the message could
                      not leave now: sender_unavailable (no sender profile
                      carries the account, or the account is signed out,
                      disconnected, stopped or paused; nothing is lost, the step
                      runs by itself once the account can send, so point the
                      user at the sender profile; after seven days of waiting
                      the step fails under the same token),
                      subscription_required (the workspace is on the billing
                      hold). A skipped step: not_linked (the thread is linked to
                      no person: move_stage, find_people, resume_orchestration);
                      already_beyond, stage_unknown, person_gone,
                      playtables_refused, target_stage_key_unknown (move_stage:
                      the person already stands further along the pipeline than
                      the stage and the agent never moves a person back, the
                      team has no stage under the key, the person is gone from
                      the CRM, the CRM refused, the step names no outcome
                      stage); no_company, no_company_anchor, person_not_found,
                      prompt_missing (find_people); sender_unavailable,
                      message_not_reactable, linkedin_refused, gtm_unavailable,
                      gtm_bridge_unavailable, gtm_busy, step_job_failed (react:
                      the account cannot act, the message takes no reaction,
                      LinkedIn said no, gtm-api did not answer or stayed busy,
                      the job that runs the reaction died; a reaction never
                      fails, whatever keeps it from landing is a skip and the
                      plan goes on); no_recent_post, already_liked,
                      not_on_linkedin, no_linkedin_profile, post_not_likeable,
                      gtm_scope_missing, gtm_access_lost, and, as for a
                      reaction, sender_unavailable, linkedin_refused,
                      gtm_unavailable, gtm_busy, step_job_failed (like_post: the
                      lead shows the account no recent post of their own (a
                      plain repost or a post older than 90 days does not count),
                      the account liked their latest post already, the thread
                      runs on no LinkedIn account, the lead has no profile the
                      account can open, LinkedIn takes no Like on the post, the
                      workspace connection lacks the engagements permission or
                      no longer shows the account; a Like never fails either, it
                      is skipped and the plan goes on); no_booking_link
                      (send_booking_link: the team lost its link after
                      planning); no_dialog, objective_already_reached
                      (reach_objective); no_step_transport (stoplist_person: the
                      block itself was applied when the reply was read). A
                      failed step carries the error code of the run that died on
                      it: playtables_unreachable (the CRM did not answer through
                      three tries), no_message_sent (the turn wrote no message),
                      turn_timeout, budget_exceeded, runner_error; or the reason
                      the send door refused the step's message with: stoplisted,
                      agent_disabled_on_thread (refused for good, the turn is
                      not tried again), send_refused (the door named no reason,
                      usually the thread has no account on the channel),
                      sender_unavailable or subscription_required (the step
                      waited for its sender for seven days, or the account
                      dropped on each of three tries). unknown stands for a
                      cause that was not a token. The list is open: read a token
                      you do not know as "it could not run".
                required:
                  - id
                  - kind
                  - params
                  - state
                  - executed_at
                  - cause
              description: >-
                Ordered steps, 1..8. They run in order; a failed one stops the
                plan.
            created_by_run_sid:
              type: string
              description: >-
                The strategize run that produced this plan (ub_rn_…). Its
                reason, confidence and LLM log ref answer "why this plan".
            behavior:
              type: string
              nullable: true
              enum:
                - answer_interested
                - meeting_request_book
                - answer_info_request
                - referral_capture
                - not_now_defer
                - ooo_delay_ping
                - auto_reply_skip
                - wrong_person_referral
                - reschedule_meeting
                - cancel_meeting
                - return_to_orchestration
                - close_not_interested
                - handle_objection
                - stoplist_do_not_contact
                - vendor_pitch_skip
                - acknowledge_low_signal
                - followup_no_reply
                - signal_followup
                - followup_after_person
              description: >-
                The built-in competence module that planned; null when a matched
                custom scenario drove the plan on its own.
            behavior_version:
              type: integer
              nullable: true
              minimum: 1
              description: >-
                Version of that module at planning time (the audit stamp,
                rendered as "answer_interested v3"); null when behavior is null.
            custom_scenario_sid:
              type: string
              nullable: true
              description: >-
                The custom scenario that matched (ub_sc_…), which takes
                precedence over the built-in behavior; null when none did. The
                sid survives the scenario being deleted.
            approved_by_user_sid:
              type: string
              nullable: true
              description: >-
                User that approved a proposed plan; null while unapproved or
                when the plan was born active under autopilot.
            created_at:
              type: string
              description: ISO 8601 UTC.
            updated_at:
              type: string
              description: ISO 8601 UTC.
            deleted_at:
              type: string
              nullable: true
              description: >-
                ISO 8601 UTC. Always null in practice: plans have no delete
                path, the terminal states cover removal.
          required:
            - sid
            - team_sid
            - agent_sid
            - conversation_sid
            - state
            - goal
            - steps
            - created_by_run_sid
            - behavior
            - behavior_version
            - custom_scenario_sid
            - approved_by_user_sid
            - created_at
            - updated_at
            - deleted_at
        updated_fields:
          type: array
          items:
            type: string
        previous_values:
          type: object
          additionalProperties: {}
        kept_fields:
          type: array
          items:
            type: string
          description: >-
            The fields this write did not change because the person's own value
            stands on them (stamped person); read the item for what landed.
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: >-
                The team this call ran in (the token team, or the team_sid
                override). Null when unauthenticated; absent from pre-2026-08-20
                backends.
            actor_type:
              type: string
              nullable: true
              description: >-
                user | agent | api_key | system. Null when unauthenticated;
                absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - item
        - updated_fields
        - previous_values
        - meta
    McpError:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - validation_failed
                - nothing_to_update
                - not_found
                - relation_not_found
                - invalid_transition
                - limit_exceeded
                - payment_required
                - duplicate_rejected
                - conflict
                - delete_blocked
                - unauthorized
                - forbidden
                - rate_limited
                - internal_error
                - service_unavailable
                - not_implemented
            message:
              type: string
            recoverable:
              type: boolean
            suggestion:
              type: string
            field_errors:
              type: object
              additionalProperties:
                type: array
                items:
                  type: object
                  properties:
                    rule:
                      type: string
                    message:
                      type: string
                  required:
                    - rule
                    - message
            blockers:
              type: array
              items:
                type: object
                properties:
                  type:
                    type: string
                    description: >-
                      Machine-readable blocker type (active_flow, pending_tasks,
                      …).
                  severity:
                    type: string
                    enum:
                      - hard
                      - soft
                    description: >-
                      hard = external action required; soft = acknowledge is
                      enough.
                  description:
                    type: string
                  entity_sid:
                    type: string
                    nullable: true
                  count:
                    type: integer
                  resolution:
                    type: string
                    description: 'Hard: tool name to call. Soft: code for acknowledge[].'
                  resolution_hint:
                    type: string
                required:
                  - type
                  - severity
                  - description
                  - entity_sid
                  - resolution
                  - resolution_hint
            context:
              type: object
              additionalProperties: {}
          required:
            - code
            - message
            - recoverable
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: >-
                The team this call ran in (the token team, or the team_sid
                override). Null when unauthenticated; absent from pre-2026-08-20
                backends.
            actor_type:
              type: string
              nullable: true
              description: >-
                user | agent | api_key | system. Null when unauthenticated;
                absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - error
  responses:
    McpClientError:
      description: >-
        MCP error envelope. `error.code` is one of validation_failed,
        nothing_to_update, not_found, relation_not_found, invalid_transition,
        limit_exceeded, payment_required, duplicate_rejected, conflict,
        delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/McpError'
    McpServerError:
      description: >-
        MCP error envelope with `error.code` internal_error or
        service_unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/McpError'
  securitySchemes:
    BearerJwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Access token issued by gs.service.id. Its `access_identity` claim
        carries `team_sid`, `actor_sid` and `actor_type`, and that team scope is
        authoritative.
    TeamSid:
      type: apiKey
      in: header
      name: Team-SID
      description: >-
        Team scope for tokens that do not carry one. Ignored when the token
        already names a team.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.