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

# Edit author-editable metadata on a single tool (response_field_map, is_enabled, input_defaults — defaults + pinned)

> Update author-editable tool metadata.

Three mutable fields:

* ``response_field_map`` — the customer-owned field map
  (``{"field_mappings": [...]}``) selecting which response fields the agent
  receives. Narrows the agent-facing payload and drives the AOP compiler's
  ``kind=llm`` → ``kind=action`` promotion (ENG-631). Omit the field to
  no-op; pass an explicit ``null`` to clear. The response *shape*
  (``response_schema``) is sync-owned and read-only over this API (D2), so
  it is rejected by the request schema's ``extra="forbid"``.
* ``is_enabled`` — turn the individual tool on/off (the PRD's per-tool
  toggle). A disabled tool is excluded from resolution, so the agent can no
  longer call it. Omit to no-op.
* ``input_defaults`` — operator input-arg config for input fields
  (``{field_name: {"value": ..., "type": "default"|"pinned"}}``, ENG-590). A
  ``default`` is a suggestion the agent may overwrite; a ``pinned`` value the
  caller cannot overwrite. Validated against the tool's current
  ``input_schema``: an unknown field or wrong-type value is rejected with a
  422 listing each offending field. Omit to no-op; pass an explicit ``null``
  to clear. Surfaced on every tool read (``default_count`` / ``pinned_count``
  / ``stale_input_fields`` / ``merged_input_preview``); neither kind is
  injected into a tool call in this scope (runtime enforcement is a follow-on).

Only the fields the caller actually set are written. Verifies
parent-connection org ownership before the tool update so a correctly-org'd
tool id under a foreign-org connection still 404s.



## OpenAPI

````yaml /api-reference/openapi.json patch /v1/integrations/connections/{connection_id}/tools/{tool_id}
openapi: 3.1.0
info:
  title: Feather API
  description: >-
    Unified customer experience platform API. Manages identity, conversations,
    memory, agents, procedures, policies, model routing, knowledge bases,
    integrations, and runtime execution.
  version: 1.21.0
servers:
  - url: https://api-sandbox.featherhq.com
    description: Sandbox
  - url: http://localhost:8000
    description: Local dev
security: []
paths:
  /v1/integrations/connections/{connection_id}/tools/{tool_id}:
    patch:
      tags:
        - integrations
      summary: >-
        Edit author-editable metadata on a single tool (response_field_map,
        is_enabled, input_defaults — defaults + pinned)
      description: >-
        Update author-editable tool metadata.


        Three mutable fields:


        * ``response_field_map`` — the customer-owned field map
          (``{"field_mappings": [...]}``) selecting which response fields the agent
          receives. Narrows the agent-facing payload and drives the AOP compiler's
          ``kind=llm`` → ``kind=action`` promotion (ENG-631). Omit the field to
          no-op; pass an explicit ``null`` to clear. The response *shape*
          (``response_schema``) is sync-owned and read-only over this API (D2), so
          it is rejected by the request schema's ``extra="forbid"``.
        * ``is_enabled`` — turn the individual tool on/off (the PRD's per-tool
          toggle). A disabled tool is excluded from resolution, so the agent can no
          longer call it. Omit to no-op.
        * ``input_defaults`` — operator input-arg config for input fields
          (``{field_name: {"value": ..., "type": "default"|"pinned"}}``, ENG-590). A
          ``default`` is a suggestion the agent may overwrite; a ``pinned`` value the
          caller cannot overwrite. Validated against the tool's current
          ``input_schema``: an unknown field or wrong-type value is rejected with a
          422 listing each offending field. Omit to no-op; pass an explicit ``null``
          to clear. Surfaced on every tool read (``default_count`` / ``pinned_count``
          / ``stale_input_fields`` / ``merged_input_preview``); neither kind is
          injected into a tool call in this scope (runtime enforcement is a follow-on).

        Only the fields the caller actually set are written. Verifies

        parent-connection org ownership before the tool update so a
        correctly-org'd

        tool id under a foreign-org connection still 404s.
      operationId: updateConnectionTool
      parameters:
        - name: connection_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            title: Connection Id
        - name: tool_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            title: Tool Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConnectionToolPatchRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConnectionToolResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - APIKeyHeader: []
