swagger: '2.0'
info:
  title: SmartSaaS API
  version: 1.0.0
  x-logo:
    url: ./smartsaas-logo-complete.svg
  description: >
    ## Agent & Tool API


    This API enables **AI agents and automation tools** (e.g. OpenClaw, MCP
    servers, custom integrations) to **act on behalf of SmartSaaS users**.
    Agents use an API key scoped to a user/company to read and write data,
    manage projects, store research, and push real-time updates—all without
    requiring the user to be logged in.


    ### Use cases

    - **OpenClaw & MCP-style tools**: Agents that assist users by creating
    datasets, adding knowledge, managing projects, and streaming responses to
    the user's messaging UI.

    - **Research assistants**: Store findings via `/research`; results appear in
    the user's knowledge base.

    - **Project automation**: Create projects, work packages, and tasks; update
    task status.

    - **Real-time feedback**: Use the **OpenClaw webhook** to push messages and
    task progress to the user's app in real time.


    ### Authentication

    All routes require API key authentication. Send the key in the
    `Authorization` header as `Bearer <api-key>` or as the raw key. The API key
    is bound to a user/company; requests operate in that context.


    ### Permissions

    Keys are scoped by permission: `users:read`, `data:read`, `data:write`,
    `knowledge:read`, `knowledge:write`, `business_plans:read`,
    `business_plans:write`, `projects:read`, `projects:write`, `sales:read`,
    `sales:write`, `templates:read`, `templates:write`, plus `analytics:read`,
    `integrations:*`, `organiser:*`, `company:*`, `admin:*` as configured.
    Configure permissions when creating keys in SmartSaaS.


    ### Tool mapping (MCP / OpenClaw)

    | Capability | Endpoint | Use case |

    |------------|----------|----------|

    | List users | `GET /protected/users` | Resolve recipients, team context |

    | Push message | `POST /protected/openclaw/webhook` | Stream replies to
    user's UI |

    | Task progress | `POST /protected/openclaw/webhook` | Update Agent Tasks
    board |

    | List/create datasets | `GET/POST /protected/data/folders` | Store agent
    outputs |

    | Add data rows | `POST /protected/data/folders/{id}/items` | Append
    scraped/processed data |

    | List/add knowledge | `GET/POST /protected/knowledge` | RAG, store findings
    |

    | Post research | `POST /protected/research` | Save research as knowledge |

    | Manage business plans | `GET/POST/DELETE /protected/business-plans` |
    Create/retrieve plans |

    | Manage projects | `GET/POST /protected/projects`, work-packages, tasks |
    Create tasks, update status |

    | Project detail & completed | `GET /protected/projects/{id}/detail`, `GET
    /protected/projects/completed/list` | Full project payload, completed list |

    | Sales campaigns & CRM | `GET/POST /protected/sales/campaigns`, CRM,
    funnel, forecasts | Campaigns, leads, analytics |

    | Templates | `GET/POST /protected/templates/*` | Email, document, webpage,
    invoice, media |
  host: https://smartsaas.co.uk/documentation/api
  basepath: /api
  termsOfService: https://smartsaas.co.uk/terms-and-conditions
  contact:
    email: admin@smartsaas.co.uk
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
servers:
  - url: https://smartsaas.co.uk/documentation/api
    description: Production
  - url: http://localhost:19006
    description: Local development
tags:
  - name: Users
    description: List users in the company. Use to resolve recipients or show team context.
  - name: Real-time
    description: >-
      Push messages and task updates to the user's app (webhook for
      OpenClaw/agents).
  - name: Data
    description: >-
      Datasets and folders. Create, list, add items; use for storing agent
      outputs.
  - name: Knowledge
    description: >-
      Knowledge base and research. Store findings, articles; use for RAG or
      context.
  - name: Business Plans
    description: Business plans. Create, list, retrieve, delete.
  - name: Projects
    description: >-
      Projects, work packages, tasks, team. Full project management on behalf of
      users.
  - name: Sales
    description: >-
      Campaigns, CRM folders, sales stats, funnel, forecasts. Permissions
      sales:read, sales:write.
  - name: Templates
    description: >-
      Email, invoice, document, webpage templates and media. Permissions
      templates:read, templates:write.
securityDefinitions:
  ApiKeyAuth:
    type: apiKey
    name: Authorization
    in: header
    description: >-
      API key for protected routes. Send as 'Bearer <api-key>' or '<api-key>' in
      the Authorization header. Scoped by permissions including users:read,
      data:read, data:write, knowledge:read, knowledge:write,
      business_plans:read, business_plans:write, projects:read, projects:write,
      sales:read, sales:write, templates:read, templates:write.
