{
  "openapi": "3.0.3",
  "info": {
    "title": "Willow API",
    "description": "The Willow API allows you to programmatically manage MCP servers and other resources in your organization.\n\n## Authentication\n\nAll API endpoints require authentication using a Bearer token. You can generate API tokens from the Admin Settings in your Willow dashboard.\n\nInclude your token in the `Authorization` header:\n```\nAuthorization: Bearer wxt_xxxxx\n```\n\nSee [API Tokens](/docs/admin/api-tokens) for more details on generating and managing tokens.\n\n## Versioning and deprecation\n\nThis is version `1` of the Admin API. Every endpoint accepts an optional\n`Willow-API-Version` header; omitting it means version `1`. New endpoints and\nfields are added without a version change. Breaking changes ship only under a\nnew version, and an operation is removed no sooner than 6 months after it is\ndeprecated. Deprecated operations are marked `deprecated: true` in this spec\nand return `Deprecation` and `Sunset` response headers.\n\nSee [API Versioning and Deprecation](/docs/developers/api-versioning) for the full policy.\n",
    "version": "1.0.0",
    "contact": {
      "name": "Willow Support",
      "url": "https://withwillow.ai"
    }
  },
  "servers": [
    {
      "url": "https://app.withwillow.ai",
      "description": "Your Willow instance"
    }
  ],
  "tags": [
    {
      "name": "MCP Servers",
      "description": "Create and manage MCP servers programmatically"
    },
    {
      "name": "Connectors",
      "description": "Browse the catalog of available connectors (built-in MCPs) and check whether a connector is already in use in your organization"
    },
    {
      "name": "Groups",
      "description": "Manage groups and their integrations"
    },
    {
      "name": "Users",
      "description": "Manage users in your organization"
    },
    {
      "name": "Toolkits",
      "description": "Create and manage toolkits"
    },
    {
      "name": "Skills",
      "description": "Create and manage skills"
    },
    {
      "name": "Guards",
      "description": "Create and manage guards (content evaluation rules with checks, thresholds, and actions)"
    },
    {
      "name": "Commands",
      "description": "Create and manage commands"
    },
    {
      "name": "Plugins",
      "description": "Create and manage plugins"
    },
    {
      "name": "Background Agents",
      "description": "Create, sync, and invoke background agents, and inspect their platform sessions"
    },
    {
      "name": "Auth Exchange",
      "description": "Exchange external JWT tokens for Willow Connect credentials"
    },
    {
      "name": "AI Discovery",
      "description": "Inspect AI tools discovered across your organization by the Willow Scan Agent — MCP servers, skills, agent memory, AI agents, and the devices reporting them"
    },
    {
      "name": "AI Discovery Policy",
      "description": "Read and manage the AI Discovery enforcement policy — the default actions and ordered rules that allow, warn, or block discovered MCP servers and skills"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/api/mcp-servers": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listMcpServers",
        "summary": "List MCP Servers",
        "description": "Returns a list of all MCP servers in your organization.\n\nThe response includes all configured MCP servers with their current status, configuration, and metadata.\n",
        "tags": [
          "MCP Servers"
        ],
        "parameters": [
          {
            "name": "x-willow-group",
            "in": "header",
            "required": false,
            "description": "Scope the returned list to the MCP servers accessible to a specific group, by group name (case-insensitive), instead of the full org-wide list. An unknown group resolves to an empty list rather than an error.\n",
            "schema": {
              "type": "string"
            },
            "example": "engineering"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter MCP servers by status.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "draft"
              ]
            },
            "example": "active"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Case-insensitive search against MCP server name and description.",
            "schema": {
              "type": "string"
            },
            "example": "slack"
          },
          {
            "name": "include_tools",
            "in": "query",
            "required": false,
            "description": "Include enabled tools for each server. Deprecated in favor of `fields=tools(...)`.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          },
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "description": "Comma-separated list of fields to include in the response. When omitted, all fields are returned.\nSupports nested field selection using parenthesized syntax — e.g. `tools(name,slug,description)`.\n",
            "schema": {
              "type": "string"
            },
            "example": "slug,name,status,tools(name,slug,description)"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of MCP servers to return (1-200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            },
            "example": 100
          },
          {
            "name": "includeTotal",
            "in": "query",
            "required": false,
            "description": "Include the total number of matching MCP servers in `totalCount`.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          }
        ],
        "responses": {
          "200": {
            "description": "List of MCP servers retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListMcpServersResponse"
                },
                "example": {
                  "data": [
                    {
                      "slug": "my-custom-server",
                      "name": "My Custom Server",
                      "description": "Custom MCP server for internal tools",
                      "status": "active",
                      "logo_url": "https://icons.withwillow.ai/connectors/slack.svg",
                      "auth_type": "proxy-oauth",
                      "tools_count": 12,
                      "is_local_mcp": false,
                      "connection": {
                        "url": "https://gateway.example.com/mcp?mcp=my-custom-server",
                        "transport": "both"
                      },
                      "tools": []
                    }
                  ],
                  "pagination": {
                    "cursor": 0,
                    "limit": 100,
                    "hasMore": false,
                    "nextCursor": null
                  },
                  "totalCount": 1
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to retrieve MCP servers"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createMcpServer",
        "summary": "Create MCP Server",
        "description": "Creates a new MCP server integration in your organization.\n\nThe server will be created with the specified configuration and will be immediately available for use by your organization's users.\n\nIf no `slug` is provided, one will be automatically generated from the `name`. If the slug already exists, a numeric suffix will be appended to ensure uniqueness.\n",
        "tags": [
          "MCP Servers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMcpServerRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic MCP Server",
                  "description": "Create a simple MCP server with minimal configuration",
                  "value": {
                    "name": "My Custom Server",
                    "mcp_proxy": "{\"type\":\"http\",\"url\":\"https://my-mcp-server.example.com\"}"
                  }
                },
                "withAuth": {
                  "summary": "Server with OAuth Authentication",
                  "description": "Create an MCP server that requires OAuth authentication",
                  "value": {
                    "name": "GitHub Integration",
                    "slug": "github-custom",
                    "mcp_proxy": "{\"type\":\"http\",\"url\":\"https://github-mcp.example.com\"}",
                    "description": "Custom GitHub MCP server integration",
                    "status": "active",
                    "auth_settings": {
                      "authType": "proxy-oauth",
                      "clientId": "your-client-id",
                      "authUrl": "https://github.com/login/oauth/authorize",
                      "tokenUrl": "https://github.com/login/oauth/access_token",
                      "client": {
                        "scope": "repo user"
                      }
                    }
                  }
                },
                "withApiKey": {
                  "summary": "Server with API Key Authentication",
                  "description": "Create an MCP server that requires an API key from users",
                  "value": {
                    "name": "Custom API Server",
                    "mcp_proxy": "{\"type\":\"http\",\"url\":\"https://api-server.example.com\"}",
                    "auth_settings": {
                      "authType": "proxy-api-key",
                      "howtoMarkdown": "Go to [Settings](https://example.com/settings) to generate your API key."
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "MCP server created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateMcpServerResponse"
                },
                "example": {
                  "data": {
                    "slug": "my-custom-server"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing required field",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "invalidJson": {
                    "summary": "Invalid MCP proxy JSON",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "mcp_proxy: mcp_proxy must be valid JSON"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug format",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens, no leading/trailing hyphens"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create MCP server"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateMcpServer",
        "summary": "Update MCP Server",
        "description": "Updates an existing MCP server by slug.\n\nOnly the fields provided in the request body will be updated. Omitted fields retain their current values.\n",
        "tags": [
          "MCP Servers"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the MCP server to update",
            "schema": {
              "type": "string"
            },
            "example": "my-custom-server"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMcpServerRequest"
              },
              "examples": {
                "updateName": {
                  "summary": "Update Name",
                  "value": {
                    "name": "Updated Server Name"
                  }
                },
                "updateStatus": {
                  "summary": "Update Status",
                  "value": {
                    "status": "draft"
                  }
                },
                "updateAuth": {
                  "summary": "Update Auth Settings",
                  "value": {
                    "auth_settings": {
                      "authType": "proxy-api-key",
                      "howtoMarkdown": "Visit [Settings](https://example.com/settings) to get your key."
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "MCP server updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateMcpServerResponse"
                },
                "example": {
                  "data": {
                    "slug": "my-custom-server"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug: slug must be lowercase alphanumeric with hyphens"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "MCP server not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "MCP server not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update MCP server"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteMcpServer",
        "summary": "Delete MCP Server",
        "description": "Deletes an MCP server by slug.\n\nThis operation is permanent and cannot be undone. All associated configurations will be removed.\n",
        "tags": [
          "MCP Servers"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the MCP server to delete",
            "schema": {
              "type": "string"
            },
            "example": "my-custom-server"
          }
        ],
        "responses": {
          "200": {
            "description": "MCP server deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "MCP server deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "MCP server not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "MCP server not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete MCP server"
                }
              }
            }
          }
        }
      }
    },
    "/api/connectors": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listConnectors",
        "summary": "List Connectors",
        "description": "Returns the catalog of connectors (available MCPs) that can be used to create MCP servers in your organization.\n\nThe catalog merges two sources, distinguished by the `source` field on each entry:\n- `connector` — built-in, first-party connectors (such as Slack, GitHub, or Gmail) with their supported authentication methods and the tools they expose.\n- `registry` — entries from the public MCP registry directory (community/third-party servers) that are not part of the connector database.\n\nUse the `source` query parameter to return only one of the two catalogs. Results are paginated. Use the `id` of an entry to check whether it is already in use in your organization via [Check Connector Usage](#tag/Connectors/operation/getConnectorUsage).\n",
        "tags": [
          "Connectors"
        ],
        "parameters": [
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Return only built-in connectors or only registry entries. When omitted, both are returned.",
            "schema": {
              "type": "string",
              "enum": [
                "connector",
                "registry"
              ]
            },
            "example": "connector"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter connectors by availability status. Registry entries are always `active`.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "beta",
                "soon"
              ]
            },
            "example": "active"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Case-insensitive search against connector id, name, and description.",
            "schema": {
              "type": "string"
            },
            "example": "slack"
          },
          {
            "name": "include_tools",
            "in": "query",
            "required": false,
            "description": "Include a summary of the tools each built-in connector exposes.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of entries to return (1-200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            },
            "example": 100
          }
        ],
        "responses": {
          "200": {
            "description": "List of connectors retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListConnectorsResponse"
                },
                "example": {
                  "data": [
                    {
                      "id": "slack",
                      "source": "connector",
                      "name": "Slack",
                      "description": "Send messages and manage channels in Slack",
                      "logo_url": "https://icons.withwillow.ai/connectors/slack.svg",
                      "website": "https://slack.com",
                      "category": "Communication",
                      "status": "active",
                      "auth_types": [
                        "proxy-oauth"
                      ],
                      "tools_count": 4
                    },
                    {
                      "id": "context7",
                      "source": "registry",
                      "name": "Context7",
                      "description": "Up-to-date code docs for any prompt",
                      "logo_url": "https://context7.com/favicon.ico",
                      "website": null,
                      "category": null,
                      "status": "active",
                      "auth_types": [
                        "none"
                      ],
                      "tools_count": 0,
                      "transport": "http",
                      "url": "https://mcp.context7.com/mcp",
                      "repo": "https://github.com/upstash/context7",
                      "official": true
                    }
                  ],
                  "pagination": {
                    "cursor": 0,
                    "limit": 100,
                    "hasMore": true,
                    "nextCursor": 100
                  },
                  "totalCount": 1804
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list connectors"
                }
              }
            }
          }
        }
      }
    },
    "/api/connectors/{connector_id}/usage": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "getConnectorUsage",
        "summary": "Check Connector Usage",
        "description": "Reports whether a catalog entry is already in use in your organization.\n\nAn entry is considered \"in use\" when at least one MCP server in your organization was created from it:\n- Built-in connectors are matched by their `connector_id`.\n- Registry MCPs are matched by comparing the registry entry's remote endpoint against the URL each installed MCP server points at.\n\nWhen the id exists in both catalogs (or you don't know which it is), omit `source` and both strategies run. The response includes the matching MCP servers so you can see exactly where the entry is configured.\n",
        "tags": [
          "Connectors"
        ],
        "parameters": [
          {
            "name": "connector_id",
            "in": "path",
            "required": true,
            "description": "The catalog entry id (for example `slack`), as returned by [List Connectors](#tag/Connectors/operation/listConnectors).",
            "schema": {
              "type": "string"
            },
            "example": "slack"
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Restrict matching to a built-in connector or a registry entry. When omitted, both are checked.",
            "schema": {
              "type": "string",
              "enum": [
                "connector",
                "registry"
              ]
            },
            "example": "connector"
          }
        ],
        "responses": {
          "200": {
            "description": "Connector usage retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorUsageResponse"
                },
                "example": {
                  "data": {
                    "connector_id": "slack",
                    "source": "connector",
                    "in_use": true,
                    "count": 2,
                    "mcp_servers": [
                      {
                        "id": "6f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
                        "slug": "slack",
                        "name": "Slack",
                        "status": "active",
                        "needs_setup": false
                      },
                      {
                        "id": "7a2d3e4f-5b6c-7d8e-9f0a-1b2c3d4e5f60",
                        "slug": "slack-eng",
                        "name": "Slack (Engineering)",
                        "status": "draft",
                        "needs_setup": true
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Connector id is missing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "error": "Connector id is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to check connector usage"
                }
              }
            }
          }
        }
      }
    },
    "/api/groups": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listGroups",
        "summary": "List Groups",
        "description": "Returns a paginated list of groups in your organization.\n\nGroups control which integrations, toolkits, and skills are available to users.\n",
        "tags": [
          "Groups"
        ],
        "parameters": [
          {
            "name": "skip",
            "in": "query",
            "required": false,
            "description": "Number of records to skip for pagination",
            "schema": {
              "type": "number",
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of records to return",
            "schema": {
              "type": "number",
              "default": 100
            },
            "example": 100
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Search term to filter groups by name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of groups retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Group"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/AdminPagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to retrieve groups"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createGroup",
        "summary": "Create Group",
        "description": "Creates a new group in your organization.\n\nGroups are used to organize users and control their access to integrations, toolkits, and skills.\n",
        "tags": [
          "Groups"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic Group",
                  "value": {
                    "name": "Engineering Team"
                  }
                },
                "withSettings": {
                  "summary": "Group with Settings",
                  "value": {
                    "name": "Engineering Team",
                    "settings": {
                      "auto_assign_users": true,
                      "auto_assign_mcps": true,
                      "show_draft_mcps": false
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Group created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Group"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "name: name is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create group"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateGroup",
        "summary": "Update Group",
        "description": "Updates an existing group by name.\n\nOnly the fields provided in the request body will be updated.\n",
        "tags": [
          "Groups"
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "The name of the group to update",
            "schema": {
              "type": "string"
            },
            "example": "Engineering Team"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              },
              "examples": {
                "updateName": {
                  "summary": "Update Name",
                  "value": {
                    "name": "Updated Team Name"
                  }
                },
                "updateSettings": {
                  "summary": "Update Settings",
                  "value": {
                    "settings": {
                      "auto_assign_users": false,
                      "show_draft_mcps": true
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Group updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Group"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "name query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Group not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Group not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update group"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteGroup",
        "summary": "Delete Group",
        "description": "Deletes a group by name.\n\nThis operation is permanent and cannot be undone. Users in this group will lose any access granted through this group.\n",
        "tags": [
          "Groups"
        ],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "The name of the group to delete",
            "schema": {
              "type": "string"
            },
            "example": "Engineering Team"
          }
        ],
        "responses": {
          "200": {
            "description": "Group deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Group deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing name query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "name query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Group not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Group not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete group"
                }
              }
            }
          }
        }
      }
    },
    "/api/groups/{name}/integrations": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "addIntegrationsToGroup",
        "summary": "Add Integrations to Group",
        "description": "Adds one or more integrations to a group by their slugs.\n\nThe integrations will be associated with the specified group, allowing users in that group to access them.\n\nIf an integration is already in the group, it will be silently ignored (no error will be returned).\n",
        "tags": [
          "Groups"
        ],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "description": "The name of the group to add integrations to",
            "schema": {
              "type": "string",
              "minLength": 1
            },
            "example": "Engineering Team"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddIntegrationsRequest"
              },
              "examples": {
                "singleIntegration": {
                  "summary": "Add single integration",
                  "description": "Add one integration to a group",
                  "value": {
                    "slugs": [
                      "github"
                    ]
                  }
                },
                "multipleIntegrations": {
                  "summary": "Add multiple integrations",
                  "description": "Add several integrations to a group at once",
                  "value": {
                    "slugs": [
                      "github",
                      "slack",
                      "jira"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Integrations added successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddIntegrationsResponse"
                },
                "example": {
                  "data": {
                    "success": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "emptySlugs": {
                    "summary": "Empty slugs array",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slugs array cannot be empty"
                    }
                  },
                  "integrationsNotFound": {
                    "summary": "Integrations not found",
                    "value": {
                      "error": "Integrations not found: invalid-slug, another-invalid"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Group not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Group not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to add integrations to group"
                }
              }
            }
          }
        }
      }
    },
    "/api/users": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listUsers",
        "summary": "List Users",
        "description": "Returns a paginated list of users in your organization.\n\nThe response includes all users with their email addresses, names, machine user status, associated groups, and timestamps.\n",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "skip",
            "in": "query",
            "required": false,
            "description": "Number of records to skip for pagination",
            "schema": {
              "type": "number",
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of records to return",
            "schema": {
              "type": "number",
              "default": 100
            },
            "example": 100
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Search term to filter users by name or email",
            "schema": {
              "type": "string"
            },
            "example": "john"
          }
        ],
        "responses": {
          "200": {
            "description": "List of users retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/AdminPagination"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "name": "John Doe",
                      "email": "john.doe@example.com",
                      "is_machine_user": false,
                      "group_ids": [
                        "group_123",
                        "group_456"
                      ],
                      "created_at": "2024-01-15T10:30:00Z",
                      "updated_at": "2024-01-20T14:45:00Z"
                    },
                    {
                      "name": "Jane Smith",
                      "email": "jane.smith@example.com",
                      "is_machine_user": false,
                      "group_ids": [
                        "group_123"
                      ],
                      "created_at": "2024-01-16T09:15:00Z",
                      "updated_at": "2024-01-18T11:20:00Z"
                    }
                  ],
                  "pagination": {
                    "skip": 0,
                    "limit": 100,
                    "hasMore": false
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to retrieve users"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createUser",
        "summary": "Create User",
        "description": "Creates a new user in your organization.\n\nThe user will be created with the specified name and email address.\n\nTo create a **machine user** instead, set `is_machine_user: true` in the request body. Machine users do not require an email — one is generated automatically. You can optionally provide a `slug` and `client_credentials` for OAuth2 authentication.\n\nCreating a machine user returns its gateway credentials under\n`credentials`, documented in `MachineUserCredentials`. The `secret` is\nshown once and cannot be retrieved afterwards, so store it when you\nreceive it.\n",
        "tags": [
          "Users"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CreateUserRequest"
                  },
                  {
                    "$ref": "#/components/schemas/CreateMachineUserViaUsersRequest"
                  }
                ]
              },
              "examples": {
                "regularUser": {
                  "summary": "Create a regular user",
                  "value": {
                    "name": "John Doe",
                    "email": "john.doe@example.com"
                  }
                },
                "machineUser": {
                  "summary": "Create a machine user",
                  "value": {
                    "is_machine_user": true,
                    "name": "CI Bot"
                  }
                },
                "machineUserWithOwners": {
                  "summary": "Create a machine user with owners",
                  "value": {
                    "is_machine_user": true,
                    "name": "CI Bot",
                    "owner_ids": [
                      "user_123",
                      "user_456"
                    ]
                  }
                },
                "machineUserWithOptions": {
                  "summary": "Create a machine user with slug and credentials",
                  "value": {
                    "is_machine_user": true,
                    "name": "CI Bot",
                    "slug": "ci-bot",
                    "client_credentials": {
                      "clientId": "my-client-id",
                      "clientSecret": "my-client-secret",
                      "tokenUrl": "https://auth.example.com/oauth/token"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User created successfully.\n\nFor **machine users**, the response also includes a `credentials`\nobject with the `client_id` and a one-time `secret`. The secret is\nreturned only once at creation time and cannot be retrieved again —\nstore it securely.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    },
                    "credentials": {
                      "$ref": "#/components/schemas/MachineUserCredentials"
                    }
                  }
                },
                "examples": {
                  "regularUser": {
                    "summary": "Regular user created",
                    "value": {
                      "data": {
                        "name": "John Doe",
                        "email": "john.doe@example.com",
                        "slug": "john-doe",
                        "is_machine_user": false,
                        "group_ids": [],
                        "created_at": "2024-01-15T10:30:00Z",
                        "updated_at": "2024-01-15T10:30:00Z"
                      }
                    }
                  },
                  "machineUser": {
                    "summary": "Machine user created (includes one-time credentials)",
                    "value": {
                      "data": {
                        "name": "CI Bot",
                        "email": "ci-bot@machine.local",
                        "slug": "ci-bot",
                        "is_machine_user": true,
                        "group_ids": [],
                        "created_at": "2024-01-15T10:30:00Z",
                        "updated_at": "2024-01-15T10:30:00Z"
                      },
                      "credentials": {
                        "client_id": "usr_ak_xxxxxxxxxxxxxxxx",
                        "secret": "usr_sk_xxxxxxxxxxxxxxxx"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingEmail": {
                    "summary": "Missing email (regular user)",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "email: email is required"
                    }
                  },
                  "invalidEmail": {
                    "summary": "Invalid email",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "email: must be a valid email address"
                    }
                  },
                  "duplicate": {
                    "summary": "Duplicate email",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "email: user with this email already exists"
                    }
                  },
                  "missingName": {
                    "summary": "Missing name (machine user)",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "ownersOnRegularUser": {
                    "summary": "owner_ids sent for a regular user",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "owner_ids: owner_ids can only be set on machine users"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create user"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateUser",
        "summary": "Update User",
        "description": "Updates an existing user by email.\n\nOnly the fields provided in the request body will be updated.\n\n`owner_ids` applies to **machine users** only and replaces the whole owner set, so send every owner you want to keep. Use it to assign owners to a machine user that was created without any.\n",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": true,
            "description": "The email address of the user to update",
            "schema": {
              "type": "string",
              "format": "email"
            },
            "example": "john.doe@example.com"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserRequest"
              },
              "examples": {
                "name": {
                  "summary": "Rename a user",
                  "value": {
                    "name": "John Updated"
                  }
                },
                "riskScore": {
                  "summary": "Set a risk score",
                  "value": {
                    "risk_score": 72
                  }
                },
                "clearRiskScore": {
                  "summary": "Clear a risk score back to unscored",
                  "value": {
                    "risk_score": null
                  }
                },
                "owners": {
                  "summary": "Replace the owners of a machine user",
                  "value": {
                    "owner_ids": [
                      "user_123",
                      "user_456"
                    ]
                  }
                },
                "clearOwners": {
                  "summary": "Remove every owner from a machine user",
                  "value": {
                    "owner_ids": []
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "email query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "User not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "User not found: john.doe@example.com"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update user"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteUser",
        "summary": "Delete User",
        "description": "Deletes a user by email.\n\nThis operation is permanent and cannot be undone. The user will be removed from all groups.\n",
        "tags": [
          "Users"
        ],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": true,
            "description": "The email address of the user to delete",
            "schema": {
              "type": "string",
              "format": "email"
            },
            "example": "john.doe@example.com"
          }
        ],
        "responses": {
          "200": {
            "description": "User deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "User deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing email query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "email query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "User not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "User not found: john.doe@example.com"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete user"
                }
              }
            }
          }
        }
      }
    },
    "/api/users/risk-scores": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "bulkUpdateRiskScores",
        "summary": "Bulk Update Risk Scores",
        "description": "Sets identity risk scores for many users at once, matching them to\nexisting users by email. Use this to push scores from an external\nidentity risk provider on a schedule instead of issuing one update per\nuser.\n\nScores are on a 0-100 scale where a higher number means a riskier user.\nProviders that use a different scale must convert before calling: for\nexample CrowdStrike Falcon Identity Protection reports 0-1, so multiply\nits `riskScore` by 100.\n\nEmails that match no user are counted in `skipped` rather than failing\nthe request, so a provider export can be pushed wholesale without first\nreconciling it against the org's user list. Scores an admin set by hand\nare also skipped unless `overwrite_manual` is `true`.\n\nScores can be pushed at any time, but they only take effect — shown in\nthe dashboard, used by guard filters, and enforced by the blocking\npolicy — once the **User Risk Score** beta feature is enabled.\n",
        "tags": [
          "Users"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkRiskScoresRequest"
              },
              "example": {
                "source": "crowdstrike",
                "scores": [
                  {
                    "email": "john.doe@example.com",
                    "risk_score": 72
                  },
                  {
                    "email": "jane.smith@example.com",
                    "risk_score": 15
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scores applied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkRiskScoresResponse"
                },
                "example": {
                  "data": {
                    "updated": 2,
                    "skipped": 0
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "outOfRange": {
                    "summary": "Score outside the 0-100 scale",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "scores.0.risk_score: risk_score must be <= 100"
                    }
                  },
                  "reservedSource": {
                    "summary": "Reserved source value",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "source: source cannot be 'manual'"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update risk scores"
                }
              }
            }
          }
        }
      }
    },
    "/api/toolkits": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listToolkits",
        "summary": "List Toolkits",
        "description": "Returns a list of all toolkits in the organization.\n\nThe response includes all configured toolkits with their current status, configuration, and metadata.\n",
        "tags": [
          "Toolkits"
        ],
        "responses": {
          "200": {
            "description": "List of toolkits retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Toolkit"
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "id": "tk_abc123",
                      "slug": "my-custom-toolkit",
                      "name": "My Custom Toolkit",
                      "description": "Custom toolkit for internal workflows",
                      "status": "active",
                      "integration_tools": {
                        "tool1": "config1"
                      },
                      "prompts": [
                        {
                          "name": "Example Prompt",
                          "template": "You are a helpful assistant."
                        }
                      ],
                      "resources": [
                        {
                          "name": "Example Resource",
                          "type": "file"
                        }
                      ],
                      "created_at": "2024-01-15T10:30:00Z",
                      "updated_at": "2024-01-20T14:45:00Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to retrieve toolkits"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createToolkit",
        "summary": "Create Toolkit",
        "description": "Creates a new toolkit in your organization.\n\nThe toolkit will be created with the specified configuration and will be immediately available for assignment to groups.\n",
        "tags": [
          "Toolkits"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateToolkitRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic Toolkit",
                  "value": {
                    "name": "My Toolkit",
                    "slug": "my-toolkit"
                  }
                },
                "full": {
                  "summary": "Full Toolkit",
                  "value": {
                    "name": "Dev Toolkit",
                    "slug": "dev-toolkit",
                    "description": "Development workflow toolkit",
                    "integration_tools": {
                      "github": "all",
                      "slack": [
                        "post-message"
                      ]
                    },
                    "prompts": [
                      {
                        "name": "Code Review",
                        "slug": "code-review",
                        "description": "Review code",
                        "outputContent": "Review the following code:\n\n{{code}}"
                      }
                    ],
                    "resources": [
                      {
                        "name": "Standards",
                        "slug": "standards",
                        "description": "Coding standards",
                        "outputContent": "Use TypeScript strict mode."
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Toolkit created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Toolkit"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing name",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "missingSlug": {
                    "summary": "Missing slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug is required"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create toolkit"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateToolkit",
        "summary": "Update Toolkit",
        "description": "Updates an existing toolkit by slug.\n\nOnly the fields provided in the request body will be updated.\n",
        "tags": [
          "Toolkits"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the toolkit to update",
            "schema": {
              "type": "string"
            },
            "example": "my-toolkit"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateToolkitRequest"
              },
              "examples": {
                "updateName": {
                  "summary": "Update Name",
                  "value": {
                    "name": "Updated Toolkit"
                  }
                },
                "updateStatus": {
                  "summary": "Update Status",
                  "value": {
                    "status": "draft"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Toolkit updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Toolkit"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Toolkit not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Toolkit not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update toolkit"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteToolkit",
        "summary": "Delete Toolkit",
        "description": "Deletes a toolkit by slug.\n\nThis operation is permanent and cannot be undone.\n",
        "tags": [
          "Toolkits"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the toolkit to delete",
            "schema": {
              "type": "string"
            },
            "example": "my-toolkit"
          }
        ],
        "responses": {
          "200": {
            "description": "Toolkit deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Toolkit deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Toolkit not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Toolkit not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete toolkit"
                }
              }
            }
          }
        }
      }
    },
    "/api/toolkits/{slug}/promote": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "promoteToolkit",
        "summary": "Promote Toolkit",
        "description": "Promotes a user-owned toolkit to an organization-level toolkit, making\nit available for assignment to groups.\n\n**This moves the toolkit; it does not copy it.** The user-level toolkit\nis removed from its owner's list and exists afterwards only at the\norganization level, under its new slug. The owner does not call this\nendpoint and is not consulted: an administrator promoting a toolkit\ntakes it out of that user's account. Tell the owner before you do.\n\nThere is no un-promote operation. Restoring a toolkit to its owner\nmeans recreating it through the User API.\n",
        "tags": [
          "Toolkits"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The slug of the user toolkit to promote. This is the namespaced\nslug the User API returned at creation (`owner@example.com:my-toolkit`),\nnot the bare slug that was requested.\n",
            "schema": {
              "type": "string"
            },
            "example": "user@example.com:my-toolkit"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PromoteToolkitRequest"
              },
              "examples": {
                "withOverrides": {
                  "summary": "Promote with overrides",
                  "value": {
                    "name": "Organization Toolkit",
                    "slug": "org-toolkit",
                    "description": "Promoted to organization level"
                  }
                },
                "minimal": {
                  "summary": "Promote without changes",
                  "value": {}
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Toolkit promoted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Toolkit"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "invalidSlug": {
                    "summary": "Invalid slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  },
                  "slugConflict": {
                    "summary": "Slug already exists",
                    "value": {
                      "code": "CONFLICT",
                      "message": "A toolkit with slug 'org-toolkit' already exists"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "User toolkit not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Toolkit not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to promote toolkit"
                }
              }
            }
          }
        }
      }
    },
    "/api/skills": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listSkills",
        "summary": "List Skills",
        "description": "Returns a list of all skills in your organization.\n",
        "tags": [
          "Skills"
        ],
        "responses": {
          "200": {
            "description": "List of skills retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Skill"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to retrieve skills"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createSkill",
        "summary": "Create Skill",
        "description": "Creates a new skill in your organization.\n",
        "tags": [
          "Skills"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSkillRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic Skill",
                  "value": {
                    "name": "My Skill",
                    "slug": "my-skill",
                    "description": "A custom skill",
                    "content": "# My Skill\n\nThis skill helps with..."
                  }
                },
                "withScripts": {
                  "summary": "Skill with Scripts",
                  "value": {
                    "name": "Build Automation",
                    "slug": "build-automation",
                    "description": "Automates build processes",
                    "content": "# Build Automation\n\nAutomates build and deploy.",
                    "status": "active",
                    "scripts": [
                      {
                        "path": "scripts/build.sh",
                        "language": "bash",
                        "content": "#!/bin/bash\nnpm run build",
                        "description": "Build script"
                      }
                    ],
                    "references": [
                      {
                        "path": "docs/build-guide.md",
                        "content": "# Build Guide\n\nFollow these steps...",
                        "description": "Build documentation"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Skill created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Skill"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing name",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create skill"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateSkill",
        "summary": "Update Skill",
        "description": "Updates an existing skill by slug.\n\nOnly the fields provided in the request body will be updated.\n",
        "tags": [
          "Skills"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the skill to update",
            "schema": {
              "type": "string"
            },
            "example": "my-skill"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSkillRequest"
              },
              "examples": {
                "updateContent": {
                  "summary": "Update Content",
                  "value": {
                    "content": "# Updated Skill\n\nNew content here."
                  }
                },
                "updateStatus": {
                  "summary": "Update Status",
                  "value": {
                    "status": "active"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Skill updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Skill"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Skill not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Skill not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update skill"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteSkill",
        "summary": "Delete Skill",
        "description": "Deletes a skill by slug.\n\nThis operation is permanent and cannot be undone.\n",
        "tags": [
          "Skills"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the skill to delete",
            "schema": {
              "type": "string"
            },
            "example": "my-skill"
          }
        ],
        "responses": {
          "200": {
            "description": "Skill deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Skill deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Skill not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Skill not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete skill"
                }
              }
            }
          }
        }
      }
    },
    "/api/skills/download": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "downloadSkill",
        "summary": "Download Skill",
        "description": "Downloads a skill as a zip file containing the complete skill package (SKILL.md, scripts, references, and assets).\n\nThe response is a binary zip file. Use the `format` query parameter to control the file extension of the download.\n",
        "tags": [
          "Skills"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "The unique identifier of the skill to download",
            "schema": {
              "type": "string"
            },
            "example": "skill_abc123"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Download format. Use `skill` to get a `.skill` extension, otherwise defaults to `.zip`.\n",
            "schema": {
              "type": "string",
              "enum": [
                "zip",
                "skill"
              ],
              "default": "zip"
            },
            "example": "zip"
          }
        ],
        "responses": {
          "200": {
            "description": "Skill zip file downloaded successfully",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Missing required query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "error": "Skill ID is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Skill not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Skill not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to download skill"
                }
              }
            }
          }
        }
      }
    },
    "/api/guards": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listGuards",
        "summary": "List Guards",
        "description": "Returns a list of all guards in your organization, including both custom and default guards.\n\nGuards evaluate content against a set of checks (regex, LLM, etc.) and trigger actions (block, warn, require approval, redact) when the combined score exceeds the threshold.\n\nRequires a token with the `admin:read` scope.\n",
        "tags": [
          "Guards"
        ],
        "responses": {
          "200": {
            "description": "List of guards retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Guard"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list guards"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createGuard",
        "summary": "Create Guard",
        "description": "Creates a new guard in your organization.\n\nGuards evaluate content against a set of checks (regex, LLM, built-in, JSONata) and trigger actions when the combined certainty score exceeds the threshold.\n\nRequires a token with the `admin:write` scope.\n",
        "tags": [
          "Guards"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGuardRequest"
              },
              "examples": {
                "regexGuard": {
                  "summary": "Regex-based guard",
                  "value": {
                    "name": "Email Detection",
                    "slug": "email-detection",
                    "description": "Detects email addresses in content",
                    "checks": [
                      {
                        "id": "regex-email",
                        "name": "Email Address",
                        "type": "regex",
                        "certainty": 10,
                        "config": {
                          "pattern": "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b"
                        }
                      }
                    ],
                    "threshold": 5,
                    "action": "warn",
                    "message": "This request contains an email address.",
                    "scope": "runtime"
                  }
                },
                "simpleGuard": {
                  "summary": "Simple guard (defaults)",
                  "value": {
                    "name": "My Guard",
                    "slug": "my-guard"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Guard created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Guard"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing name",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug format",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create guard"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateGuard",
        "summary": "Update Guard",
        "description": "Updates an existing guard by ID.\n\nOnly the fields provided in the request body will be updated.\n\nRequires a token with the `admin:write` scope.\n",
        "tags": [
          "Guards"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "The ID of the guard to update",
            "schema": {
              "type": "string"
            },
            "example": "guard_abc123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGuardRequest"
              },
              "examples": {
                "updateStatus": {
                  "summary": "Publish a guard",
                  "value": {
                    "status": "active"
                  }
                },
                "updateThreshold": {
                  "summary": "Change threshold and action",
                  "value": {
                    "threshold": 8,
                    "action": "block"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Guard updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Guard"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "id query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Guard not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Guard not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update guard"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteGuard",
        "summary": "Delete Guard",
        "description": "Deletes a guard by ID.\n\nThis operation is permanent and cannot be undone.\n\nRequires a token with the `admin:write` scope.\n",
        "tags": [
          "Guards"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "The ID of the guard to delete",
            "schema": {
              "type": "string"
            },
            "example": "guard_abc123"
          }
        ],
        "responses": {
          "200": {
            "description": "Guard deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Guard deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing id query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "id query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Guard not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Guard not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete guard"
                }
              }
            }
          }
        }
      }
    },
    "/api/commands": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listCommands",
        "summary": "List Commands",
        "description": "Returns a list of all commands in your organization.\n",
        "tags": [
          "Commands"
        ],
        "responses": {
          "200": {
            "description": "List of commands retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Command"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to retrieve commands"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createCommand",
        "summary": "Create Command",
        "description": "Creates a new command in your organization.\n\nCommands are reusable prompt templates that users can invoke by name.\n",
        "tags": [
          "Commands"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCommandRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic Command",
                  "value": {
                    "name": "Summarize",
                    "slug": "summarize",
                    "output_content": "Summarize the following text:\n\n{{text}}"
                  }
                },
                "withArguments": {
                  "summary": "Command with Arguments",
                  "value": {
                    "name": "Translate",
                    "slug": "translate",
                    "description": "Translate text to another language",
                    "output_content": "Translate the following text to {{language}}:\n\n{{text}}",
                    "arguments": [
                      {
                        "name": "text",
                        "type": "string",
                        "description": "The text to translate",
                        "required": true
                      },
                      {
                        "name": "language",
                        "type": "string",
                        "description": "Target language",
                        "required": true
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Command created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Command"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing name",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  },
                  "duplicateSlug": {
                    "summary": "Duplicate slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: a command with this slug already exists"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create command"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateCommand",
        "summary": "Update Command",
        "description": "Updates an existing command by slug.\n\nOnly the fields provided in the request body will be updated.\n",
        "tags": [
          "Commands"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the command to update",
            "schema": {
              "type": "string"
            },
            "example": "summarize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCommandRequest"
              },
              "examples": {
                "updateContent": {
                  "summary": "Update Content",
                  "value": {
                    "output_content": "Updated prompt template:\n\n{{text}}"
                  }
                },
                "updateStatus": {
                  "summary": "Update Status",
                  "value": {
                    "status": "draft"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Command updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Command"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Command not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Command not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update command"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteCommand",
        "summary": "Delete Command",
        "description": "Deletes a command by slug.\n\nThis operation is permanent and cannot be undone.\n",
        "tags": [
          "Commands"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the command to delete",
            "schema": {
              "type": "string"
            },
            "example": "summarize"
          }
        ],
        "responses": {
          "200": {
            "description": "Command deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Command deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Command not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Command not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete command"
                }
              }
            }
          }
        }
      }
    },
    "/api/plugins": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listPlugins",
        "summary": "List Plugins",
        "description": "Returns a list of all plugins in your organization.\n",
        "tags": [
          "Plugins"
        ],
        "responses": {
          "200": {
            "description": "List of plugins retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Plugin"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to retrieve plugins"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPlugin",
        "summary": "Create Plugin",
        "description": "Creates a new plugin in your organization.\n",
        "tags": [
          "Plugins"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePluginRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic Plugin",
                  "value": {
                    "name": "My Plugin",
                    "slug": "my-plugin",
                    "description": "A custom plugin"
                  }
                },
                "withSkills": {
                  "summary": "Plugin with Skills and Toolkits",
                  "value": {
                    "name": "Dev Plugin",
                    "slug": "dev-plugin",
                    "description": "Development workflow plugin",
                    "status": "active",
                    "skill_ids": [
                      "skill-id-1"
                    ],
                    "mcps": {
                      "toolkit_ids": [
                        "toolkit-id-1"
                      ],
                      "integration_ids": [
                        "integration-id-1"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Plugin created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Plugin"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing name",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create plugin"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updatePlugin",
        "summary": "Update Plugin",
        "description": "Updates an existing plugin by slug.\n\nOnly the fields provided in the request body will be updated.\n",
        "tags": [
          "Plugins"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the plugin to update",
            "schema": {
              "type": "string"
            },
            "example": "my-plugin"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePluginRequest"
              },
              "examples": {
                "updateStatus": {
                  "summary": "Update Status",
                  "value": {
                    "status": "active"
                  }
                },
                "updateDescription": {
                  "summary": "Update Description",
                  "value": {
                    "description": "Updated plugin description"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plugin updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Plugin"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter or invalid body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Plugin not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Plugin not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update plugin"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deletePlugin",
        "summary": "Delete Plugin",
        "description": "Deletes a plugin by slug.\n\nThis operation is permanent and cannot be undone.\n",
        "tags": [
          "Plugins"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "The slug of the plugin to delete",
            "schema": {
              "type": "string"
            },
            "example": "my-plugin"
          }
        ],
        "responses": {
          "200": {
            "description": "Plugin deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Plugin deleted successfully"
                }
              }
            }
          },
          "400": {
            "description": "Missing slug query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "slug query parameter is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Plugin not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Plugin not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete plugin"
                }
              }
            }
          }
        }
      }
    },
    "/api/plugins/sync": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "syncPluginsFromGithub",
        "summary": "Sync Plugins from GitHub",
        "description": "Re-imports plugins from your organization's configured GitHub source\nrepositories and republishes them to your marketplace targets. This is\nthe on-demand equivalent of the **Sync all now** button and the daily\nauto-sync — it ignores the per-repo auto-sync toggle and the\nonce-per-day guard, re-importing using the credentials captured when\neach source repo was added.\n\nSource repos are configured under **Plugins → Plugins Settings → Sync\nfrom GitHub**. If none are configured, the sync is a no-op that returns\nan empty `outcomes` list.\n\nBy default the request runs synchronously and returns per-repo results.\nFor organizations with many repos, set `background: true` to return\nimmediately (`202`) and continue the sync server-side.\n\nRequires a token with the `admin:write` scope.\n",
        "tags": [
          "Plugins"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SyncPluginsRequest"
              },
              "examples": {
                "all": {
                  "summary": "Sync every configured repo (wait for results)",
                  "value": {}
                },
                "singleRepo": {
                  "summary": "Sync a single repo",
                  "value": {
                    "repo": "my-org/my-plugins"
                  }
                },
                "background": {
                  "summary": "Fire-and-forget",
                  "value": {
                    "background": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sync completed. Returns per-repo outcomes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PluginSyncResult"
                    }
                  }
                },
                "example": {
                  "data": {
                    "syncedAny": true,
                    "outcomes": [
                      {
                        "repo": "my-org/my-plugins",
                        "status": "success",
                        "imported": 4,
                        "skipped": 0,
                        "failed": 0
                      }
                    ]
                  }
                }
              }
            }
          },
          "202": {
            "description": "Accepted. Returned when `background: true` — the sync continues\nserver-side and results are not included in the response.\n",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "started": {
                      "type": "boolean",
                      "example": true
                    }
                  }
                },
                "example": {
                  "started": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "repo: String must contain at least 1 character(s)"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Token is missing the required `admin:write` scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnauthorizedError"
                },
                "example": {
                  "error": "Token does not have the required permissions"
                }
              }
            }
          },
          "404": {
            "description": "A `repo` was supplied but no configured source repo matches it.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "No configured source repo matching \"my-org/my-plugins\""
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to sync plugins from GitHub"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listBackgroundAgents",
        "summary": "List Background Agents",
        "description": "Returns a list of all background agents in your organization.\n\nBackground agents are synthetic identities that run on external agent platforms (Claude Managed Agents, AWS AgentCore, or your own runtime) and call tools through the Willow gateway.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Case-insensitive search against agent name and slug.",
            "schema": {
              "type": "string"
            },
            "example": "support"
          },
          {
            "name": "owner_id",
            "in": "query",
            "required": false,
            "description": "Only return agents owned by this user ID.",
            "schema": {
              "type": "string"
            },
            "example": "user_abc123"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination. Pages contain up to 100 agents.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "includeTotal",
            "in": "query",
            "required": false,
            "description": "Include the total number of matching agents in `totalCount`.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          }
        ],
        "responses": {
          "200": {
            "description": "List of background agents retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BackgroundAgent"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "hasMore": {
                          "type": "boolean"
                        }
                      }
                    },
                    "totalCount": {
                      "type": "integer",
                      "description": "Total number of matching agents. Only present when `includeTotal=true`."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list background agents"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createBackgroundAgent",
        "summary": "Create Background Agent",
        "description": "Creates a new background agent in your organization.\n\nThe response includes the agent's `access_key` and a one-time plaintext `secret`. Store the secret securely — it is never returned again. The agent authenticates to the gateway with `Authorization: Bearer <access_key>:<secret>`.\n",
        "tags": [
          "Background Agents"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBackgroundAgentRequest"
              },
              "examples": {
                "claudeAgent": {
                  "summary": "Claude Managed Agents",
                  "value": {
                    "name": "Support Triage Agent",
                    "slug": "support-triage-agent",
                    "description": "Triages incoming support tickets",
                    "platform": "claude-managed-agents",
                    "platform_config": {
                      "model": "claude-sonnet-4-6",
                      "system_prompt": "You triage support tickets."
                    }
                  }
                },
                "customAgent": {
                  "summary": "Custom runtime (defaults)",
                  "value": {
                    "name": "My Agent",
                    "slug": "my-agent"
                  }
                },
                "agentWithConnectLinks": {
                  "summary": "With connect links for a bot account",
                  "value": {
                    "name": "Release Bot",
                    "slug": "release-bot",
                    "platform": "claude-managed-agents",
                    "connect": {
                      "integrations": [
                        "github",
                        "jira"
                      ],
                      "user_email": "bot-release@acme.com"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Background agent created successfully. The `secret` field is only returned on creation.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/BackgroundAgent"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "secret": {
                              "type": "string",
                              "description": "One-time plaintext secret. Never returned again."
                            },
                            "auth_urls": {
                              "type": "array",
                              "description": "Connect links for the MCP servers listed in `connect`. Only present when `connect` was sent.",
                              "items": {
                                "$ref": "#/components/schemas/AgentAuthUrl"
                              }
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "examples": {
                  "missingName": {
                    "summary": "Missing name",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "name: name is required"
                    }
                  },
                  "invalidSlug": {
                    "summary": "Invalid slug format",
                    "value": {
                      "code": "INVALID_FORMAT",
                      "message": "slug: slug must be lowercase alphanumeric with hyphens"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "An agent with this slug already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Agent with this slug already exists"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to create background agent"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "getBackgroundAgent",
        "summary": "Get Background Agent",
        "description": "Returns a single background agent by ID, including its capabilities, platform configuration, and sync state.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          }
        ],
        "responses": {
          "200": {
            "description": "Background agent retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BackgroundAgent"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Background agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to fetch background agent"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateBackgroundAgent",
        "summary": "Update Background Agent",
        "description": "Updates an existing background agent by ID.\n\nOnly the fields provided in the request body will be updated. When `capabilities` is provided it replaces the agent's capabilities as a whole. After changing capabilities or platform configuration for a synced agent, call the sync endpoint to push the changes to the external platform.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent to update",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBackgroundAgentRequest"
              },
              "examples": {
                "disableAgent": {
                  "summary": "Disable an agent",
                  "value": {
                    "status": "disabled"
                  }
                },
                "updatePlatformConfig": {
                  "summary": "Change the model",
                  "value": {
                    "platform_config": {
                      "model": "claude-opus-4-8"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Background agent updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BackgroundAgent"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "status: Invalid enum value"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Background agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update background agent"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteBackgroundAgent",
        "summary": "Delete Background Agent",
        "description": "Deletes a background agent by ID.\n\nThis operation is permanent and cannot be undone. The agent's gateway credentials stop working immediately. Resources created on the external platform (e.g. the Claude managed agent) are not removed.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent to delete",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          }
        ],
        "responses": {
          "200": {
            "description": "Background agent deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "message": "Background agent deleted successfully"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Background agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to delete background agent"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/by-slug/{slug}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "getBackgroundAgentBySlug",
        "summary": "Get Background Agent by Slug",
        "description": "Returns a single background agent by its slug.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The slug of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "support-triage-agent"
          }
        ],
        "responses": {
          "200": {
            "description": "Background agent retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BackgroundAgent"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Background agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to fetch background agent"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{id}/sync": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "syncBackgroundAgent",
        "summary": "Sync Background Agent",
        "description": "Syncs the agent to its platform. Creates or updates the agent definition there, uploads enabled skills, and stores fresh gateway credentials on the platform side. The dashboard calls this action **Deploy**; the endpoint keeps the older `/sync` name.\n\nSyncing rotates the agent's secret internally, so any previously issued plaintext secret stops working.\n\nApplies to platforms that keep an external copy of the agent, including `willow-agents`, `claude-managed-agents`, `aws-agentcore`, and custom types registered through **Add custom type** (`custom-managed`).\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent to sync",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mcp_url": {
                    "type": "string",
                    "description": "Override the MCP gateway URL stored on the external platform. Defaults to the organization's gateway URL.",
                    "example": "https://run.withwillow.ai/agent/support-triage-agent"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Agent synced successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "sync_state": {
                          "$ref": "#/components/schemas/AgentSyncState"
                        },
                        "skill_sync_errors": {
                          "type": "array",
                          "description": "Skills that failed to upload to the platform, if any.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "skill_name": {
                                "type": "string"
                              },
                              "error": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Agent cannot be synced (unsupported platform or platform not connected)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Claude Managed Agents is not connected. Add your ANTHROPIC_API_KEY in the agent platform settings first."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to sync background agent"
                }
              }
            }
          },
          "502": {
            "description": "The external platform rejected the sync",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to sync with Claude Managed Agents: invalid API key"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{id}/rotate-secret": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "rotateBackgroundAgentSecret",
        "summary": "Rotate Background Agent Secret",
        "description": "Rotates the agent's gateway secret and returns the new plaintext secret.\n\nThe previous secret stops working immediately. The new secret is only returned once — store it securely. If the agent is synced to an external platform, sync it again afterwards so the platform receives the new credentials.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          }
        ],
        "responses": {
          "200": {
            "description": "Secret rotated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "secret": {
                          "type": "string",
                          "description": "The new plaintext secret. Never returned again."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Background agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to rotate background agent secret"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{id}/auth-url": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "getBackgroundAgentAuthUrl",
        "summary": "Get Background Agent Connect Link",
        "description": "Returns the link that connects one of the agent's MCP servers.\n\nA background agent is not a user, so it cannot hold a connection of its own — it runs an MCP server as the connected account of an org member (`auth_mode: \"connected_user\"`). That is the person themselves for a personal assistant, or a dedicated bot user (for example an Okta service account) for a shared agent.\n\nWithout `user_email` the link is for the account the agent is already configured to use. This endpoint only reads: pass `user_email` to preview a link for another account, or use `POST` to also point the agent at that account.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          },
          {
            "name": "integration",
            "in": "query",
            "required": true,
            "description": "Slug of the MCP server to connect",
            "schema": {
              "type": "string"
            },
            "example": "github"
          },
          {
            "name": "user_email",
            "in": "query",
            "required": false,
            "description": "Connect this account instead of the one the agent is configured with. Must already exist in the organization.",
            "schema": {
              "type": "string"
            },
            "example": "bot-github@acme.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Connect link generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AgentAuthUrl"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing `integration`, or the agent has no connected account configured for it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "error": "\"release-bot\" has no connected account configured for \"github\". Pass user_email, or set the MCP server's authentication to a connected account first."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Background agent, MCP server, or user not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "User not found: bot-github@acme.com"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to generate auth URL"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "connectBackgroundAgentAccount",
        "summary": "Connect Background Agent Account",
        "description": "Points the listed MCP servers at `user_email`'s connected account and returns the link that connects each one — the automatable form of choosing \"Connected account\" in the agent's Tools tab and clicking Connect.\n\nThe agent's other MCP servers keep their existing authentication. The connection itself is only created once the returned link is opened by (or on behalf of) that account.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "integrations",
                  "user_email"
                ],
                "properties": {
                  "integrations": {
                    "type": "array",
                    "minItems": 1,
                    "description": "Slugs of the MCP servers to connect",
                    "items": {
                      "type": "string"
                    }
                  },
                  "user_email": {
                    "type": "string",
                    "description": "Email of the org member whose account the agent runs as"
                  }
                }
              },
              "example": {
                "integrations": [
                  "github",
                  "jira"
                ],
                "user_email": "bot-release@acme.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Agent configured and connect links generated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "auth_urls": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AgentAuthUrl"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "user_email: user_email is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Background agent, MCP server, or user not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "MCP server not found: github"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to generate auth URL"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{id}/invoke": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "invokeBackgroundAgent",
        "summary": "Invoke Background Agent",
        "description": "Sends a message to the agent on its external platform and starts (or resumes) a conversation.\n\nConversations are correlated by `session_key` — a stable identifier you choose for the entity or thread (for example, a ticket ID or a pull request URL). Sending another message with the same `session_key` resumes the existing conversation; a new key starts a new session.\n\nThe agent must be active and synced to the `claude-managed-agents` or `aws-agentcore` platform.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent to invoke",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvokeBackgroundAgentRequest"
              },
              "example": {
                "session_key": "ticket-4821",
                "message": "A new ticket was opened: users report login failures after the last deploy. Please investigate."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message delivered to the agent",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "session_id": {
                          "type": "string",
                          "description": "The platform session the message was delivered to."
                        },
                        "session_key": {
                          "type": "string",
                          "description": "The correlation key from the request."
                        },
                        "created": {
                          "type": "boolean",
                          "description": "Whether a new session was created for this key."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": {
                    "session_id": "session_xyz789",
                    "session_key": "ticket-4821",
                    "created": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, agent disabled, unsupported platform, or agent not synced",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "examples": {
                  "notSynced": {
                    "summary": "Agent not synced",
                    "value": {
                      "error": "Agent is not synced to its platform. Sync it from the agent settings first."
                    }
                  },
                  "disabled": {
                    "summary": "Agent disabled",
                    "value": {
                      "error": "Agent is disabled"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Agent not found"
                }
              }
            }
          },
          "429": {
            "description": "The agent is over its budget or has reached one of its session or message limits. The message was not delivered; send it again after the number of seconds in `Retry-After`.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the budget or limit's current period ends.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "This agent has reached its limit of 20 new sessions per hour. Try again in 12 minutes, or ask the agent's owner (Dana Levi) or a Willow admin to raise the limit."
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to invoke background agent"
                }
              }
            }
          },
          "502": {
            "description": "The external platform rejected the message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to deliver message to Claude Managed Agents: overloaded"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{id}/sessions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listBackgroundAgentSessions",
        "summary": "List Background Agent Sessions",
        "description": "Lists the agent's conversation sessions on its external platform. Sessions created via the invoke endpoint (or webhooks) are enriched with their local `session_key` correlation.\n\nOnly available for agents on the `claude-managed-agents` platform.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of sessions to return.",
            "schema": {
              "type": "integer"
            },
            "example": 20
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Opaque page cursor from a previous response (`pagination.next_page` / `pagination.prev_page`).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "description": "Sort order by creation time.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "example": "desc"
          },
          {
            "name": "include_archived",
            "in": "query",
            "required": false,
            "description": "Include archived sessions.",
            "schema": {
              "type": "boolean"
            },
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "Sessions retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AgentSession"
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "properties": {
                        "next_page": {
                          "type": "string",
                          "nullable": true
                        },
                        "prev_page": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Agent is not on a platform that supports sessions or is not synced",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Sessions are only available for Claude Managed Agents (this agent is on \"custom\")"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Background agent not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Agent not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list background agent sessions"
                }
              }
            }
          },
          "502": {
            "description": "The external platform rejected the request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list sessions from Claude Managed Agents: overloaded"
                }
              }
            }
          }
        }
      }
    },
    "/api/background-agents/{id}/sessions/{sessionId}/events": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "getBackgroundAgentSessionEvents",
        "summary": "Get Session Events",
        "description": "Returns the conversation log (event stream) for a single session of this agent, along with the session record.\n\nOnly available for agents on the `claude-managed-agents` platform.\n",
        "tags": [
          "Background Agents"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The ID of the background agent",
            "schema": {
              "type": "string"
            },
            "example": "agent_abc123"
          },
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "The platform session ID (from the sessions list or the invoke response)",
            "schema": {
              "type": "string"
            },
            "example": "session_xyz789"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of events to return.",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Opaque page cursor from a previous response.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "description": "Sort order by event time.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "example": "asc"
          }
        ],
        "responses": {
          "200": {
            "description": "Session events retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "session": {
                          "$ref": "#/components/schemas/AgentSession"
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/AgentSessionEvent"
                          }
                        },
                        "pagination": {
                          "type": "object",
                          "properties": {
                            "next_page": {
                              "type": "string",
                              "nullable": true
                            },
                            "prev_page": {
                              "type": "string",
                              "nullable": true
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Agent or session not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                },
                "example": {
                  "error": "Session not found"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to fetch session events"
                }
              }
            }
          },
          "502": {
            "description": "The external platform rejected the request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to load session events from Claude Managed Agents: overloaded"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth-exchange": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "post": {
        "operationId": "exchangeAuth",
        "summary": "Exchange JWT for Connect Credentials",
        "description": "Exchanges an external JWT token (verified via the organization's configured JWKS URI) for Willow Connect credentials.\n\nThis endpoint enables programmatic token generation for users authenticated by your identity provider (Okta, Keycloak, etc.).\n\n## Prerequisites\n\n1. Configure your SSO provider (Okta or Keycloak) in Admin Settings with a JWKS URI\n2. Generate an API token with the `connect:exchange-auth` scope (or `connect:write` / `all` which include it)\n\n## How it works\n\n1. Your application authenticates a user with your identity provider and obtains a JWT\n2. Send the JWT in the `Authorization: Bearer <jwt>` header along with your API key in the `x-api-key` header\n3. Willow verifies the JWT against the configured JWKS URI\n4. If valid, Willow issues Connect credentials (access token, refresh token, etc.) with the original JWT stored as the `id_token`\n\nThe JWT must contain a `sub`, `email`, or `client_id` claim to identify the user.\n",
        "tags": [
          "Auth Exchange"
        ],
        "security": [],
        "parameters": [
          {
            "name": "x-api-key",
            "in": "header",
            "required": true,
            "description": "API token with `connect:exchange-auth` scope (or `connect:write` / `all`).\nTokens are prefixed with `wxt_` and can be generated from Admin Settings.\n",
            "schema": {
              "type": "string"
            },
            "example": "wxt_abc123..."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "No request body is needed. The JWT is sent via the Authorization header."
        },
        "responses": {
          "200": {
            "description": "JWT verified and credentials issued successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthExchangeResponse"
                },
                "example": {
                  "access_token": "a1b2c3d4e5f6...",
                  "token_type": "Bearer",
                  "access_token_expired_at": 1719878400000,
                  "scope": "openid email profile",
                  "refresh_token": "f6e5d4c3b2a1...",
                  "expires_in": 86400000,
                  "id_token": "eyJhbGciOiJSUzI1NiIs..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request (empty JWT, missing claims, or JWKS URI not configured)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "examples": {
                  "noJwks": {
                    "summary": "JWKS URI not configured",
                    "value": {
                      "error": "JWKS URI not configured. Configure it in your SSO provider settings (Okta/Keycloak)."
                    }
                  },
                  "noClaims": {
                    "summary": "Missing required claims",
                    "value": {
                      "error": "JWT must contain a sub, email, or client_id claim"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Authorization header or API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "examples": {
                  "missingApiKey": {
                    "summary": "Missing API key",
                    "value": {
                      "error": "Missing x-api-key header"
                    }
                  },
                  "invalidJwt": {
                    "summary": "JWT verification failed",
                    "value": {
                      "error": "JWT verification failed"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key does not have the required scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Invalid API key or insufficient scopes"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "An error occurred while processing the auth exchange request"
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery/mcp-servers": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listDiscoveredMcpServers",
        "summary": "List Discovered MCP Servers",
        "description": "Returns MCP servers discovered across your organization's devices by the Willow Scan Agent.\n\nResults are grouped by identity hash (identical configurations seen on multiple devices are merged) and include a `status` of either `shadow` (running outside the gateway) or `managed` (proxied through your Willow gateway), plus any guard-check and AI-risk assessments.\n",
        "tags": [
          "AI Discovery"
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of MCP servers to return (1-200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            },
            "example": 100
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by governance status.",
            "schema": {
              "type": "string",
              "enum": [
                "shadow",
                "managed"
              ]
            },
            "example": "shadow"
          }
        ],
        "responses": {
          "200": {
            "description": "List of discovered MCP servers retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DiscoveredMcpServer"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/DiscoveryPagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list discovered MCP servers"
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery/skills": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listDiscoveredSkills",
        "summary": "List Discovered Skills",
        "description": "Returns agent skills discovered across your organization's devices by the Willow Scan Agent.\n\nResults are grouped by identity hash and include any guard-check and AI-risk assessments.\n",
        "tags": [
          "AI Discovery"
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of skills to return (1-200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            },
            "example": 100
          }
        ],
        "responses": {
          "200": {
            "description": "List of discovered skills retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DiscoveredSkill"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/DiscoveryPagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list discovered skills"
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery/memory": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listDiscoveredMemory",
        "summary": "List Discovered Agent Memory",
        "description": "Returns agent memory files (for example `CLAUDE.md` and `AGENTS.md`) discovered across your organization's devices by the Willow Scan Agent.\n\nResults are grouped by identity hash.\n",
        "tags": [
          "AI Discovery"
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of memory files to return (1-200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            },
            "example": 100
          }
        ],
        "responses": {
          "200": {
            "description": "List of discovered memory files retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DiscoveredMemory"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/DiscoveryPagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list discovered memory files"
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery/devices": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listDiscoveredDevices",
        "summary": "List Devices",
        "description": "Returns the devices reporting to your organization via the Willow Scan Agent, including the capability counts and AI agents detected on each device.\n",
        "tags": [
          "AI Discovery"
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of devices to return (1-200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            },
            "example": 100
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by activity. `active` devices scanned recently; `stale` devices have not scanned within the staleness window.\n",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "stale"
              ]
            },
            "example": "active"
          },
          {
            "name": "staleDays",
            "in": "query",
            "required": false,
            "description": "Number of days without a scan before a device is considered stale. Defaults to 3. Use with `status=stale` to poll for devices that stopped reporting (for example, `staleDays=2` for a daily keepalive with one day of buffer).\n",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 3
            },
            "example": 2
          }
        ],
        "responses": {
          "200": {
            "description": "List of devices retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DiscoveredDevice"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/DiscoveryPagination"
                    },
                    "activeCount": {
                      "type": "integer",
                      "description": "Total number of active devices",
                      "example": 42
                    },
                    "staleCount": {
                      "type": "integer",
                      "description": "Total number of stale devices",
                      "example": 7
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list devices"
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery/agents": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "listDiscoveredAgents",
        "summary": "List AI Agents",
        "description": "Returns the AI agents (for example Cursor, Claude Code, Windsurf) discovered across your organization's devices, merged by agent name with the per-device instances that reported them.\n",
        "tags": [
          "AI Discovery"
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Zero-based cursor offset for pagination.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "example": 0
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of agents to return (1-200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            },
            "example": 100
          }
        ],
        "responses": {
          "200": {
            "description": "List of AI agents retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DiscoveredAiAgent"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/DiscoveryPagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to list AI agents"
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery/stats": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "getDiscoveryStats",
        "summary": "Get Discovery Statistics",
        "description": "Returns summary statistics for AI usage discovered across your organization, including totals for devices, MCP servers, skills, memory files, and AI agents, plus an aggregated guard-check and AI-risk severity breakdown.\n",
        "tags": [
          "AI Discovery"
        ],
        "responses": {
          "200": {
            "description": "Discovery statistics retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DiscoveryStats"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to fetch discovery stats"
                }
              }
            }
          }
        }
      }
    },
    "/api/discovery/policy": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiVersion"
        }
      ],
      "get": {
        "operationId": "getDiscoveryPolicy",
        "summary": "Get Enforcement Policy",
        "description": "Returns the AI Discovery enforcement policy for your organization.\n\nThe policy defines the default action applied to discovered MCP servers and skills when no rule matches, along with an ordered list of rules that are evaluated top-to-bottom (first match wins).\n",
        "tags": [
          "AI Discovery Policy"
        ],
        "responses": {
          "200": {
            "description": "Enforcement policy retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EnforcementPolicy"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to fetch enforcement policy"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateDiscoveryPolicy",
        "summary": "Update Enforcement Policy",
        "description": "Updates the AI Discovery enforcement policy for your organization.\n\nOnly the fields provided in the request body are updated. When `rules` is provided it **replaces** the entire ordered rule set — rules are ordered by their position in the array, and any rule without an `id` is assigned a generated one.\n",
        "tags": [
          "AI Discovery Policy"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEnforcementPolicyRequest"
              },
              "examples": {
                "updateDefaults": {
                  "summary": "Change default actions",
                  "value": {
                    "mcp_servers": "warn",
                    "skills": "allow"
                  }
                },
                "blockSpecific": {
                  "summary": "Block a specific discovered MCP server",
                  "value": {
                    "rules": [
                      {
                        "name": "Block unknown filesystem MCP",
                        "match_field": "hash",
                        "pattern": "9f2c1a7e5b3d4c8e6a1f0b2d3e4f5a6b",
                        "target": "mcp_server",
                        "action": "block",
                        "status": "active"
                      }
                    ]
                  }
                },
                "blockAllUnmanaged": {
                  "summary": "Warn on all unmanaged skills for a group",
                  "value": {
                    "skills": "allow",
                    "rules": [
                      {
                        "name": "Warn unmanaged skills for Engineering",
                        "match_field": "all_unmanaged",
                        "pattern": "",
                        "target": "skill",
                        "action": "warn",
                        "scope_type": "group",
                        "scope_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
                        "scope_name": "Engineering"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enforcement policy updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/EnforcementPolicy"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                },
                "example": {
                  "code": "INVALID_FORMAT",
                  "message": "rules.0.name: name cannot be empty"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerError"
                },
                "example": {
                  "error": "Failed to update enforcement policy"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API token authentication. Tokens are prefixed with `wxt_` and can be generated from Admin Settings.\n"
      }
    },
    "parameters": {
      "ApiVersion": {
        "name": "Willow-API-Version",
        "in": "header",
        "required": false,
        "description": "Admin API version to use. Omit the header to get version `1`, which is\ncurrently the only version. Breaking changes ship only under a new\nversion, announced at least 6 months ahead. See\n[API Versioning and Deprecation](/docs/developers/api-versioning).\n",
        "schema": {
          "type": "string",
          "enum": [
            "1"
          ],
          "default": "1"
        }
      }
    },
    "headers": {
      "Deprecation": {
        "description": "Sent on responses from a deprecated operation (RFC 9745). The value is\nthe date the operation was deprecated, for example `@1798761600`.\n",
        "schema": {
          "type": "string"
        }
      },
      "Sunset": {
        "description": "Sent on responses from a deprecated operation (RFC 8594). The HTTP date\nafter which the operation may be removed, at least 6 months after the\ndeprecation was announced.\n",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "Forbidden": {
        "description": "The token is valid but its scopes do not permit this operation. Every\nendpoint enforces the scopes described in [API Tokens](/docs/admin/api-tokens),\nso any of them can return this.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UnauthorizedError"
            },
            "example": {
              "error": "Forbidden"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required or invalid token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UnauthorizedError"
            },
            "example": {
              "error": "Unauthorized"
            }
          }
        }
      }
    },
    "schemas": {
      "ValidationError": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Error code",
            "example": "INVALID_FORMAT"
          },
          "message": {
            "type": "string",
            "description": "Detailed error message",
            "example": "name: name is required"
          },
          "error": {
            "type": "string",
            "description": "Short error string returned instead of code/message by handlers that have not adopted the structured form. Observed on addIntegrationsToGroup.",
            "example": "Group not found"
          }
        }
      },
      "UnauthorizedError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message",
            "example": "Unauthorized"
          }
        }
      },
      "ServerError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message",
            "example": "Internal server error"
          }
        }
      },
      "NotFoundError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message",
            "example": "Resource not found"
          }
        }
      },
      "DiscoveryPagination": {
        "type": "object",
        "properties": {
          "hasMore": {
            "type": "boolean",
            "description": "Whether more results are available beyond the current page",
            "example": true
          },
          "total": {
            "type": "integer",
            "description": "Total number of matching records",
            "example": 128
          }
        }
      },
      "DiscoveryGuardCheck": {
        "type": "object",
        "nullable": true,
        "description": "Result of the most recent guard (policy) check, or `null` if not evaluated",
        "properties": {
          "severity": {
            "type": "string",
            "enum": [
              "pass",
              "warning",
              "error"
            ],
            "description": "Guard-check outcome severity",
            "example": "warning"
          },
          "details": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Human-readable findings from the guard check",
            "example": [
              "Server requests broad filesystem access"
            ]
          },
          "checked_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the guard check was performed",
            "example": "2024-06-01T12:00:00Z"
          }
        }
      },
      "DiscoveryAiRisk": {
        "type": "object",
        "nullable": true,
        "description": "AI-assessed risk for the capability, or `null` if not evaluated",
        "properties": {
          "level": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high",
              "critical"
            ],
            "description": "Overall AI risk level",
            "example": "high"
          },
          "score": {
            "type": "number",
            "description": "Numeric risk score",
            "example": 78
          },
          "reasoning": {
            "type": "string",
            "description": "Explanation for the assessed risk",
            "example": "Grants write access to production systems without scoping"
          },
          "calculated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the risk assessment was calculated",
            "example": "2024-06-01T12:00:00Z"
          }
        }
      },
      "DiscoveredMcpServerConfig": {
        "type": "object",
        "description": "The raw MCP server configuration as discovered on the device",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "stdio",
              "http",
              "sse",
              "streamable-http"
            ],
            "example": "stdio"
          },
          "command": {
            "type": "string",
            "example": "npx"
          },
          "args": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "-y",
              "@modelcontextprotocol/server-filesystem",
              "/Users"
            ]
          },
          "env": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "example": "https://mcp.example.com/sse"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "DiscoveredMcpServer": {
        "type": "object",
        "properties": {
          "identityHash": {
            "type": "string",
            "description": "Stable hash identifying this MCP server configuration",
            "example": "9f2c1a7e5b3d4c8e6a1f0b2d3e4f5a6b"
          },
          "identifier": {
            "type": "string",
            "description": "Human-friendly identifier derived from the configuration",
            "example": "@modelcontextprotocol/server-filesystem"
          },
          "displayName": {
            "type": "string",
            "nullable": true,
            "description": "Name shown for this server in the AI Discovery UI",
            "example": "Filesystem"
          },
          "userCount": {
            "type": "integer",
            "description": "Number of distinct users this server was discovered for",
            "example": 3
          },
          "names": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "All configuration key names this server was registered under",
            "example": [
              "filesystem"
            ]
          },
          "capabilityType": {
            "type": "string",
            "example": "mcp_server"
          },
          "config": {
            "$ref": "#/components/schemas/DiscoveredMcpServerConfig"
          },
          "sourceApplications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI applications the server was configured in",
            "example": [
              "cursor",
              "claude-desktop"
            ]
          },
          "sourceFilePaths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Config file paths where the server was found",
            "example": [
              "~/.cursor/mcp.json"
            ]
          },
          "deviceCount": {
            "type": "integer",
            "description": "Number of distinct devices this server was seen on",
            "example": 5
          },
          "instanceCount": {
            "type": "integer",
            "description": "Total number of instances (across devices and apps)",
            "example": 8
          },
          "status": {
            "type": "string",
            "enum": [
              "shadow",
              "managed"
            ],
            "description": "Whether the server runs outside (`shadow`) or through (`managed`) the Willow gateway",
            "example": "shadow"
          },
          "toolkitName": {
            "type": "string",
            "nullable": true,
            "example": null
          },
          "mcpName": {
            "type": "string",
            "nullable": true,
            "example": null
          },
          "guardCheck": {
            "$ref": "#/components/schemas/DiscoveryGuardCheck"
          },
          "aiRisk": {
            "$ref": "#/components/schemas/DiscoveryAiRisk"
          }
        }
      },
      "DiscoveredSkill": {
        "type": "object",
        "properties": {
          "identityHash": {
            "type": "string",
            "example": "3b7d1e9a2c4f5a6b8d0e1f2a3b4c5d6e"
          },
          "name": {
            "type": "string",
            "example": "pdf-processing"
          },
          "capabilityType": {
            "type": "string",
            "enum": [
              "skill"
            ],
            "example": "skill"
          },
          "config": {
            "type": "object",
            "properties": {
              "description": {
                "type": "string",
                "example": "Extracts text and tables from PDF documents"
              },
              "content": {
                "type": "string",
                "description": "The skill's markdown content"
              },
              "compatibility": {
                "type": "string"
              },
              "metadata": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              }
            }
          },
          "scope": {
            "type": "string",
            "enum": [
              "global",
              "local"
            ],
            "example": "local"
          },
          "sourceApplications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "claude-code"
            ]
          },
          "sourceFilePaths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "~/.claude/skills/pdf-processing/SKILL.md"
            ]
          },
          "deviceCount": {
            "type": "integer",
            "example": 3
          },
          "instanceCount": {
            "type": "integer",
            "example": 3
          },
          "guardCheck": {
            "$ref": "#/components/schemas/DiscoveryGuardCheck"
          },
          "aiRisk": {
            "$ref": "#/components/schemas/DiscoveryAiRisk"
          }
        }
      },
      "DiscoveredMemory": {
        "type": "object",
        "properties": {
          "identityHash": {
            "type": "string",
            "example": "a1b2c3d4e5f60718293a4b5c6d7e8f90"
          },
          "name": {
            "type": "string",
            "example": "CLAUDE.md"
          },
          "capabilityType": {
            "type": "string",
            "enum": [
              "memory"
            ],
            "example": "memory"
          },
          "config": {
            "type": "object",
            "properties": {
              "content": {
                "type": "string",
                "description": "The memory file contents"
              },
              "memoryType": {
                "type": "string",
                "enum": [
                  "claude",
                  "agents"
                ],
                "example": "claude"
              }
            }
          },
          "scope": {
            "type": "string",
            "enum": [
              "global",
              "local"
            ],
            "example": "local"
          },
          "sourceApplications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "claude-code"
            ]
          },
          "sourceFilePaths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "~/project/CLAUDE.md"
            ]
          },
          "deviceCount": {
            "type": "integer",
            "example": 2
          },
          "instanceCount": {
            "type": "integer",
            "example": 2
          }
        }
      },
      "DiscoveredDevice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
          },
          "deviceId": {
            "type": "string",
            "description": "Stable device identifier reported by the scan agent",
            "example": "e3b0c44298fc1c149afbf4c8996fb924"
          },
          "hostname": {
            "type": "string",
            "example": "johns-macbook"
          },
          "username": {
            "type": "string",
            "example": "john"
          },
          "os": {
            "type": "string",
            "example": "macOS 14.5"
          },
          "platform": {
            "type": "string",
            "example": "darwin"
          },
          "architecture": {
            "type": "string",
            "example": "arm64"
          },
          "lastScanDate": {
            "type": "string",
            "format": "date-time",
            "example": "2024-06-01T12:00:00Z"
          },
          "capabilityCounts": {
            "type": "object",
            "nullable": true,
            "additionalProperties": {
              "type": "integer"
            },
            "example": {
              "mcp_server": 4,
              "skill": 2,
              "memory": 1
            }
          },
          "sourceApplications": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "example": [
              "cursor",
              "claude-code"
            ]
          },
          "aiAgents": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "example": [
              "cursor",
              "claude-code"
            ]
          },
          "userId": {
            "type": "string",
            "nullable": true,
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "userName": {
            "type": "string",
            "nullable": true,
            "example": "John Doe"
          },
          "userEmail": {
            "type": "string",
            "nullable": true,
            "example": "john@example.com"
          },
          "agentVersion": {
            "type": "string",
            "nullable": true,
            "example": "1.4.2"
          }
        }
      },
      "DiscoveredAiAgentInstance": {
        "type": "object",
        "properties": {
          "deviceId": {
            "type": "string",
            "example": "e3b0c44298fc1c149afbf4c8996fb924"
          },
          "hostname": {
            "type": "string",
            "example": "johns-macbook"
          },
          "username": {
            "type": "string",
            "example": "john"
          },
          "config": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "DiscoveredAiAgent": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "cursor"
          },
          "deviceCount": {
            "type": "integer",
            "example": 12
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "example": "2024-05-01T08:30:00Z"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time",
            "example": "2024-06-01T12:00:00Z"
          },
          "instances": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DiscoveredAiAgentInstance"
            }
          }
        }
      },
      "DiscoveryStats": {
        "type": "object",
        "properties": {
          "totalDevices": {
            "type": "integer",
            "example": 49
          },
          "totalMcps": {
            "type": "integer",
            "example": 128
          },
          "totalSkills": {
            "type": "integer",
            "example": 37
          },
          "totalMemory": {
            "type": "integer",
            "example": 15
          },
          "totalAiAgents": {
            "type": "integer",
            "example": 6
          },
          "riskSummary": {
            "type": "object",
            "description": "Aggregated guard-check and AI-risk severity counts across MCP servers and skills",
            "properties": {
              "guardBlocked": {
                "type": "integer",
                "example": 4
              },
              "guardWarning": {
                "type": "integer",
                "example": 11
              },
              "guardPassed": {
                "type": "integer",
                "example": 90
              },
              "aiCritical": {
                "type": "integer",
                "example": 2
              },
              "aiHigh": {
                "type": "integer",
                "example": 9
              },
              "aiMedium": {
                "type": "integer",
                "example": 21
              },
              "aiLow": {
                "type": "integer",
                "example": 73
              }
            }
          }
        }
      },
      "EnforcementRule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the rule",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "name": {
            "type": "string",
            "description": "Display name for the rule",
            "example": "Block unknown filesystem MCP"
          },
          "pattern": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "The value(s) matched by `match_field`. For `match_field: hash` this is one or more identity hashes; for `match_field: all_unmanaged` it is ignored (use an empty string).\n",
            "example": "9f2c1a7e5b3d4c8e6a1f0b2d3e4f5a6b"
          },
          "match_field": {
            "type": "string",
            "enum": [
              "hash",
              "all_unmanaged"
            ],
            "description": "What the rule matches against",
            "example": "hash"
          },
          "target": {
            "type": "string",
            "enum": [
              "mcp_server",
              "skill",
              "all"
            ],
            "description": "Capability type the rule applies to",
            "example": "mcp_server"
          },
          "action": {
            "type": "string",
            "enum": [
              "allow",
              "warn",
              "block"
            ],
            "description": "Action taken when the rule matches",
            "example": "block"
          },
          "enabled": {
            "type": "boolean",
            "example": true
          },
          "order": {
            "type": "integer",
            "description": "Evaluation order (rules are checked ascending; first match wins)",
            "example": 0
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active"
            ],
            "description": "Draft rules are stored but not enforced",
            "example": "active"
          },
          "scope_type": {
            "type": "string",
            "enum": [
              "all",
              "group",
              "user",
              "device"
            ],
            "description": "Which targets the rule applies to",
            "example": "group"
          },
          "scope_id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Identifier(s) of the scoped group/user/device",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "scope_name": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Human-readable name(s) of the scoped group/user/device",
            "example": "Engineering"
          },
          "agents": {
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "AI agents (source applications) the rule is limited to. Omit or send null to apply the rule to every agent.",
            "example": [
              "cursor"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "example": "2024-06-01T12:00:00Z"
          },
          "created_by": {
            "type": "string",
            "example": "admin@example.com"
          }
        }
      },
      "EnforcementPolicy": {
        "type": "object",
        "properties": {
          "mcp_servers": {
            "type": "string",
            "enum": [
              "allow",
              "warn",
              "block"
            ],
            "description": "Default action for discovered MCP servers when no rule matches",
            "example": "allow"
          },
          "skills": {
            "type": "string",
            "enum": [
              "allow",
              "warn",
              "block"
            ],
            "description": "Default action for discovered skills when no rule matches",
            "example": "allow"
          },
          "capability_names": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Maps identity hashes to human-readable display names used in rules",
            "example": {
              "9f2c1a7e5b3d4c8e6a1f0b2d3e4f5a6b": "filesystem"
            }
          },
          "rules": {
            "type": "array",
            "description": "Ordered rules, evaluated top-to-bottom (first match wins)",
            "items": {
              "$ref": "#/components/schemas/EnforcementRule"
            }
          }
        }
      },
      "UpdateEnforcementPolicyRequest": {
        "type": "object",
        "description": "At least one field must be provided. When `rules` is present it replaces the entire ordered rule set.\n",
        "properties": {
          "mcp_servers": {
            "type": "string",
            "enum": [
              "allow",
              "warn",
              "block"
            ],
            "description": "Default action for discovered MCP servers when no rule matches",
            "example": "warn"
          },
          "skills": {
            "type": "string",
            "enum": [
              "allow",
              "warn",
              "block"
            ],
            "description": "Default action for discovered skills when no rule matches",
            "example": "allow"
          },
          "capability_names": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Maps identity hashes to human-readable display names used in rules"
          },
          "rules": {
            "type": "array",
            "description": "Full ordered set of rules to store (replaces existing rules)",
            "items": {
              "type": "object",
              "required": [
                "name",
                "pattern",
                "match_field",
                "target",
                "action"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Existing rule id; omit to create a new rule"
                },
                "name": {
                  "type": "string",
                  "example": "Block unknown filesystem MCP"
                },
                "pattern": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  ],
                  "example": "9f2c1a7e5b3d4c8e6a1f0b2d3e4f5a6b"
                },
                "match_field": {
                  "type": "string",
                  "enum": [
                    "hash",
                    "all_unmanaged"
                  ],
                  "example": "hash"
                },
                "target": {
                  "type": "string",
                  "enum": [
                    "mcp_server",
                    "skill",
                    "all"
                  ],
                  "example": "mcp_server"
                },
                "action": {
                  "type": "string",
                  "enum": [
                    "allow",
                    "warn",
                    "block"
                  ],
                  "example": "block"
                },
                "enabled": {
                  "type": "boolean",
                  "default": true
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "draft",
                    "active"
                  ],
                  "default": "active"
                },
                "scope_type": {
                  "type": "string",
                  "enum": [
                    "all",
                    "group",
                    "user",
                    "device"
                  ]
                },
                "scope_id": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "scope_name": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "agents": {
                  "oneOf": [
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "AI agents (source applications) the rule is limited to. Omit or send null to apply the rule to every agent."
                }
              }
            }
          }
        }
      },
      "Connector": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Catalog item identifier. Use this value as the `connector_id` when checking usage.",
            "example": "slack"
          },
          "source": {
            "type": "string",
            "enum": [
              "connector",
              "registry"
            ],
            "description": "Where the entry comes from:\n- `connector` — a built-in, first-party connector maintained in Willow's connector database.\n- `registry` — an entry from the public MCP registry directory (community/third-party servers).\n",
            "example": "connector"
          },
          "name": {
            "type": "string",
            "description": "Display name of the connector",
            "example": "Slack"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable description of the connector",
            "example": "Send messages and manage channels in Slack"
          },
          "logo_url": {
            "type": "string",
            "nullable": true,
            "description": "URL to the connector's logo image",
            "example": "https://icons.withwillow.ai/connectors/slack.svg"
          },
          "website": {
            "type": "string",
            "nullable": true,
            "description": "Connector vendor or documentation website",
            "example": "https://slack.com"
          },
          "category": {
            "type": "string",
            "nullable": true,
            "description": "Category the connector belongs to",
            "example": "Communication"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "beta",
              "soon"
            ],
            "description": "Availability status. Registry entries are always reported as `active`.",
            "example": "active"
          },
          "auth_types": {
            "type": "array",
            "description": "Authentication methods supported by the connector",
            "items": {
              "type": "string"
            },
            "example": [
              "proxy-oauth"
            ]
          },
          "tools_count": {
            "type": "integer",
            "description": "Number of tools the connector exposes. Always `0` for registry entries.",
            "example": 4
          },
          "tools": {
            "type": "array",
            "nullable": true,
            "description": "Summary of the connector's tools. Present only for built-in connectors when `include_tools=true`.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Tool name",
                  "example": "post_message"
                },
                "read_only": {
                  "type": "boolean",
                  "description": "Whether the tool only reads data without modifying state",
                  "example": false
                },
                "risk": {
                  "type": "string",
                  "description": "Risk level assigned to the tool",
                  "example": "low"
                }
              }
            }
          },
          "transport": {
            "type": "string",
            "description": "Connection transport. Present only for `registry` entries.",
            "example": "http"
          },
          "url": {
            "type": "string",
            "description": "Remote endpoint URL. Present only for `registry` entries that expose one.",
            "example": "https://mcp.example.ai/mcp"
          },
          "repo": {
            "type": "string",
            "description": "Source code repository. Present only for some `registry` entries.",
            "example": "https://github.com/example/mcp"
          },
          "official": {
            "type": "boolean",
            "description": "Whether the registry entry is an official integration. Present only for `registry` entries.",
            "example": true
          }
        }
      },
      "ListConnectorsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Connector"
            }
          },
          "pagination": {
            "type": "object",
            "properties": {
              "cursor": {
                "type": "integer",
                "description": "Cursor used for this page.",
                "example": 0
              },
              "limit": {
                "type": "integer",
                "description": "Maximum number of records requested.",
                "example": 100
              },
              "hasMore": {
                "type": "boolean",
                "description": "Whether there are additional records after this page.",
                "example": true
              },
              "nextCursor": {
                "type": "integer",
                "nullable": true,
                "description": "Cursor value to use for the next request, or null when exhausted.",
                "example": 100
              }
            }
          },
          "totalCount": {
            "type": "integer",
            "description": "Total number of matching catalog entries across all pages.",
            "example": 1804
          }
        }
      },
      "ConnectorUsageResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "connector_id": {
                "type": "string",
                "description": "The catalog item id that was checked",
                "example": "slack"
              },
              "source": {
                "type": "string",
                "enum": [
                  "connector",
                  "registry",
                  "mixed"
                ],
                "description": "How the matches were resolved. `connector` matches by built-in connector id,\n`registry` matches installed registry MCPs by their remote URL, and `mixed`\nmeans both strategies produced matches.\n",
                "example": "connector"
              },
              "in_use": {
                "type": "boolean",
                "description": "Whether at least one MCP server in the organization uses this connector",
                "example": true
              },
              "count": {
                "type": "integer",
                "description": "Number of MCP servers in the organization that use this connector",
                "example": 2
              },
              "mcp_servers": {
                "type": "array",
                "description": "MCP servers in the organization that were created from this connector",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "MCP server identifier",
                      "example": "6f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f"
                    },
                    "slug": {
                      "type": "string",
                      "description": "MCP server slug",
                      "example": "slack"
                    },
                    "name": {
                      "type": "string",
                      "description": "MCP server display name",
                      "example": "Slack"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "draft"
                      ],
                      "description": "MCP server status",
                      "example": "active"
                    },
                    "disabled": {
                      "type": "boolean",
                      "description": "When true the MCP is temporarily turned off: it serves no tools and is hidden from clients, but keeps its status.",
                      "example": false
                    },
                    "needs_setup": {
                      "type": "boolean",
                      "description": "Whether the MCP server is still missing required credentials or configuration and needs to be set up before it can be used",
                      "example": false
                    }
                  }
                }
              }
            }
          }
        }
      },
      "AdminPagination": {
        "type": "object",
        "properties": {
          "skip": {
            "type": "number",
            "description": "Number of records skipped",
            "example": 0
          },
          "limit": {
            "type": "number",
            "description": "Maximum number of records requested",
            "example": 100
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether there are more records available",
            "example": false
          }
        }
      },
      "McpServersCursorPagination": {
        "type": "object",
        "properties": {
          "cursor": {
            "type": "integer",
            "description": "Cursor used for this page.",
            "example": 0
          },
          "limit": {
            "type": "integer",
            "description": "Maximum number of records requested.",
            "example": 100
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether there are additional records after this page.",
            "example": false
          },
          "nextCursor": {
            "type": "integer",
            "nullable": true,
            "description": "Cursor value to use for the next request, or `null` when exhausted.",
            "example": null
          }
        }
      },
      "AuthExchangeResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "The access token for Willow Connect"
          },
          "token_type": {
            "type": "string",
            "enum": [
              "Bearer"
            ],
            "description": "Token type (always \"Bearer\")"
          },
          "access_token_expired_at": {
            "type": "number",
            "description": "Unix timestamp (ms) when the access token expires"
          },
          "scope": {
            "type": "string",
            "description": "OAuth scopes granted",
            "example": "openid email profile"
          },
          "refresh_token": {
            "type": "string",
            "description": "Refresh token for obtaining new credentials"
          },
          "expires_in": {
            "type": "number",
            "description": "Token lifetime in milliseconds"
          },
          "id_token": {
            "type": "string",
            "description": "The original JWT that was exchanged, stored as the id_token"
          }
        }
      },
      "ListMcpServersResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/McpServer"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/McpServersCursorPagination"
          },
          "totalCount": {
            "type": "integer",
            "description": "Total number of matching MCP servers. Present only when `includeTotal=true`.",
            "example": 42
          }
        }
      },
      "McpServer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal identifier. Every MCP server endpoint addresses servers by\n`slug`, so this is returned for correlation rather than for use as a\nrequest parameter.\n",
            "example": "mcp_abc123"
          },
          "slug": {
            "type": "string",
            "description": "Unique identifier for the MCP server",
            "example": "my-custom-server"
          },
          "name": {
            "type": "string",
            "description": "Display name for the MCP server",
            "example": "My Custom Server"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the MCP server",
            "example": "Custom MCP server for internal tools"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "description": "Server visibility status",
            "example": "active"
          },
          "disabled": {
            "type": "boolean",
            "description": "When true the MCP is temporarily turned off: it serves no tools and is hidden from clients, but keeps its status (draft/active).",
            "example": false
          },
          "logo_url": {
            "type": "string",
            "nullable": true,
            "description": "URL to the server's logo image",
            "example": "https://icons.withwillow.ai/connectors/slack.svg"
          },
          "auth_type": {
            "type": "string",
            "nullable": true,
            "description": "Authentication type required by the server (e.g. proxy-oauth, proxy-api-key, proxy-passthrough, none)",
            "example": "proxy-oauth"
          },
          "tools_count": {
            "type": "integer",
            "description": "Number of enabled tools on this server",
            "example": 12
          },
          "is_local_mcp": {
            "type": "boolean",
            "description": "Whether this is a local (stdio) MCP server",
            "example": false
          },
          "connection": {
            "type": "object",
            "description": "Connection details for the MCP server",
            "properties": {
              "url": {
                "type": "string",
                "description": "MCP server endpoint URL",
                "example": "https://gateway.example.com/mcp?mcp=my-server"
              },
              "transport": {
                "type": "string",
                "enum": [
                  "http",
                  "stdio",
                  "both"
                ],
                "description": "Supported transport. `stdio` for local servers, `both` for remote servers.",
                "example": "both"
              }
            }
          },
          "tools": {
            "type": "array",
            "nullable": true,
            "description": "List of enabled tools. Populated when `fields` includes `tools` or `include_tools=true` (deprecated).",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Tool display name",
                  "example": "Send Message"
                },
                "slug": {
                  "type": "string",
                  "description": "Tool identifier",
                  "example": "send-message"
                },
                "description": {
                  "type": "string",
                  "description": "Tool description",
                  "example": "Send a message to a Slack channel"
                },
                "risk": {
                  "type": "string",
                  "enum": [
                    "low",
                    "mid",
                    "high"
                  ],
                  "nullable": true,
                  "description": "Risk level assigned to this tool",
                  "example": "low"
                },
                "inputSchema": {
                  "type": "object",
                  "description": "JSON Schema describing the tool's input parameters",
                  "example": {
                    "type": "object",
                    "properties": {
                      "channel": {
                        "type": "string",
                        "description": "Channel ID or name"
                      },
                      "text": {
                        "type": "string",
                        "description": "Message text"
                      }
                    },
                    "required": [
                      "channel",
                      "text"
                    ]
                  }
                },
                "annotations": {
                  "type": "object",
                  "description": "MCP standard behavioral hints for the tool",
                  "properties": {
                    "readOnlyHint": {
                      "type": "boolean",
                      "description": "Tool does not modify any state",
                      "example": false
                    },
                    "destructiveHint": {
                      "type": "boolean",
                      "description": "Tool may perform destructive actions",
                      "example": false
                    },
                    "idempotentHint": {
                      "type": "boolean",
                      "description": "Calling with the same inputs multiple times has the same effect as calling once",
                      "example": false
                    },
                    "openWorldHint": {
                      "type": "boolean",
                      "description": "Tool interacts with external systems beyond the immediate environment",
                      "example": true
                    }
                  }
                },
                "forceApproval": {
                  "type": "string",
                  "enum": [
                    "user",
                    "admin"
                  ],
                  "nullable": true,
                  "description": "Whether this tool requires explicit approval before execution. `user` means any user must approve, `admin` means only admins can approve.",
                  "example": "user"
                },
                "policy_check": {
                  "type": "object",
                  "nullable": true,
                  "description": "Result of the most recent policy check run against this tool",
                  "properties": {
                    "severity": {
                      "type": "string",
                      "enum": [
                        "pass",
                        "warning",
                        "error"
                      ],
                      "description": "Overall severity of the policy check result",
                      "example": "pass"
                    },
                    "details": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Individual policy check messages",
                      "example": []
                    },
                    "checked_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the policy check was last run",
                      "example": "2024-01-20T14:45:00Z"
                    }
                  }
                },
                "ai_risk": {
                  "type": "object",
                  "nullable": true,
                  "description": "AI-generated risk assessment for this tool",
                  "properties": {
                    "level": {
                      "type": "string",
                      "enum": [
                        "low",
                        "medium",
                        "high",
                        "critical"
                      ],
                      "description": "Risk level assessed by the AI",
                      "example": "low"
                    },
                    "score": {
                      "type": "number",
                      "description": "Numeric risk score (0-100)",
                      "example": 12
                    },
                    "reasoning": {
                      "type": "string",
                      "description": "Explanation of the risk assessment",
                      "example": "This tool only sends messages and does not access sensitive data."
                    },
                    "calculated_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "When the AI risk assessment was calculated",
                      "example": "2024-01-20T14:45:00Z"
                    }
                  }
                }
              }
            }
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "description": "Free-form metadata stored alongside the server"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the MCP server was created"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the MCP server was last modified"
          }
        }
      },
      "CreateMcpServerRequest": {
        "type": "object",
        "required": [
          "name",
          "mcp_proxy"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the MCP server",
            "example": "My Custom Server",
            "minLength": 1
          },
          "mcp_proxy": {
            "type": "string",
            "description": "JSON string containing the MCP server configuration.\nMust be valid JSON with `type` and `url` fields.\n",
            "example": "{\"type\":\"http\",\"url\":\"https://my-mcp-server.example.com\"}"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the server. If not provided, will be generated from the name.\nMust be lowercase alphanumeric with hyphens only. No leading or trailing hyphens allowed.\n",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "example": "my-custom-server"
          },
          "logo_url": {
            "type": "string",
            "description": "URL to the server's logo image",
            "example": "https://example.com/logo.png"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the MCP server",
            "example": "Custom MCP server for internal tools"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "default": "active",
            "description": "Server visibility status.\n- `active`: Visible to users in the integrations catalog\n- `draft`: Hidden from users, only visible to admins\n"
          },
          "request_settings": {
            "$ref": "#/components/schemas/RequestSettings"
          },
          "auth_settings": {
            "$ref": "#/components/schemas/AuthSettings"
          }
        }
      },
      "UpdateMcpServerRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the MCP server",
            "minLength": 1
          },
          "mcp_proxy": {
            "type": "string",
            "description": "JSON string containing the MCP server configuration"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          },
          "logo_url": {
            "type": "string",
            "description": "URL to the server's logo image"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ]
          },
          "disabled": {
            "type": "boolean",
            "description": "When true the MCP is temporarily turned off: it serves no tools and is hidden from clients, but keeps its status (draft/active)."
          },
          "request_settings": {
            "$ref": "#/components/schemas/RequestSettings"
          },
          "auth_settings": {
            "$ref": "#/components/schemas/AuthSettings"
          }
        }
      },
      "CreateMcpServerResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "slug": {
                "type": "string",
                "description": "The unique slug assigned to the created MCP server",
                "example": "my-custom-server"
              }
            }
          }
        }
      },
      "RequestSettings": {
        "type": "object",
        "description": "Advanced request configuration for the MCP server",
        "properties": {
          "headers": {
            "type": "array",
            "description": "Custom headers to include in requests to the MCP server",
            "items": {
              "$ref": "#/components/schemas/Header"
            }
          },
          "settings": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Additional key-value settings"
          },
          "proxySettings": {
            "$ref": "#/components/schemas/ProxySettings"
          }
        }
      },
      "Header": {
        "type": "object",
        "required": [
          "key",
          "value"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "Header name",
            "example": "X-Custom-Header"
          },
          "value": {
            "type": "string",
            "description": "Header value",
            "example": "custom-value"
          }
        }
      },
      "ProxySettings": {
        "type": "object",
        "description": "Settings for MCP proxy behavior",
        "properties": {
          "disableTools": {
            "type": "boolean",
            "default": false,
            "description": "Disable tool functionality for this server"
          },
          "disableResources": {
            "type": "boolean",
            "default": false,
            "description": "Disable resource functionality for this server"
          },
          "disablePrompts": {
            "type": "boolean",
            "default": false,
            "description": "Disable prompt functionality for this server"
          },
          "autoSyncTools": {
            "type": "boolean",
            "default": true,
            "description": "Automatically sync available tools from the server"
          },
          "localMcp": {
            "type": "boolean",
            "default": false,
            "description": "Whether this is a local MCP server"
          }
        }
      },
      "AuthSettings": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/ProxyOauthSettings"
          },
          {
            "$ref": "#/components/schemas/ProxyPassthroughSettings"
          },
          {
            "$ref": "#/components/schemas/ProxyApiKeySettings"
          },
          {
            "$ref": "#/components/schemas/NoneAuthSettings"
          }
        ],
        "discriminator": {
          "propertyName": "authType",
          "mapping": {
            "proxy-oauth": "#/components/schemas/ProxyOauthSettings",
            "proxy-passthrough": "#/components/schemas/ProxyPassthroughSettings",
            "proxy-api-key": "#/components/schemas/ProxyApiKeySettings",
            "none": "#/components/schemas/NoneAuthSettings"
          }
        }
      },
      "ProxyOauthSettings": {
        "type": "object",
        "description": "OAuth 2.0 authentication configuration",
        "required": [
          "authType",
          "clientId",
          "authUrl",
          "tokenUrl",
          "client"
        ],
        "properties": {
          "authType": {
            "type": "string",
            "enum": [
              "proxy-oauth"
            ],
            "description": "Authentication type identifier"
          },
          "clientId": {
            "type": "string",
            "description": "OAuth client ID",
            "example": "your-oauth-client-id"
          },
          "authUrl": {
            "type": "string",
            "description": "OAuth authorization URL",
            "example": "https://provider.com/oauth/authorize"
          },
          "tokenUrl": {
            "type": "string",
            "description": "OAuth token exchange URL",
            "example": "https://provider.com/oauth/token"
          },
          "client": {
            "type": "object",
            "additionalProperties": true,
            "description": "Additional OAuth client configuration (e.g., scope, redirect URI)",
            "example": {
              "scope": "read write"
            }
          }
        }
      },
      "ProxyPassthroughSettings": {
        "type": "object",
        "description": "Pass through authentication from the client",
        "required": [
          "authType"
        ],
        "properties": {
          "authType": {
            "type": "string",
            "enum": [
              "proxy-passthrough"
            ],
            "description": "Authentication type identifier"
          }
        }
      },
      "ProxyApiKeySettings": {
        "type": "object",
        "description": "API key authentication configuration",
        "required": [
          "authType"
        ],
        "properties": {
          "authType": {
            "type": "string",
            "enum": [
              "proxy-api-key"
            ],
            "description": "Authentication type identifier"
          },
          "howtoMarkdown": {
            "type": "string",
            "description": "Markdown instructions for users on how to obtain their API key",
            "example": "Visit [Settings](https://example.com/settings) to generate your API key."
          }
        }
      },
      "NoneAuthSettings": {
        "type": "object",
        "description": "No authentication required",
        "required": [
          "authType"
        ],
        "properties": {
          "authType": {
            "type": "string",
            "enum": [
              "none"
            ],
            "description": "Authentication type identifier"
          }
        }
      },
      "Group": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique group identifier",
            "example": "grp_abc123"
          },
          "name": {
            "type": "string",
            "description": "Group name",
            "example": "Engineering Team"
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "The organization this group belongs to",
            "example": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
          },
          "settings": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/GroupSettings"
              }
            ]
          },
          "owner_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of users who own this group"
          },
          "admins": {
            "type": "array",
            "description": "Users with admin capabilities scoped to this group, each with a role\nof `Owner`, `AI Champion` or `Viewer`. See\n[Group admin roles](/docs/admin/groups#group-admin-roles).\n",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "integration_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of integrations assigned to this group"
          },
          "user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of users in this group"
          },
          "toolkit_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of toolkits assigned to this group"
          },
          "skill_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of skills assigned to this group"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the group was created"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the group was last modified"
          }
        }
      },
      "GroupSettings": {
        "type": "object",
        "properties": {
          "auto_assign_users": {
            "type": "boolean",
            "description": "Automatically assign new users to this group"
          },
          "auto_assign_machine_users": {
            "type": "boolean",
            "description": "Automatically assign new machine users to this group"
          },
          "auto_assign_mcps": {
            "type": "boolean",
            "description": "Automatically assign new MCP servers to this group"
          },
          "show_draft_mcps": {
            "type": "boolean",
            "description": "Show draft MCP servers to users in this group"
          },
          "auto_assign_toolkits": {
            "type": "boolean",
            "description": "Automatically assign new toolkits to this group"
          },
          "show_draft_toolkits": {
            "type": "boolean",
            "description": "Show draft toolkits to users in this group"
          },
          "auto_assign_skills": {
            "type": "boolean",
            "description": "Automatically assign new skills to this group"
          },
          "show_draft_skills": {
            "type": "boolean",
            "description": "Show draft skills to users in this group"
          }
        }
      },
      "CreateGroupRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Group name",
            "minLength": 1,
            "example": "Engineering Team"
          },
          "settings": {
            "$ref": "#/components/schemas/GroupSettings"
          }
        }
      },
      "UpdateGroupRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Group name",
            "minLength": 1
          },
          "settings": {
            "$ref": "#/components/schemas/GroupSettings"
          }
        }
      },
      "AddIntegrationsRequest": {
        "type": "object",
        "required": [
          "slugs"
        ],
        "properties": {
          "slugs": {
            "type": "array",
            "description": "List of integration slugs to add to the group",
            "items": {
              "type": "string",
              "minLength": 1
            },
            "minItems": 1,
            "example": [
              "github",
              "slack"
            ]
          }
        }
      },
      "AddIntegrationsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean",
                "description": "Whether the operation was successful",
                "example": true
              }
            }
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "User's display name",
            "example": "John Doe"
          },
          "email": {
            "type": "string",
            "description": "User's email address",
            "example": "john.doe@example.com"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the user",
            "example": "john-doe"
          },
          "is_machine_user": {
            "type": "boolean",
            "description": "Whether this is a machine user account",
            "example": false
          },
          "group_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Array of group IDs the user belongs to",
            "example": [
              "group_123",
              "group_456"
            ]
          },
          "owner_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "For a **machine user**, the IDs of the people accountable for it.\nAlways empty for regular users, who cannot have owners.\n",
            "example": [
              "user_123"
            ]
          },
          "owned_machine_user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "For a regular user, the IDs of the machine users they own. Always\nempty for machine users.\n",
            "example": [
              "user_bot_456"
            ]
          },
          "risk_score": {
            "type": "integer",
            "nullable": true,
            "minimum": 0,
            "maximum": 100,
            "description": "Identity risk score, where a higher number means a riskier user.\n`null` means the user has never been scored, which is distinct from\na score of `0` (assessed and found low risk).\n",
            "example": 72
          },
          "risk_score_source": {
            "type": "string",
            "nullable": true,
            "enum": [
              "manual",
              "api",
              "scim",
              "crowdstrike"
            ],
            "description": "What last set `risk_score`. `manual` means an admin set it in the\ndashboard; provider syncs skip those users unless configured to\noverwrite manual scores.\n",
            "example": "crowdstrike"
          },
          "risk_score_updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When `risk_score` was last written",
            "example": "2024-01-20T03:00:00Z"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the user was created",
            "example": "2024-01-15T10:30:00Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the user was last updated",
            "example": "2024-01-20T14:45:00Z"
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          }
        }
      },
      "MachineUserCredentials": {
        "type": "object",
        "description": "One-time authentication credentials returned only when a **machine user**\nis created. The `secret` is shown once at creation time and cannot be\nretrieved again — store it securely.\n",
        "properties": {
          "client_id": {
            "type": "string",
            "description": "Client ID (the machine user's access key) used to authenticate",
            "example": "usr_ak_xxxxxxxxxxxxxxxx"
          },
          "secret": {
            "type": "string",
            "description": "One-time plaintext secret. It is never returned again — store it securely.",
            "example": "usr_sk_xxxxxxxxxxxxxxxx"
          }
        },
        "required": [
          "client_id",
          "secret"
        ]
      },
      "CreateUserRequest": {
        "type": "object",
        "required": [
          "name",
          "email"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "User's display name",
            "minLength": 1,
            "example": "John Doe"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "User's email address",
            "example": "john.doe@example.com"
          }
        }
      },
      "UpdateUserRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "User's display name",
            "minLength": 1,
            "example": "John Updated"
          },
          "owner_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The complete set of owners for a **machine user**, not a delta: any\ncurrent owner left out of the array is removed, and `[]` clears\nevery owner. Each ID must belong to a regular user in your\norganization. Rejected with `400` for a regular user.\n",
            "example": [
              "user_123",
              "user_456"
            ]
          },
          "risk_score": {
            "type": "integer",
            "nullable": true,
            "minimum": 0,
            "maximum": 100,
            "description": "Identity risk score, where a higher number means a riskier user.\nOmit the field to leave the current score untouched, or send `null`\nto clear it back to unscored.\n\nScores set through this endpoint are recorded with source `api`,\nwhich overwrites a score an admin set by hand. They take effect once\nthe **User Risk Score** beta feature is enabled.\n",
            "example": 72
          }
        }
      },
      "BulkRiskScoresRequest": {
        "type": "object",
        "required": [
          "scores"
        ],
        "properties": {
          "source": {
            "type": "string",
            "maxLength": 64,
            "description": "Label recorded on every updated user, identifying the system that\nsupplied the scores. Defaults to `api`. The value `manual` is\nreserved for dashboard edits and is rejected.\n",
            "example": "crowdstrike"
          },
          "overwrite_manual": {
            "type": "boolean",
            "default": false,
            "description": "Whether to replace scores an admin set by hand in the dashboard.\nDefaults to `false` so a scheduled push cannot undo a deliberate\noverride.\n"
          },
          "scores": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5000,
            "description": "Scores to apply, matched to users by email",
            "items": {
              "type": "object",
              "required": [
                "email",
                "risk_score"
              ],
              "properties": {
                "email": {
                  "type": "string",
                  "format": "email",
                  "example": "john.doe@example.com"
                },
                "risk_score": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 100,
                  "example": 72
                }
              }
            }
          }
        }
      },
      "BulkRiskScoresResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "updated": {
                "type": "integer",
                "description": "Number of users whose score was written",
                "example": 128
              },
              "skipped": {
                "type": "integer",
                "description": "Entries that matched no user in the organization, or whose\ncurrent score was set manually and left untouched.\n",
                "example": 4
              }
            }
          }
        }
      },
      "CreateMachineUserViaUsersRequest": {
        "type": "object",
        "required": [
          "is_machine_user",
          "name"
        ],
        "properties": {
          "is_machine_user": {
            "type": "boolean",
            "description": "Must be `true` to create a machine user via this endpoint",
            "enum": [
              true
            ],
            "example": true
          },
          "name": {
            "type": "string",
            "description": "Display name for the machine user",
            "minLength": 1,
            "example": "CI Bot"
          },
          "slug": {
            "type": "string",
            "description": "Optional URL-friendly identifier",
            "example": "ci-bot"
          },
          "owner_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of the users accountable for this machine user. Every ID must\nbelong to a regular user in your organization — a machine user\ncannot own another machine user. Rejected with `400` when\n`is_machine_user` is not `true`.\n",
            "example": [
              "user_123"
            ]
          },
          "client_credentials": {
            "type": "object",
            "description": "Optional OAuth2 client credentials for token-based authentication",
            "properties": {
              "clientId": {
                "type": "string",
                "description": "OAuth2 client ID",
                "minLength": 1
              },
              "clientSecret": {
                "type": "string",
                "description": "OAuth2 client secret",
                "minLength": 1
              },
              "tokenUrl": {
                "type": "string",
                "format": "uri",
                "description": "OAuth2 token endpoint URL"
              }
            },
            "required": [
              "clientId",
              "clientSecret"
            ]
          }
        }
      },
      "Toolkit": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the toolkit",
            "example": "tk_abc123"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier for the toolkit",
            "example": "my-custom-toolkit"
          },
          "name": {
            "type": "string",
            "description": "Display name for the toolkit",
            "example": "My Custom Toolkit"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the toolkit",
            "example": "Custom toolkit for internal workflows"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "description": "Toolkit visibility status",
            "example": "active"
          },
          "integration_tools": {
            "type": "object",
            "additionalProperties": true,
            "description": "Integration tools configuration"
          },
          "prompts": {
            "type": "object",
            "nullable": true,
            "description": "Prompt templates, wrapped in an `items` array. Note the asymmetry\nwith `CreateToolkitRequest`, which accepts `prompts` as a bare\narray: you write an array and read back a wrapper. `null` when the\ntoolkit has no prompts. This matches how `Skill` models `scripts`,\n`references` and `assets`.\n",
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "resources": {
            "type": "object",
            "nullable": true,
            "description": "Resource configurations, wrapped in an `items` array. Same\nwrite-array / read-wrapper asymmetry as `prompts`.\n",
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the toolkit was created",
            "example": "2024-01-15T10:30:00Z"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the toolkit was last updated",
            "example": "2024-01-20T14:45:00Z"
          },
          "descriptions": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Per-tool description overrides, keyed by tool name."
          },
          "is_org": {
            "type": "boolean",
            "description": "True when this is an organization-level record rather than user-owned.",
            "example": true
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "User who owns this record. Null for organization-level records.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          }
        }
      },
      "CreateToolkitRequest": {
        "type": "object",
        "required": [
          "name",
          "slug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the toolkit",
            "minLength": 1,
            "example": "My Toolkit"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "example": "my-toolkit"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description"
          },
          "integration_tools": {
            "type": "object",
            "additionalProperties": true,
            "description": "Integration tools configuration"
          },
          "prompts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "resources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "UpdateToolkitRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ]
          },
          "integration_tools": {
            "type": "object",
            "additionalProperties": true
          },
          "prompts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "resources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "PromoteToolkitRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the promoted toolkit"
          },
          "description": {
            "type": "string",
            "description": "Description for the promoted toolkit"
          },
          "slug": {
            "type": "string",
            "description": "New slug for the promoted toolkit",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          }
        }
      },
      "Skill": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "sk_abc123"
          },
          "slug": {
            "type": "string",
            "example": "my-skill"
          },
          "name": {
            "type": "string",
            "example": "My Skill"
          },
          "description": {
            "type": "string",
            "example": "A custom skill"
          },
          "content": {
            "type": "string",
            "description": "Skill content in Markdown format"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          },
          "metadata": {
            "type": "object",
            "nullable": true,
            "additionalProperties": {
              "type": "string"
            },
            "description": "Key-value metadata"
          },
          "allowed_tools": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "description": "List of allowed tool names"
          },
          "scripts": {
            "type": "object",
            "nullable": true,
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SkillScript"
                }
              }
            }
          },
          "references": {
            "type": "object",
            "nullable": true,
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SkillReference"
                }
              }
            }
          },
          "assets": {
            "type": "object",
            "nullable": true,
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SkillAsset"
                }
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation timestamp.",
            "example": "2026-01-15T09:30:00Z"
          },
          "identity_hash": {
            "type": "string",
            "description": "Content hash used to match this skill against discovered copies."
          },
          "is_org": {
            "type": "boolean",
            "description": "True when this is an organization-level record rather than user-owned.",
            "example": true
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "User who owns this record. Null for organization-level records.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last modification timestamp.",
            "example": "2026-01-15T09:30:00Z"
          }
        }
      },
      "SkillScript": {
        "type": "object",
        "required": [
          "path",
          "language",
          "content"
        ],
        "properties": {
          "path": {
            "type": "string"
          },
          "language": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "SkillReference": {
        "type": "object",
        "required": [
          "path",
          "content"
        ],
        "properties": {
          "path": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "SkillAsset": {
        "type": "object",
        "required": [
          "path"
        ],
        "properties": {
          "path": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "mimeType": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "CreateSkillRequest": {
        "type": "object",
        "required": [
          "name",
          "slug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "example": "My Skill"
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "example": "my-skill"
          },
          "description": {
            "type": "string"
          },
          "content": {
            "type": "string",
            "description": "Skill content in Markdown format"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "default": "draft"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "allowed_tools": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scripts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillScript"
            }
          },
          "references": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillReference"
            }
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillAsset"
            }
          }
        }
      },
      "UpdateSkillRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          },
          "description": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ]
          },
          "metadata": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "allowed_tools": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scripts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillScript"
            }
          },
          "references": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillReference"
            }
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillAsset"
            }
          }
        }
      },
      "GuardCheckConfig": {
        "type": "object",
        "description": "Check-specific configuration",
        "properties": {
          "pattern": {
            "type": "string",
            "description": "Regex pattern (for regex type)"
          },
          "replacement": {
            "type": "string",
            "description": "Replacement text for redaction (for regex type)"
          },
          "expression": {
            "type": "string",
            "description": "JSONata expression (for jsonata type)"
          },
          "prompt": {
            "type": "string",
            "description": "LLM prompt (for llm type)"
          },
          "precondition_pattern": {
            "type": "string",
            "description": "Optional regex the content must match (case-insensitive) before the LLM is called (for llm type). Content that doesn't match is skipped and scores 0."
          },
          "builtin_id": {
            "type": "string",
            "description": "Built-in check identifier (for builtin type)"
          },
          "min_confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Minimum model confidence (for the person-name-builtin check)"
          },
          "allowlist": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Spans to never report (for the person-name-builtin check)"
          }
        }
      },
      "GuardCheck": {
        "type": "object",
        "required": [
          "id",
          "type",
          "certainty"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the check",
            "example": "regex-email"
          },
          "name": {
            "type": "string",
            "description": "Display name for the check",
            "example": "Email Address"
          },
          "type": {
            "type": "string",
            "enum": [
              "builtin",
              "regex",
              "jsonata",
              "llm"
            ],
            "description": "Type of check to perform"
          },
          "certainty": {
            "type": "number",
            "description": "Certainty score (0-10) contributed when this check matches",
            "example": 10
          },
          "config": {
            "$ref": "#/components/schemas/GuardCheckConfig"
          },
          "disabled": {
            "type": "boolean",
            "description": "Whether the check is disabled"
          }
        }
      },
      "Guard": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "guard_abc123"
          },
          "slug": {
            "type": "string",
            "example": "email-detection"
          },
          "name": {
            "type": "string",
            "example": "Email Detection"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Detects email addresses in content"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GuardCheck"
            }
          },
          "threshold": {
            "type": "number",
            "description": "Score threshold that triggers the guard action",
            "example": 5
          },
          "action": {
            "type": "string",
            "enum": [
              "redact",
              "warn",
              "warn_user",
              "block"
            ],
            "description": "Action to take when threshold is exceeded. `redact` masks the matched text, `warn` allows the call but shows a warning, `warn_user` requires the user to approve the request before it proceeds, and `block` prevents the call entirely.",
            "example": "warn"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          },
          "is_default": {
            "type": "boolean",
            "description": "Whether this is a built-in default guard"
          },
          "scope": {
            "type": "string",
            "nullable": true,
            "enum": [
              "buildtime",
              "runtime"
            ],
            "description": "When the guard is evaluated"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation timestamp.",
            "example": "2026-01-15T09:30:00Z"
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "message": {
            "type": "string",
            "nullable": true,
            "description": "Message shown to the user when this guard blocks or warns a call. Absent on the built-in default guards."
          },
          "settings": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Guard-level settings.",
            "properties": {
              "sync_checks": {
                "type": "boolean",
                "description": "Whether the guard's checks are kept in sync with their source."
              },
              "redact_fallback_action": {
                "type": "string",
                "enum": [
                  "block",
                  "warn",
                  "allow"
                ],
                "description": "What a redact guard does when it triggers but nothing could be masked (for example when the match only exists inside encoded content). Defaults to `block`."
              }
            }
          },
          "sort_order": {
            "type": "integer",
            "description": "Position used when ordering guards for evaluation.",
            "example": 0
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last modification timestamp.",
            "example": "2026-01-15T09:30:00Z"
          }
        }
      },
      "CreateGuardRequest": {
        "type": "object",
        "required": [
          "name",
          "slug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "example": "Email Detection"
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "example": "email-detection"
          },
          "description": {
            "type": "string"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GuardCheck"
            }
          },
          "threshold": {
            "type": "number",
            "description": "Score threshold that triggers the action (default 5)",
            "default": 5
          },
          "action": {
            "type": "string",
            "enum": [
              "redact",
              "warn",
              "warn_user",
              "block"
            ],
            "default": "block",
            "description": "Action to take when the threshold is exceeded"
          },
          "message": {
            "type": "string",
            "description": "Message shown to the user when this guard blocks or warns a call"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "default": "draft"
          },
          "scope": {
            "type": "string",
            "enum": [
              "buildtime",
              "runtime"
            ]
          }
        }
      },
      "UpdateGuardRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          },
          "description": {
            "type": "string"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GuardCheck"
            }
          },
          "threshold": {
            "type": "number"
          },
          "action": {
            "type": "string",
            "enum": [
              "redact",
              "warn",
              "warn_user",
              "block"
            ]
          },
          "message": {
            "type": "string",
            "nullable": true,
            "description": "Message shown to the user when this guard blocks or warns a call. Set to `null` to clear it."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "buildtime",
              "runtime"
            ]
          }
        }
      },
      "Command": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cmd_abc123"
          },
          "slug": {
            "type": "string",
            "example": "summarize"
          },
          "name": {
            "type": "string",
            "example": "Summarize"
          },
          "description": {
            "type": "string",
            "example": "Summarize text content"
          },
          "output_content": {
            "type": "string",
            "description": "The command prompt template"
          },
          "arguments": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/CommandArgument"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "example": "active"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation timestamp.",
            "example": "2026-01-15T09:30:00Z"
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last modification timestamp.",
            "example": "2026-01-15T09:30:00Z"
          }
        }
      },
      "CommandArgument": {
        "type": "object",
        "required": [
          "name",
          "type"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Argument name"
          },
          "type": {
            "type": "string",
            "enum": [
              "string",
              "number",
              "boolean",
              "array",
              "object"
            ],
            "description": "Argument data type"
          },
          "description": {
            "type": "string",
            "description": "Argument description"
          },
          "required": {
            "type": "boolean",
            "default": false,
            "description": "Whether the argument is required"
          },
          "items": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "string",
                  "number",
                  "boolean",
                  "object"
                ]
              }
            },
            "description": "Array item type (when type is \"array\")"
          }
        }
      },
      "CreateCommandRequest": {
        "type": "object",
        "required": [
          "name",
          "slug",
          "output_content"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "example": "Summarize"
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "example": "summarize"
          },
          "description": {
            "type": "string"
          },
          "output_content": {
            "type": "string",
            "minLength": 1,
            "description": "The command prompt template"
          },
          "arguments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CommandArgument"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "default": "active"
          }
        }
      },
      "UpdateCommandRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          },
          "description": {
            "type": "string"
          },
          "output_content": {
            "type": "string",
            "minLength": 1
          },
          "arguments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CommandArgument"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ]
          }
        }
      },
      "PluginMcps": {
        "type": "object",
        "description": "MCP resources associated with the plugin",
        "properties": {
          "toolkit_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of toolkits included in this plugin"
          },
          "integration_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of integrations included in this plugin"
          },
          "rawMcpServers": {
            "type": "object",
            "additionalProperties": true,
            "description": "Raw MCP server configurations keyed by server name"
          }
        }
      },
      "Plugin": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier",
            "example": "plg_abc123"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier",
            "example": "my-plugin"
          },
          "name": {
            "type": "string",
            "description": "Display name",
            "example": "My Plugin"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable description. Null when the plugin was created without one — note this differs from skills, commands and toolkits, which store an empty string in the same situation.",
            "example": "A custom plugin"
          },
          "version": {
            "type": "string",
            "description": "Plugin version",
            "example": "1.0.0"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "description": "Plugin visibility status",
            "example": "active"
          },
          "author": {
            "type": "object",
            "nullable": true,
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string"
              }
            }
          },
          "homepage": {
            "type": "string",
            "nullable": true,
            "description": "Plugin homepage URL",
            "example": "https://example.com"
          },
          "repository": {
            "type": "string",
            "nullable": true,
            "description": "Plugin source repository URL",
            "example": "https://github.com/org/repo"
          },
          "keywords": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "description": "Searchable keywords"
          },
          "skill_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of skills included in this plugin"
          },
          "command_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of commands included in this plugin"
          },
          "rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of rules included in this plugin"
          },
          "hook_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of hooks included in this plugin"
          },
          "sub_agent_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of sub-agents included in this plugin"
          },
          "mcps": {
            "$ref": "#/components/schemas/PluginMcps"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          },
          "verified": {
            "type": "boolean",
            "description": "True when the plugin has been verified by the organization.",
            "example": false
          }
        }
      },
      "CreatePluginRequest": {
        "type": "object",
        "required": [
          "name",
          "slug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the plugin",
            "example": "My Plugin",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier. Must be lowercase alphanumeric with hyphens only.",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "example": "my-plugin"
          },
          "description": {
            "type": "string",
            "description": "Human-readable description",
            "example": "A custom plugin"
          },
          "version": {
            "type": "string",
            "description": "Plugin version string",
            "example": "1.0.0"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ],
            "default": "draft"
          },
          "author": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string"
              }
            }
          },
          "homepage": {
            "type": "string"
          },
          "repository": {
            "type": "string"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "skill_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of skills to include"
          },
          "command_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of commands to include"
          },
          "rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of rules to include"
          },
          "hook_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of hooks to include"
          },
          "sub_agent_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of sub-agents to include"
          },
          "mcps": {
            "$ref": "#/components/schemas/PluginMcps"
          }
        }
      },
      "UpdatePluginRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "draft"
            ]
          },
          "author": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string"
              }
            }
          },
          "homepage": {
            "type": "string"
          },
          "repository": {
            "type": "string"
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "skill_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "command_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rule_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hook_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sub_agent_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "mcps": {
            "$ref": "#/components/schemas/PluginMcps"
          }
        }
      },
      "SyncPluginsRequest": {
        "type": "object",
        "description": "All fields optional. An empty body syncs every configured source repo\nand waits for the results.\n",
        "properties": {
          "repo": {
            "type": "string",
            "minLength": 1,
            "description": "Restrict the sync to a single configured source repo, in\n`owner/repo` form. Omit to sync every configured repo.\n",
            "example": "my-org/my-plugins"
          },
          "background": {
            "type": "boolean",
            "default": false,
            "description": "When `true`, return `202` immediately and continue the sync\nserver-side. Use for orgs with many repos where a synchronous call\ncould exceed the client's request timeout.\n"
          }
        }
      },
      "PluginSyncOutcome": {
        "type": "object",
        "description": "Result of syncing a single source repo.",
        "properties": {
          "repo": {
            "type": "string",
            "description": "The source repo, in `owner/repo` form",
            "example": "my-org/my-plugins"
          },
          "status": {
            "type": "string",
            "enum": [
              "success",
              "partial",
              "error"
            ],
            "description": "`success` — all discovered plugins imported. `partial` — some\nplugins failed while others succeeded. `error` — the repo could not\nbe synced (see `error`).\n",
            "example": "success"
          },
          "imported": {
            "type": "integer",
            "description": "Number of plugins imported from the repo",
            "example": 4
          },
          "skipped": {
            "type": "integer",
            "description": "Plugins that had nothing importable (e.g. a standalone MCP server\nentry with no plugin content).\n",
            "example": 0
          },
          "failed": {
            "type": "integer",
            "description": "Number of plugins that failed to import",
            "example": 0
          },
          "error": {
            "type": "string",
            "description": "Present only when `status` is `error` or `partial`.",
            "example": "1 of 3 plugin(s) failed to sync"
          }
        }
      },
      "PluginSyncResult": {
        "type": "object",
        "properties": {
          "syncedAny": {
            "type": "boolean",
            "description": "True if at least one plugin was imported across all repos. When\ntrue, Willow republishes the org's marketplace targets.\n",
            "example": true
          },
          "outcomes": {
            "type": "array",
            "description": "One entry per source repo that was processed.",
            "items": {
              "$ref": "#/components/schemas/PluginSyncOutcome"
            }
          }
        }
      },
      "BackgroundAgent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier of the agent",
            "example": "agent_abc123"
          },
          "name": {
            "type": "string",
            "description": "Display name of the agent",
            "example": "Support Triage Agent"
          },
          "slug": {
            "type": "string",
            "description": "URL-safe identifier, unique within the organization",
            "example": "support-triage-agent"
          },
          "description": {
            "type": "string",
            "description": "What the agent does"
          },
          "icon": {
            "type": "string",
            "nullable": true,
            "description": "Icon identifier shown in the dashboard"
          },
          "access_key": {
            "type": "string",
            "description": "Gateway access key. The agent authenticates with `Bearer <access_key>:<secret>`.",
            "example": "ba_x1y2z3..."
          },
          "owner_ids": {
            "type": "array",
            "description": "User IDs that own this agent",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ],
            "description": "Disabled agents cannot call tools or receive messages"
          },
          "capabilities": {
            "$ref": "#/components/schemas/AgentCapabilities"
          },
          "platform": {
            "type": "string",
            "enum": [
              "custom",
              "custom-managed",
              "willow-agents",
              "claude-managed-agents",
              "claude-tag",
              "aws-agentcore",
              "cursor-agents",
              "kagent",
              "snowflake-cortex-agents",
              "codex",
              "langgraph"
            ],
            "description": "The external platform the agent runs on"
          },
          "platform_config": {
            "type": "object",
            "additionalProperties": true,
            "description": "Platform-specific settings (e.g. `model`, `system_prompt` for Willow Agents and Claude Managed Agents; `model_id` for AWS AgentCore)"
          },
          "sync_state": {
            "$ref": "#/components/schemas/AgentSyncState"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "org_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization this record belongs to.",
            "example": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
          }
        }
      },
      "AgentCapabilities": {
        "type": "object",
        "description": "The tools, skills, and rules the agent is allowed to use",
        "properties": {
          "tools": {
            "type": "array",
            "description": "Gateway tools exposed to the agent",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "id": {
                  "type": "string"
                },
                "integration_slug": {
                  "type": "string"
                },
                "tool_slug": {
                  "type": "string"
                },
                "tool_name": {
                  "type": "string"
                },
                "enabled": {
                  "type": "boolean"
                }
              }
            }
          },
          "skills": {
            "type": "array",
            "description": "Skills attached to the agent",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "id": {
                  "type": "string"
                },
                "skill_id": {
                  "type": "string"
                },
                "skill_slug": {
                  "type": "string"
                },
                "enabled": {
                  "type": "boolean"
                }
              }
            }
          },
          "rules": {
            "type": "array",
            "description": "Rules attached to the agent",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "id": {
                  "type": "string"
                },
                "rule_id": {
                  "type": "string"
                },
                "rule_slug": {
                  "type": "string"
                },
                "enabled": {
                  "type": "boolean"
                }
              }
            }
          },
          "integration_auth": {
            "type": "array",
            "description": "Per-integration connected-auth configuration",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "properties": {
                "integration_slug": {
                  "type": "string"
                },
                "use_connected_auth": {
                  "type": "boolean"
                },
                "auth_user_email": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "AgentSyncState": {
        "type": "object",
        "nullable": true,
        "description": "Result of the last sync with the external agent platform",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "synced",
              "error"
            ]
          },
          "external_agent_id": {
            "type": "string",
            "description": "The agent's ID on the external platform"
          },
          "external_agent_version": {
            "type": "integer"
          },
          "credential_id": {
            "type": "string",
            "description": "Identifier of the stored credential record created by the sync.",
            "example": "vcrd_01ABCDEfghijKLMNopqrSTUv"
          },
          "vault_id": {
            "type": "string",
            "description": "Identifier of the secret-store entry backing the agent credential.",
            "example": "vlt_01ABCDEfghijKLMNopqrSTUv"
          },
          "external_agent_arn": {
            "type": "string",
            "description": "Full resource ARN (AWS AgentCore harness)"
          },
          "mcp_server_url": {
            "type": "string",
            "description": "The gateway MCP URL stored on the platform"
          },
          "last_synced_at": {
            "type": "string",
            "format": "date-time"
          },
          "error": {
            "type": "string",
            "description": "Error message from the last failed sync"
          }
        }
      },
      "AgentSession": {
        "type": "object",
        "description": "A conversation session on the agent's external platform",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platform session ID",
            "example": "session_xyz789"
          },
          "status": {
            "type": "string",
            "description": "Session status (e.g. idle, running, terminated)"
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "archived_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "session_key": {
            "type": "string",
            "nullable": true,
            "description": "Local correlation key (e.g. ticket ID) when the session was created via invoke or a webhook"
          },
          "last_event_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "AgentSessionEvent": {
        "type": "object",
        "additionalProperties": true,
        "description": "A single event from a session's conversation log",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "Event type (e.g. message, agent.tool_use, tool_result)"
          },
          "processed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "content": {
            "type": "array",
            "description": "Content blocks for message events",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "name": {
            "type": "string",
            "description": "Tool name for tool_use events"
          },
          "input": {
            "type": "object",
            "additionalProperties": true,
            "description": "Tool input for tool_use events"
          },
          "is_error": {
            "type": "boolean",
            "description": "Whether a tool_result event represents an error"
          }
        }
      },
      "CreateBackgroundAgentRequest": {
        "type": "object",
        "required": [
          "name",
          "slug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "Display name of the agent",
            "example": "Support Triage Agent"
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "description": "URL-safe identifier, unique within the organization",
            "example": "support-triage-agent"
          },
          "description": {
            "type": "string",
            "description": "What the agent does"
          },
          "owner_ids": {
            "type": "array",
            "description": "User IDs that own this agent",
            "items": {
              "type": "string"
            }
          },
          "platform": {
            "type": "string",
            "enum": [
              "custom",
              "custom-managed",
              "willow-agents",
              "claude-managed-agents",
              "claude-tag",
              "aws-agentcore",
              "cursor-agents",
              "kagent",
              "snowflake-cortex-agents",
              "codex",
              "langgraph"
            ],
            "default": "custom",
            "description": "The external platform the agent runs on"
          },
          "platform_config": {
            "type": "object",
            "additionalProperties": true,
            "description": "Platform-specific settings"
          },
          "connect": {
            "type": "object",
            "description": "Optionally set up the agent's connected account in the same call. The listed MCP servers are configured to run as `user_email`'s connected account, and the response carries an `auth_urls` entry per MCP server — the link that user opens to connect it.\n",
            "required": [
              "integrations",
              "user_email"
            ],
            "properties": {
              "integrations": {
                "type": "array",
                "minItems": 1,
                "description": "Slugs of the MCP servers to connect",
                "items": {
                  "type": "string"
                },
                "example": [
                  "github",
                  "jira"
                ]
              },
              "user_email": {
                "type": "string",
                "description": "Email of the org member whose account the agent runs as. Must already exist in the organization.",
                "example": "bot-github@acme.com"
              }
            }
          }
        }
      },
      "AgentAuthUrl": {
        "type": "object",
        "properties": {
          "integration": {
            "type": "string",
            "description": "Slug of the MCP server the link connects",
            "example": "github"
          },
          "user_email": {
            "type": "string",
            "description": "The account the connection is stored against",
            "example": "bot-github@acme.com"
          },
          "url": {
            "type": "string",
            "description": "Link that starts the OAuth flow for that account",
            "example": "https://acme.withwillow.ai/acme/api/auth/init?state=..."
          }
        }
      },
      "UpdateBackgroundAgentRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          },
          "description": {
            "type": "string"
          },
          "icon": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ]
          },
          "owner_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "capabilities": {
            "$ref": "#/components/schemas/AgentCapabilities"
          },
          "platform": {
            "type": "string",
            "enum": [
              "custom",
              "custom-managed",
              "willow-agents",
              "claude-managed-agents",
              "claude-tag",
              "aws-agentcore",
              "cursor-agents",
              "kagent",
              "snowflake-cortex-agents",
              "codex",
              "langgraph"
            ]
          },
          "platform_config": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "InvokeBackgroundAgentRequest": {
        "type": "object",
        "required": [
          "session_key",
          "message"
        ],
        "properties": {
          "session_key": {
            "type": "string",
            "maxLength": 512,
            "description": "Stable correlation key for the conversation (e.g. a ticket ID). Reusing a key resumes the existing session.",
            "example": "ticket-4821"
          },
          "message": {
            "type": "string",
            "description": "The message to send to the agent",
            "example": "A new ticket was opened. Please investigate."
          }
        }
      }
    }
  }
}