components:
  schemas:
    ConnectionToolPatchRequest:
      properties:
        response_field_map:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Response Field Map
        is_enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Is Enabled
        input_defaults:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/InputArgConfig'
              type: object
            - type: 'null'
          title: Input Defaults
      additionalProperties: false
      type: object
      title: ConnectionToolPatchRequest
      description: >-
        Author-editable fields on a single ``IntegrationConnectionTool``.


        Three mutable fields: ``response_field_map`` (the customer-owned field
        map

        ``{"field_mappings": [...]}`` that narrows the agent-facing response and

        drives the AOP compiler's ``kind=llm`` → ``kind=action`` promotion),

        ``is_enabled`` (turn the individual tool on/off for the agent), and

        ``input_defaults`` (operator input-arg config,

        ``{field_name: {"value": ..., "type": "default"|"pinned"}}`` — ENG-590;
        a

        ``default`` may be overwritten by the agent, a ``pinned`` value cannot).

        ``input_defaults`` is validated at the service layer against the row's
        current

        ``input_schema`` (it needs the row, which a Pydantic validator can't
        see), so a

        wrong-type value or unknown field is rejected there with a 422. The
        response

        *shape* (``response_schema``) is sync-owned and read-only over the API

        (ENG-631 D2), so it is deliberately NOT accepted here —
        ``extra="forbid"``

        rejects it with a 422.


        Pydantic's ``model_fields_set`` is used at the service layer to
        distinguish

        "omit this field" (no-op) from "explicit ``None``" (clear the field).
    ConnectionToolResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
        connection_id:
          type: string
          format: uuid
          title: Connection Id
        organization_id:
          type: string
          format: uuid
          title: Organization Id
        integration_key:
          $ref: '#/components/schemas/IntegrationKey'
        nickname_slug:
          type: string
          title: Nickname Slug
        tool_path:
          type: string
          title: Tool Path
        slug:
          type: string
          title: Slug
        display_name:
          type: string
          title: Display Name
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
        input_schema:
          additionalProperties: true
          type: object
          title: Input Schema
        response_schema:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Response Schema
        response_field_map:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Response Field Map
        input_defaults:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/InputArgConfig'
              type: object
            - type: 'null'
          title: Input Defaults
        is_enabled:
          type: boolean
          title: Is Enabled
        last_seen_at:
          type: string
          format: date-time
          title: Last Seen At
        created_at:
          type: string
          format: date-time
          title: Created At
        updated_at:
          type: string
          format: date-time
          title: Updated At
        stale_field_paths:
          items:
            type: string
          type: array
          title: Stale Field Paths
          description: Saved field-map paths no longer present in the shape (ENG-631 D4).
          readOnly: true
        default_count:
          type: integer
          title: Default Count
          description: >-
            How many input fields carry an operator *default* (ENG-590 / PRD
            7.7).
          readOnly: true
        pinned_count:
          type: integer
          title: Pinned Count
          description: How many input fields are operator-*pinned* (ENG-590).
          readOnly: true
        stale_input_fields:
          items:
            type: string
          type: array
          title: Stale Input Fields
          description: >-
            Configured input fields removed/renamed/retyped by a re-sync (PRD
            7.6).
          readOnly: true
        merged_input_preview:
          additionalProperties: true
          type: object
          title: Merged Input Preview
          description: '``input_schema`` with each operator value injected (PRD 7.8).'
          readOnly: true
      type: object
      required:
        - id
        - connection_id
        - organization_id
        - integration_key
        - nickname_slug
        - tool_path
        - slug
        - display_name
        - description
        - input_schema
        - is_enabled
        - last_seen_at
        - created_at
        - updated_at
        - stale_field_paths
        - default_count
        - pinned_count
        - stale_input_fields
        - merged_input_preview
      title: ConnectionToolResponse
    ErrorResponse:
      properties:
        error:
          type: string
          title: Error
        message:
          type: string
          title: Message
      type: object
      required:
        - error
        - message
      title: ErrorResponse
      description: Standard error response returned by all API error handlers.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    InputArgConfig:
      properties:
        value:
          title: Value
        type:
          $ref: '#/components/schemas/InputArgType'
          default: default
      additionalProperties: false
      type: object
      required:
        - value
      title: InputArgConfig
      description: >-
        One operator-configured input field: a ``value`` plus its enforcement
        ``type``.


        The wire/stored shape of each entry in the ``input_defaults`` map.
        ``type``

        defaults to ``default`` so a caller can omit it for the common case.
    IntegrationKey:
      type: string
      enum:
        - slack
        - custom_mcp
        - notion
        - google_drive
        - calcom
        - twilio
        - email
      title: IntegrationKey
      description: |-
        Stable identifier for each supported integration.

        The string value must match the vendor's per-provider identifier
        (for Nango: ``provider_config_key``). Persisted on
        ``integration_connections.integration_key`` and
        ``integration_connection_tools.integration_key``.

        Adding a new integration: append a member here, add an
        ``IntegrationSpec`` to ``INTEGRATIONS``, register the provider in the
        vendor cloud via ``src/integrations/bootstrap.py`` (Step 3).
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    InputArgType:
      type: string
      enum:
        - default
        - pinned
      title: InputArgType
      description: |-
        How an operator-configured input value is enforced.

        * ``DEFAULT`` — a suggestion the agent may overwrite.
        * ``PINNED`` — a forced value the caller must use and cannot overwrite.
  securitySchemes:
    APIKeyHeader:
      type: apiKey
      in: header
      name: x-api-key

````