paths:
  /api/protected/users:
    get:
      summary: List users
      description: >
        List users in the authenticated company. Use to resolve who to act for,
        find team members, or show context in agent responses.

        **Permission**: `users:read`
      operationId: get-protected-users
      tags:
        - Users
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
        '429':
          description: Rate limit exceeded
  /api/protected/openclaw/webhook:
    post:
      summary: Agent webhook (real-time push)
      description: >
        Push messages and task progress to the user's app in real time. Used by
        OpenClaw, MCP servers, and other agents to stream responses and task
        updates to the user's messaging UI.


        - **Messages**: Send `message`, `chunk` (streaming), `messageId`,
        `conversationId`, `done`.

        - **Task tracing**: Send `taskId`, `status` (started | in_progress |
        done), `summary` to create/update Agent Tasks visible on the user's
        board.

        - Events are emitted to the user's socket room; the Resolver app
        receives `openclaw:message` and `agent-task-update` events.

        **Permission**: API key only (no extra permission).
      operationId: post-protected-openclaw-webhook
      tags:
        - Real-time
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                message:
                  type: string
                  description: Full message text
                chunk:
                  type: string
                  description: Streaming chunk
                messageId:
                  type: string
                conversationId:
                  type: string
                  default: openclaw
                done:
                  type: boolean
                  default: false
                taskId:
                  type: string
                  description: For task tracing
                status:
                  type: string
                  enum:
                    - started
                    - in_progress
                    - done
                summary:
                  type: string
                  description: Task summary for Agent Tasks board
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '503':
          description: Socket server unavailable
  /api/protected/data/folders:
    get:
      summary: List data folders
      description: >
        List datasets/folders for the user. Use to find where to store agent
        outputs or to browse existing data.

        **Permission**: `data:read`
      operationId: get-protected-data-folders
      tags:
        - Data
      security:
        - ApiKeyAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 10
        - name: sortBy
          in: query
          schema:
            type: string
            default: updatedAt
        - name: sortOrder
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create data folder
      description: >
        Create a dataset/folder. Use to store structured outputs (e.g. CSV,
        tables) from agent work. Body: title/name/dataTitle, dataTags,
        dataSchema, company, parentId.

        **Permission**: `data:write`
      operationId: post-protected-data-folders
      tags:
        - Data
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                name:
                  type: string
                dataTitle:
                  type: string
                parentId:
                  type: string
                dataTags:
                  type: array
                  items:
                    type: string
                dataSchema:
                  type: array
                company:
                  type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/data/folders/{folderId}:
    get:
      summary: Get data folder by ID
      description: Retrieve a dataset by ID. **Permission** `data:read`
      operationId: get-protected-data-folder
      tags:
        - Data
      security:
        - ApiKeyAuth: []
      parameters:
        - name: folderId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/data/folders/{folderId}/items:
    post:
      summary: Add item to data folder
      description: >
        Add a row/item to a dataset. Use to append agent-generated data (e.g.
        scraped records, analysis results).

        **Permission**: `data:write`
      operationId: post-protected-data-folder-items
      tags:
        - Data
      security:
        - ApiKeyAuth: []
      parameters:
        - name: folderId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/data/folders/{folderId}/content:
    get:
      summary: Get data folder content
      description: >-
        Retrieve items in a dataset. Use for RAG or to process existing data.
        **Permission** `data:read`
      operationId: get-protected-data-folder-content
      tags:
        - Data
      security:
        - ApiKeyAuth: []
      parameters:
        - name: folderId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/knowledge:
    get:
      summary: List knowledge articles
      description: >-
        List knowledge base articles. Use for RAG or to find existing context.
        **Permission** `knowledge:read`
      operationId: get-protected-knowledge
      tags:
        - Knowledge
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create knowledge article
      description: >
        Add a knowledge article. Use to store agent-generated docs, summaries,
        or reference material for the user.

        **Permission**: `knowledge:write`
      operationId: post-protected-knowledge
      tags:
        - Knowledge
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                content:
                  type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/knowledge/{id}:
    get:
      summary: Get knowledge article by ID
      description: Retrieve a knowledge article. **Permission** `knowledge:read`
      operationId: get-protected-knowledge-by-id
      tags:
        - Knowledge
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/research:
    post:
      summary: Post research (stored as knowledge)
      description: >
        Submit research findings; stored as a knowledge article. Use for
        research agents to save findings (title, findings/content/summary,
        source, url, sources).

        **Permission**: `knowledge:write`
      operationId: post-protected-research
      tags:
        - Knowledge
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                findings:
                  type: string
                content:
                  type: string
                summary:
                  type: string
                source:
                  type: string
                url:
                  type: string
                sources:
                  type: array
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/business-plans:
    get:
      summary: List business plans
      description: List business plans for the user. **Permission** `business_plans:read`
      operationId: get-protected-business-plans
      tags:
        - Business Plans
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create business plan
      description: >-
        Create a business plan on behalf of the user. **Permission**
        `business_plans:write`
      operationId: post-protected-business-plans
      tags:
        - Business Plans
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/business-plans/{planId}:
    get:
      summary: Get business plan by ID
      description: Retrieve a business plan. **Permission** `business_plans:read`
      operationId: get-protected-business-plan
      tags:
        - Business Plans
      security:
        - ApiKeyAuth: []
      parameters:
        - name: planId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    delete:
      summary: Delete business plan
      description: Delete a business plan. **Permission** `business_plans:write`
      operationId: delete-protected-business-plan
      tags:
        - Business Plans
      security:
        - ApiKeyAuth: []
      parameters:
        - name: planId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects:
    get:
      summary: List projects
      description: >-
        List projects for the user. Use to find where to add tasks or work
        packages. **Permission** `projects:read`
      operationId: get-protected-projects
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create project
      description: >
        Create a project on behalf of the user. Body: title, description, tags,
        status, start_date, end_date.

        **Permission**: `projects:write`
      operationId: post-protected-projects
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                description:
                  type: string
                tags:
                  type: array
                status:
                  type: string
                start_date:
                  type: string
                end_date:
                  type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects/{projectId}/work-packages:
    post:
      summary: Create work package
      description: Add a work package to a project. **Permission** `projects:write`
      operationId: post-protected-work-packages
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects/{projectId}/work-packages/{wpId}/tasks:
    post:
      summary: Create task
      description: >-
        Add a task to a work package. Use for task automation or agent-created
        todos. **Permission** `projects:write`
      operationId: post-protected-tasks
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: wpId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects/{projectId}/tasks/{taskId}:
    patch:
      summary: Modify task
      description: >-
        Update task fields (e.g. status, title). Use for progress updates.
        **Permission** `projects:write`
      operationId: patch-protected-task
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
        - name: taskId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects/{projectId}/team:
    post:
      summary: Add team member
      description: >-
        Add team member(s) to a project. Request body accepts teamMember or
        teamMembers array. Permission projects:write
      operationId: post-protected-team
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects/{projectId}/detail:
    get:
      summary: Get full project
      description: >-
        Load one project with populated relations. **Permission**
        `projects:read`
      operationId: get-protected-project-detail
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters:
        - name: projectId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects/completed/list:
    get:
      summary: List completed projects
      description: >-
        Completed projects for the user/company context. **Permission**
        `projects:read`
      operationId: get-protected-projects-completed
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/projects/templates/{companyId}:
    get:
      summary: Project templates placeholder
      description: >-
        Reserved for project templates; may return empty array. **Permission**
        `projects:read`
      operationId: get-protected-project-templates
      tags:
        - Projects
      security:
        - ApiKeyAuth: []
      parameters:
        - name: companyId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/campaigns:
    get:
      summary: List active campaigns
      description: '**Permission** `sales:read`'
      operationId: get-protected-sales-campaigns
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create campaign
      description: >-
        Body matches `POST /api/sales/create-campaign` (`campaign`, optional
        `id`). **Permission** `sales:write`
      operationId: post-protected-sales-campaigns
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/campaigns/expired:
    post:
      summary: List expired campaigns
      description: >-
        Optional body `id` (defaults to company/user from key). **Permission**
        `sales:read`
      operationId: post-protected-sales-campaigns-expired
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/campaigns/count:
    get:
      summary: Campaign count
      description: '**Permission** `sales:read`'
      operationId: get-protected-sales-campaigns-count
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/campaigns/lookup:
    post:
      summary: Get campaign by id
      description: >-
        Body includes `campaignId`, optional pagination (`page`, `limit`,
        `stageIndex`). **Permission** `sales:read`
      operationId: post-protected-sales-campaigns-lookup
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - campaignId
              properties:
                campaignId:
                  type: string
                page:
                  type: integer
                limit:
                  type: integer
                stageIndex:
                  type: integer
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/campaigns/update:
    post:
      summary: Update campaign
      description: Same as `POST /api/sales/update-campaign`. **Permission** `sales:write`
      operationId: post-protected-sales-campaigns-update
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/campaigns/delete:
    post:
      summary: Delete campaign
      description: Same as `POST /api/sales/delete-campaign`. **Permission** `sales:write`
      operationId: post-protected-sales-campaigns-delete
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/campaigns/schedule/start:
    post:
      summary: Start scheduled campaign
      description: >-
        Same as `POST /api/campaigns/schedule/start-campaign`. **Permission**
        `sales:write`
      operationId: post-protected-sales-campaigns-schedule-start
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/crm/count:
    get:
      summary: CRM item count
      description: '**Permission** `sales:read`'
      operationId: get-protected-sales-crm-count
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/crm/folders:
    post:
      summary: List CRM data folders
      description: >-
        Optional body `id` (defaults to company/user). **Permission**
        `sales:read`
      operationId: post-protected-sales-crm-folders
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/crm/clients:
    post:
      summary: List CRM clients in a dataset
      description: >-
        Body **must** include `id` (data folder ObjectId). **Permission**
        `sales:read`
      operationId: post-protected-sales-crm-clients
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - id
              properties:
                id:
                  type: string
                  description: CRM data folder id
      responses:
        '200':
          description: Success
        '400':
          description: Missing id
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/stats:
    post:
      summary: Sales stats
      description: >-
        Optional `companyId` in body (defaults from key). **Permission**
        `sales:read`
      operationId: post-protected-sales-stats
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/analytics:
    get:
      summary: Unified sales analytics
      description: >-
        Query params align with `GET /api/sales/analytics` (e.g. `startDate`,
        `endDate`, `filterType`, `forecastId`, `dataItemIds`). **Permission**
        `sales:read`
      operationId: get-protected-sales-analytics
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters:
        - name: startDate
          in: query
          required: false
          type: string
        - name: endDate
          in: query
          required: false
          type: string
        - name: filterType
          in: query
          required: false
          type: string
          enum:
            - day
            - week
            - month
        - name: forecastId
          in: query
          required: false
          type: string
        - name: dataItemIds
          in: query
          required: false
          type: string
          description: Comma-separated Mongo ids
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/leads:
    post:
      summary: Create lead
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-leads
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/leads/update:
    post:
      summary: Update lead
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-leads-update
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/leads/delete:
    post:
      summary: Delete lead
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-leads-delete
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/move-lead:
    post:
      summary: Funnel move lead
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-move-lead
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/update-lead:
    post:
      summary: Funnel update lead data
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-update-lead
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/remove-lead:
    delete:
      summary: Funnel remove lead from campaign
      description: '**Permission** `sales:write`'
      operationId: delete-protected-sales-funnel-remove-lead
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/add-lead:
    post:
      summary: Funnel add lead
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-add-lead
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/update-stage:
    post:
      summary: Funnel update stage
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-update-stage
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/add-stage:
    post:
      summary: Funnel add stage
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-add-stage
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/remove-stage:
    delete:
      summary: Funnel remove stage
      description: '**Permission** `sales:write`'
      operationId: delete-protected-sales-funnel-remove-stage
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/analytics:
    post:
      summary: Funnel analytics
      description: '**Permission** `sales:read`'
      operationId: post-protected-sales-funnel-analytics
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/lead-history:
    post:
      summary: Funnel lead history
      description: '**Permission** `sales:read`'
      operationId: post-protected-sales-funnel-lead-history
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/bulk-move-leads:
    post:
      summary: Funnel bulk move leads
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-bulk-move-leads
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/export:
    post:
      summary: Funnel export
      description: '**Permission** `sales:read`'
      operationId: post-protected-sales-funnel-export
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/import-leads:
    post:
      summary: Funnel import leads
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-import-leads
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/funnel/update-settings:
    post:
      summary: Funnel update campaign settings
      description: '**Permission** `sales:write`'
      operationId: post-protected-sales-funnel-update-settings
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/forecasts:
    get:
      summary: List forecasts
      description: '**Permission** `sales:read`'
      operationId: get-protected-sales-forecasts
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Save forecast
      description: >-
        Body matches forecast controller (`products`, `name`, optional
        `forecastId`, etc.). **Permission** `sales:write`
      operationId: post-protected-sales-forecasts
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/sales/forecasts/{forecastId}:
    get:
      summary: Get forecast by id
      description: '**Permission** `sales:read`'
      operationId: get-protected-sales-forecast-by-id
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters:
        - name: forecastId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    delete:
      summary: Delete forecast
      description: '**Permission** `sales:write`'
      operationId: delete-protected-sales-forecast
      tags:
        - Sales
      security:
        - ApiKeyAuth: []
      parameters:
        - name: forecastId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates:
    get:
      summary: Combined template picker list
      description: >-
        Email, invoice, document templates for UI picker. **Permission**
        `templates:read`
      operationId: get-protected-templates
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/count:
    get:
      summary: Template counts
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-count
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/brand-assets:
    get:
      summary: Company brand assets
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-brand-assets
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/email:
    get:
      summary: List email templates
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-email
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create email template
      description: >-
        Same payload as `POST /api/templates/post-email-template`.
        **Permission** `templates:write`
      operationId: post-protected-templates-email
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/email/defaults:
    get:
      summary: Default email templates
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-email-defaults
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/email/{id}:
    get:
      summary: Get single email template
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-email-by-id
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    delete:
      summary: Delete email template
      description: '**Permission** `templates:write`'
      operationId: delete-protected-templates-email
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/email/update:
    post:
      summary: Update email template
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-email-update
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/email/make-global:
    post:
      summary: Make email template global
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-email-make-global
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/email/duplicate:
    post:
      summary: Duplicate email template
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-email-duplicate
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/email/duplicate-child:
    post:
      summary: Duplicate child email template
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-email-duplicate-child
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/save-copy:
    post:
      summary: Save template copy
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-save-copy
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/invoice:
    get:
      summary: List invoice templates
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-invoice
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create invoice template
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-invoice
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/invoice/schema:
    get:
      summary: Invoice template schema
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-invoice-schema
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/documents/legacy:
    get:
      summary: List legacy document records
      description: >-
        Legacy `documents` collection (excludes heavy content). **Permission**
        `templates:read`
      operationId: get-protected-templates-documents-legacy
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create legacy document template
      description: >-
        Same as `POST /api/templates/documents/post-template`. **Permission**
        `templates:write`
      operationId: post-protected-templates-documents-legacy
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/documents:
    get:
      summary: List document templates (schema model)
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-documents
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create document template
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-documents
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    patch:
      summary: Patch document template
      description: '**Permission** `templates:write`'
      operationId: patch-protected-templates-documents
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/documents/delete:
    post:
      summary: Delete document template
      description: Body includes `documentId`. **Permission** `templates:write`
      operationId: post-protected-templates-documents-delete
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/documents/sign:
    post:
      summary: Sign document
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-documents-sign
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/documents/audit:
    post:
      summary: Record document audit events
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-documents-audit
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/webpages:
    get:
      summary: List webpage templates
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-webpages
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    post:
      summary: Create webpage template
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-webpages
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/webpages/{id}:
    get:
      summary: Get webpage template
      description: '**Permission** `templates:read`'
      operationId: get-protected-templates-webpage-by-id
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    patch:
      summary: Patch webpage template
      description: >-
        Merges path `id` into body `_id` if omitted. **Permission**
        `templates:write`
      operationId: patch-protected-templates-webpage
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
    delete:
      summary: Delete webpage template
      description: '**Permission** `templates:write`'
      operationId: delete-protected-templates-webpage
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/webpages/update:
    post:
      summary: Update webpage template (body _id)
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-webpages-update
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/webpages/{id}/duplicate:
    post:
      summary: Duplicate webpage template
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-webpage-duplicate
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/media:
    get:
      summary: List media assets (URLs / metadata)
      description: Optional query `metadata=true`. **Permission** `templates:read`
      operationId: get-protected-templates-media
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: metadata
          in: query
          required: false
          type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/by-type/{type}/{id}:
    get:
      summary: Get template by type and id
      description: >-
        `type` is `email`, `invoice`, or `document`. **Permission**
        `templates:read`
      operationId: get-protected-templates-by-type
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: type
          in: path
          required: true
          type: string
          enum:
            - email
            - invoice
            - document
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/media/global:
    post:
      summary: Post global media reference
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-media-global
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/media/upload:
    post:
      summary: Upload media assets
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-media-upload
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/media/{id}:
    put:
      summary: Update media asset metadata
      description: '**Permission** `templates:write`'
      operationId: put-protected-templates-media
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/media/insert:
    post:
      summary: Insert media asset
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-media-insert
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/media/insert-bulk:
    post:
      summary: Bulk insert media assets
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-media-insert-bulk
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
  /api/protected/templates/send-test-email:
    post:
      summary: Send test email
      description: '**Permission** `templates:write`'
      operationId: post-protected-templates-send-test-email
      tags:
        - Templates
      security:
        - ApiKeyAuth: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Success
        '401':
          description: API key required or invalid
        '403':
          description: Insufficient permissions
components:
  schemas: {}
  securitySchemes: {}
