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

# Withdraw a change-request endorsement

> UnendorseChangeRequest removes the caller from the endorser set (idempotent). Gated like EndorseChangeRequest.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/change-request/{id}/unendorse
openapi: 3.0.0
info:
  title: Murmur REST API
  description: >-
    PRE-ALPHA: INTERFACE SUBJECT TO CHANGE WITHOUT NOTICE.


    The murmur REST API lets you spawn agents, track their progress, manage
    their task lists, and read and write catalog resources from any HTTP client.
  version: v1
servers:
  - url: https://api.murmur.dev
security:
  - ApiKey: []
tags:
  - name: MurmurService
paths:
  /v1/change-request/{id}/unendorse:
    post:
      tags:
        - MurmurService
      summary: Withdraw a change-request endorsement
      description: >-
        UnendorseChangeRequest removes the caller from the endorser set
        (idempotent). Gated like EndorseChangeRequest.
      operationId: MurmurService_UnendorseChangeRequest
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MurmurServiceUnendorseChangeRequestBody'
        required: true
      responses:
        '200':
          description: A successful response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/v1UnendorseChangeRequestResponse'
        default:
          description: An unexpected error response.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/googleRpcStatus'
components:
  schemas:
    MurmurServiceUnendorseChangeRequestBody:
      type: object
      properties:
        tenant:
          $ref: '#/components/schemas/v1Tenant'
      description: >-
        UnendorseChangeRequest removes the caller from the endorser set
        (idempotent —

        removing when absent is a no-op). Gated identically to
        EndorseChangeRequest.
    v1UnendorseChangeRequestResponse:
      type: object
      properties:
        changeRequest:
          $ref: '#/components/schemas/v1CatalogChangeRequest'
    googleRpcStatus:
      type: object
      properties:
        code:
          type: integer
          format: int32
          description: >-
            Numeric status code for the failure, matching the HTTP status of the
            response via the standard mapping (e.g. 3 INVALID_ARGUMENT → 400, 5
            NOT_FOUND → 404, 7 PERMISSION_DENIED → 403, 16 UNAUTHENTICATED →
            401).
        message:
          type: string
          description: Human-readable description of what caused the failure.
        details:
          type: array
          items:
            $ref: '#/components/schemas/protobufAny'
          description: >-
            Machine-readable error details, when the failure carries them.
            Usually empty.
      description: The error envelope returned on every non-2xx response.
    v1Tenant:
      type: object
      properties:
        provider:
          $ref: '#/components/schemas/v1Provider'
        org:
          type: string
          title: username or org name
      description: |-
        Tenant identifies an organization within a provider. It is the unit of
        multi-tenant scoping — all resources (agents, pools, VMs) belong to
        exactly one tenant.
    v1CatalogChangeRequest:
      type: object
      properties:
        id:
          type: string
          description: >-
            Server-generated opaque id (e.g. "cr-a1b2c3"). Also the catalog
            name.
        targetKind:
          type: string
          description: Catalog Kind of the resource being changed (e.g. "recipe", "role").
        targetName:
          type: string
          description: Name of the target resource within target_kind.
        proposedPayload:
          type: string
          format: byte
          description: >-
            The full proposed value: the target kind's resource document as
            base64-encoded JSON. Not a diff — it validates directly against the
            target schema and applies as a full replace.
        baseVersion:
          type: string
          format: int64
          description: >-
            Version generation of the target observed at propose time, for
            conflict detection at apply. 0 means the target did not exist at
            propose time.
        status:
          $ref: '#/components/schemas/v1ChangeRequestStatus'
        proposer:
          $ref: '#/components/schemas/v1Principal'
        approver:
          $ref: '#/components/schemas/v1Principal'
        rationale:
          type: string
          title: optional justification from the proposer
        decisionNote:
          type: string
          title: optional note from the approver/rejecter
        createdAt:
          type: string
          format: date-time
        decidedAt:
          type: string
          format: date-time
          title: set on approve or reject
        appliedAt:
          type: string
          format: date-time
          title: set on successful apply
        appliedGeneration:
          type: string
          format: int64
          description: >-
            Version generation produced by the apply write. Recorded once
            APPLIED; makes apply idempotent and lets consumers point at the
            exact new version.
        endorsers:
          type: array
          items:
            $ref: '#/components/schemas/v1Endorser'
          description: >-
            Who has endorsed this change-request — an advisory demand signal
            that never feeds approval authorization. Each endorser appears at
            most once; endorsing is idempotent. Mutable only while PENDING or
            APPROVED; frozen once terminal.
        source:
          $ref: '#/components/schemas/v1ChangeSource'
        bake:
          $ref: '#/components/schemas/v1BakeAction'
        spawn:
          $ref: '#/components/schemas/v1SpawnAction'
      description: >-
        CatalogChangeRequest wraps a proposed change to ANY catalog resource and

        gates it behind an approval. It is generic over catalog Kind:
        target_kind

        names the kind, proposed_payload is the full proposed value for that
        kind,

        and apply reuses the same write path SetResource uses. Recipe is one

        possible target_kind, not a special case.
    protobufAny:
      type: object
      properties:
        '@type':
          type: string
          description: >-
            Identifies the payload type of this detail value; the remaining
            properties are that type's fields.
      additionalProperties: {}
      description: >-
        A structured detail value. `@type` identifies the payload type; the
        remaining properties are that type's fields.
    v1Provider:
      type: string
      enum:
        - PROVIDER_UNSPECIFIED
        - PROVIDER_GITHUB_OAUTH
        - PROVIDER_GITHUB_APP
        - PROVIDER_GOOGLE_OIDC
        - PROVIDER_SERVICE_PROFILE
      default: PROVIDER_UNSPECIFIED
      description: |-
        Provider identifies the identity provider type for a tenant namespace.
        Each provider is a distinct namespace — no cross-provider mixing.

         - PROVIDER_GITHUB_OAUTH: the namespace of an individual GitHub user — a single login (human or bot, e.g. "alice"), addressed as github_oauth/{login}
         - PROVIDER_GITHUB_APP: the org/tenant namespace — its account is the org name (github_app/{org}), never a person
         - PROVIDER_GOOGLE_OIDC: Google Workspace domain
         - PROVIDER_SERVICE_PROFILE: owner is a CatalogServiceProfile; account is the profile name
    v1ChangeRequestStatus:
      type: string
      enum:
        - CHANGE_REQUEST_STATUS_UNSPECIFIED
        - CHANGE_REQUEST_STATUS_PENDING
        - CHANGE_REQUEST_STATUS_APPROVED
        - CHANGE_REQUEST_STATUS_APPLIED
        - CHANGE_REQUEST_STATUS_REJECTED
      default: CHANGE_REQUEST_STATUS_UNSPECIFIED
      description: >-
        ChangeRequestStatus is the lifecycle state of a CatalogChangeRequest.

        PENDING -> APPROVED -> APPLIED on the happy path; REJECTED is terminal.

        APPROVED is retriable: a failed apply leaves the record APPROVED, not
        stuck.

         - CHANGE_REQUEST_STATUS_PENDING: awaiting review
         - CHANGE_REQUEST_STATUS_APPROVED: approval recorded; apply pending or failed (retriable)
         - CHANGE_REQUEST_STATUS_APPLIED: target written; terminal
         - CHANGE_REQUEST_STATUS_REJECTED: declined; terminal
    v1Principal:
      type: object
      properties:
        provider:
          $ref: '#/components/schemas/v1Provider'
        account:
          type: string
      description: >-
        Principal identifies the actor a caller authenticates as within a
        tenant:

        either an IdP user (provider = the auth provider, account = username) or
        a

        service profile (provider = PROVIDER_SERVICE_PROFILE, account = profile

        name). It is the "who" that owns a self-listable namespace, distinct
        from

        Tenant's "where". The two map directly onto an AgentId's owner_provider
        and

        account. An unset Principal means the caller owns no self-listable
        namespace

        (e.g. a plain token key or an agent-runtime credential).
    v1Endorser:
      type: object
      properties:
        principal:
          $ref: '#/components/schemas/v1Principal'
        agent:
          $ref: '#/components/schemas/v1AgentId'
      description: >-
        Endorser identifies who thumbs-upped a change-request. It is exactly one
        of:

        a Principal — an IdP user (e.g. github_oauth/"alice") or a service
        profile

        (e.g. service_profile/"merge-queue"), the actor that owns a namespace;
        or an

        AgentId — a running agent endorsing on its own behalf (an agent-runtime

        caller, which has no Principal). The server stamps this from the

        authenticated caller, never from the request — the same provenance rule
        a

        change-request's proposer/approver follow.
    v1ChangeSource:
      type: object
      properties:
        imageRollout:
          $ref: '#/components/schemas/v1ImageRolloutSource'
        recipeBake:
          $ref: '#/components/schemas/v1RecipeBakeSource'
      description: >-
        What generated a system-proposed change-request, with origin-specific
        detail. Unset on manually proposed change-requests.
    v1BakeAction:
      type: object
      properties:
        recipeRef:
          type: string
          description: Recipe name to bake. Required.
        environmentRef:
          type: string
          description: Environment name providing the scratch VM machine shape. Required.
        placementRef:
          type: string
          description: Placement name determining where the image is baked. Required.
        serviceProfile:
          type: string
          description: >-
            Service profile minted at bake time for the bake VM's credentials.
            Required.
        serviceAccount:
          type: string
          description: >-
            Cloud IAM identity for the bake VM. Required when the placement has
            service-account bindings; empty otherwise.
        forceNew:
          type: boolean
          description: Skip the image cache and force a fresh bake.
      description: >-
        An executable change-request verb: bake this recipe, in this placement,
        on this environment's machine shape, using this service profile's
        credentials. Approving the change-request executes the bake. Validation
        resolves the full spec at propose time and again at approve.
        Authorization binds the approver: bake.create plus
        service-profile.assume (and placement-sa.assume when a service account
        is pinned).
    v1SpawnAction:
      type: object
      properties:
        slug:
          type: string
          description: The spawned agent's slug. Required.
        workspace:
          type: string
          description: Workspace the agent runs in. Required.
        serviceProfile:
          type: string
          description: Service profile whose credentials the agent acts as. Required.
        description:
          type: string
          description: The task — the agent's initial prompt. Required.
        persona:
          type: string
          description: Agent persona.
        model:
          type: string
          description: Model override.
        expectedOutput:
          type: string
          description: 'Expected output: pr (default), push, respond, or freeform.'
        tags:
          type: array
          items:
            type: string
          description: Dashboard tags applied to the spawned agent.
        onIdle:
          $ref: '#/components/schemas/v1OnIdle'
        purpose:
          type: string
          description: One-sentence goal shown in the dashboard (max 240 chars).
        tasks:
          type: array
          items:
            type: string
          description: Checklist item subjects the agent must complete.
        reasoningEffort:
          type: string
          description: Reasoning effort (empty = model default).
        suppressedEventClasses:
          type: array
          items:
            $ref: '#/components/schemas/v1FollowUpEventClass'
          description: GitHub event classes the spawned agent ignores (never woken by).
        dequeueStrategy:
          $ref: '#/components/schemas/v1DequeueStrategy'
        suggestTerminateMode:
          $ref: '#/components/schemas/v1SuggestTerminateMode'
      description: >-
        An executable change-request verb: spawn an agent with this slug, in
        this workspace, on this task, acting as this service profile. Approving
        the change-request executes the spawn. Authorization binds the approver:
        service-profile.assume on the action's profile. Idempotent per slug: a
        re-approve while the execution is live joins it.
    v1AgentId:
      type: object
      properties:
        tenant:
          $ref: '#/components/schemas/v1Tenant'
        ownerProvider:
          $ref: '#/components/schemas/v1Provider'
        account:
          type: string
          description: >-
            Owner account: username for identity-provider owners,
            service-profile name for PROVIDER_SERVICE_PROFILE.
        agent:
          type: array
          items:
            type: string
          title: |-
            Agent path — the hierarchy from root to leaf.
            Root agent:  ["fix-bug"]
            Child:       ["fix-bug", "api"]
            Grandchild:  ["fix-bug", "api", "tests"]
        workspace:
          type: string
          description: >-
            Workspace this agent belongs to; scopes its repos, environment, and
            base branches. Optional at spawn: when empty, the server selects
            one, so a returned AgentId always carries a concrete workspace.
      description: >-
        Identifies an agent. The identity is (tenant, workspace, owner, agent
        path); the workspace scopes the agent's repos, environment, and base
        branches.
    v1ImageRolloutSource:
      type: object
      properties:
        recipeRef:
          type: string
          title: recipe whose completed bake triggered this rollout
        imageHash:
          type: string
          title: 64-char SHA-256 hash of the image this proposal currently names
      description: >-
        ImageRolloutSource marks a change-request the platform opened to repoint
        a

        workspace's image_ref at a freshly baked image, and records which bake.
    v1RecipeBakeSource:
      type: object
      properties:
        recipeRef:
          type: string
          title: recipe whose modification proposed this re-bake
      description: >-
        Marks a change-request the platform opened to re-bake a standing bake
        record after its recipe was modified: approving it re-runs the bake
        against the recipe's new content.
    v1OnIdle:
      type: string
      enum:
        - ON_IDLE_UNSPECIFIED
        - ON_IDLE_SLEEP
        - ON_IDLE_TERMINATE
        - ON_IDLE_KEEP_ALIVE
      default: ON_IDLE_UNSPECIFIED
      description: |-
        OnIdle determines what happens when the agent has no more work after
        task completion (and optional completion check).

         - ON_IDLE_SLEEP: Hibernate/suspend VM, wait for follow-up or cancel.
         - ON_IDLE_TERMINATE: End the agent and destroy its VM.
         - ON_IDLE_KEEP_ALIVE: VM stays running, session stays live. Periodic session backup every 30m.
    v1FollowUpEventClass:
      type: string
      enum:
        - FOLLOW_UP_EVENT_CLASS_UNSPECIFIED
        - FOLLOW_UP_EVENT_CLASS_CI
        - FOLLOW_UP_EVENT_CLASS_PR_COMMENTS
      default: FOLLOW_UP_EVENT_CLASS_UNSPECIFIED
      description: >-
        A user-suppressible category of follow-up event. Only events that wake
        an already-running agent are classifiable; spawn-trigger and
        orchestration events are never suppressible.

         - FOLLOW_UP_EVENT_CLASS_UNSPECIFIED: not a suppressible event
         - FOLLOW_UP_EVENT_CLASS_CI: ci_result
         - FOLLOW_UP_EVENT_CLASS_PR_COMMENTS: pr_comment, pr_review
    v1DequeueStrategy:
      type: string
      enum:
        - DEQUEUE_STRATEGY_UNSPECIFIED
        - DEQUEUE_STRATEGY_ALL
        - DEQUEUE_STRATEGY_ONE
        - DEQUEUE_STRATEGY_FIVE
        - DEQUEUE_STRATEGY_AUTO
      default: DEQUEUE_STRATEGY_UNSPECIFIED
      description: |-
        Controls how queued follow-up messages are drained between agent turns.

         - DEQUEUE_STRATEGY_UNSPECIFIED: Default: AUTO.
         - DEQUEUE_STRATEGY_ALL: Drain all queued follow-ups into one batch.
         - DEQUEUE_STRATEGY_ONE: Drain one follow-up per turn.
         - DEQUEUE_STRATEGY_FIVE: Drain up to five follow-ups per turn.
         - DEQUEUE_STRATEGY_AUTO: Drain up to five follow-ups of one kind per turn — manual follow-ups and auto-generated events are never delivered in the same turn (kind-boundary batching, capped at five).
    v1SuggestTerminateMode:
      type: string
      enum:
        - SUGGEST_TERMINATE_MODE_UNSPECIFIED
        - SUGGEST_TERMINATE_MODE_SUGGEST
        - SUGGEST_TERMINATE_MODE_IMMEDIATE
      default: SUGGEST_TERMINATE_MODE_UNSPECIFIED
      description: >-
        - SUGGEST_TERMINATE_MODE_UNSPECIFIED: inherit (workspace, then the
        SUGGEST default)

         - SUGGEST_TERMINATE_MODE_SUGGEST: advisory only: the dashboard renders a delete button; a human decides
         - SUGGEST_TERMINATE_MODE_IMMEDIATE: terminate the agent immediately, no delete button
  securitySchemes:
    ApiKey:
      type: http
      scheme: bearer
      description: 'murmur API key: mur_<key_id>.<secret>'

````