# This file is auto-generated by generate_surfmeter_api_openapi.py.
# Do not edit by hand — update the Rails routes/schemas or the overlay at
# overlays/surfmeter_api.yml and re-run build_schema_tables.sh.
openapi: 3.1.0
info:
  title: Surfmeter API
  version: v1
  description: 'The Surfmeter API lets you manage clients, users, capabilities,

    measurements, and organization-wide settings programmatically.'
paths:
  /version:
    get:
      operationId: application_version
      tags:
      - General
      responses:
        '200':
          description: Successful response
      summary: Get API version
  /clients:
    get:
      operationId: clients_index
      tags:
      - Clients
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientIndexResponse'
  /client_admin_users:
    get:
      operationId: client_admin_users_index
      tags:
      - Client Admin Users
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminUserIndexResponse'
    post:
      operationId: client_admin_users_create
      tags:
      - Client Admin Users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientAdminUserCreateData'
      responses:
        '201':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminUserCreateResponse'
  /client_admin_users/{id}:
    get:
      operationId: client_admin_users_show
      tags:
      - Client Admin Users
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminUserShowResponse'
    put:
      operationId: client_admin_users_update
      tags:
      - Client Admin Users
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientAdminUserUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminUserUpdateResponse'
    delete:
      operationId: client_admin_users_destroy
      tags:
      - Client Admin Users
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminUserDestroyResponse'
  /client_admin_users/{id}/email_change:
    post:
      operationId: client_admin_users_request_email_change
      tags:
      - Client Admin Users
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
    delete:
      operationId: client_admin_users_cancel_email_change
      tags:
      - Client Admin Users
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
  /client_groups:
    get:
      operationId: client_groups_index
      tags:
      - Client Groups
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientGroupIndexResponse'
    post:
      operationId: client_groups_create
      tags:
      - Client Groups
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientGroupCreateData'
      responses:
        '201':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientGroupCreateResponse'
  /client_groups/{id}:
    get:
      operationId: client_groups_show
      tags:
      - Client Groups
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientGroupShowResponse'
    put:
      operationId: client_groups_update
      tags:
      - Client Groups
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientGroupUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientGroupUpdateResponse'
    delete:
      operationId: client_groups_destroy
      tags:
      - Client Groups
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientGroupDestroyResponse'
  /clients/check_label_availability:
    get:
      operationId: clients_check_label_availability
      tags:
      - Clients
      parameters:
      - name: label
        in: query
        required: false
        schema:
          type: string
        description: Label to check for availability within the current data owner. Empty or whitespace-only values are treated
          as available.
      - name: exclude_id
        in: query
        required: false
        schema:
          oneOf:
          - type: integer
          - type: string
        description: Optional client ID (integer) or UUID (string) to exclude from the uniqueness check, typically the client
          currently being edited.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientCheckLabelAvailabilityResponse'
  /clients/{id}:
    get:
      operationId: clients_show
      tags:
      - Clients
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientShowResponse'
    put:
      operationId: clients_update
      tags:
      - Clients
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientUpdateResponse'
  /clients/{id}/disable:
    post:
      operationId: clients_disable
      tags:
      - Clients
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientDisableResponse'
  /clients/{client_id}/isp_contracts:
    get:
      operationId: isp_contracts_index
      tags:
      - ISP Contracts
      parameters:
      - name: client_id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IspContractIndexResponse'
    post:
      operationId: isp_contracts_create
      tags:
      - ISP Contracts
      parameters:
      - name: client_id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IspContractData'
      responses:
        '201':
          description: Successful response
  /clients/{client_id}/isp_contracts/{id}:
    put:
      operationId: isp_contracts_update
      tags:
      - ISP Contracts
      parameters:
      - name: client_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IspContractData'
      responses:
        '200':
          description: Successful response
    delete:
      operationId: isp_contracts_destroy
      tags:
      - ISP Contracts
      parameters:
      - name: client_id
        in: path
        required: true
        schema:
          type: string
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
  /isps:
    get:
      operationId: isps_index
      tags:
      - ISPs
      parameters:
      - name: name
        in: query
        required: false
        schema:
          type: string
        description: Case-insensitive substring match against the ISP name. When present, the response uses the compact combobox
          shape (id, name, country only) and is capped at 20 results.
      - name: country
        in: query
        required: false
        schema:
          type: string
        description: Two-letter ISO country code filter (e.g. "AT", "DE").
      - name: type
        in: query
        required: false
        schema:
          type: string
          enum:
          - FixedIsp
          - MobileIsp
        description: Filter by ISP type. Values outside the enum are ignored server-side.
      - name: verified
        in: query
        required: false
        schema:
          type: boolean
        description: Filter by verified status.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IspsAllIndexResponse'
    post:
      operationId: isps_create
      tags:
      - ISPs
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IspCreateData'
      responses:
        '201':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IspCreateResponse'
  /isps/{id}:
    get:
      operationId: isps_show
      tags:
      - ISPs
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IspShowResponse'
    put:
      operationId: isps_update
      tags:
      - ISPs
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IspUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IspUpdateResponse'
    delete:
      operationId: isps_destroy
      tags:
      - ISPs
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IspDestroyResponse'
  /export_api_keys:
    get:
      operationId: export_api_keys_index
      tags:
      - Export API Keys
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportApiKeyIndexResponse'
    post:
      operationId: export_api_keys_create
      tags:
      - Export API Keys
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExportApiKeyCreateData'
      responses:
        '201':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportApiKeyCreateResponse'
  /export_api_keys/{id}:
    get:
      operationId: export_api_keys_show
      tags:
      - Export API Keys
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportApiKeyShowResponse'
    delete:
      operationId: export_api_keys_destroy
      tags:
      - Export API Keys
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExportApiKeyDestroyResponse'
  /client_admin_api_keys:
    get:
      operationId: client_admin_api_keys_index
      tags:
      - Client Admin API Keys
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminApiKeyIndexResponse'
    post:
      operationId: client_admin_api_keys_create
      tags:
      - Client Admin API Keys
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientAdminApiKeyCreateData'
      responses:
        '201':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminApiKeyCreateResponse'
  /client_admin_api_keys/{id}:
    get:
      operationId: client_admin_api_keys_show
      tags:
      - Client Admin API Keys
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminApiKeyShowResponse'
    delete:
      operationId: client_admin_api_keys_destroy
      tags:
      - Client Admin API Keys
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientAdminApiKeyDestroyResponse'
  /registration_keys:
    get:
      operationId: registration_keys_index
      tags:
      - Registration Keys
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistrationKeyIndexResponse'
    post:
      operationId: registration_keys_create
      tags:
      - Registration Keys
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegistrationKeyCreateData'
      responses:
        '201':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistrationKeyCreateResponse'
  /registration_keys/{id}:
    get:
      operationId: registration_keys_show
      tags:
      - Registration Keys
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistrationKeyShowResponse'
    put:
      operationId: registration_keys_update
      tags:
      - Registration Keys
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegistrationKeyUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistrationKeyUpdateResponse'
    delete:
      operationId: registration_keys_destroy
      tags:
      - Registration Keys
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegistrationKeyDestroyResponse'
  /capabilities:
    get:
      operationId: capabilities_index
      tags:
      - Capabilities
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CapabilityIndexResponse'
    post:
      operationId: capabilities_create
      tags:
      - Capabilities
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CapabilityCreateData'
      responses:
        '201':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CapabilityCreateResponse'
  /capabilities/{id}:
    get:
      operationId: capabilities_show
      tags:
      - Capabilities
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CapabilityShowResponse'
    put:
      operationId: capabilities_update
      tags:
      - Capabilities
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CapabilityUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CapabilityUpdateResponse'
    delete:
      operationId: capabilities_destroy
      tags:
      - Capabilities
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CapabilityDestroyResponse'
  /measurement_options:
    get:
      operationId: measurement_options_index
      tags:
      - Measurement Options
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MeasurementOptionsIndexResponse'
  /measurements/search:
    post:
      operationId: measurements_search
      tags:
      - Measurements
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MeasurementSearchData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MeasurementSearchResponse'
  /measurements/{id}:
    get:
      operationId: measurements_show
      tags:
      - Measurements
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
  /measurements/{id}/p1203_client_report:
    get:
      operationId: measurements_p1203_client_report
      tags:
      - Measurements
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
  /measurements/{id}/network_performance_report:
    get:
      operationId: measurements_network_performance_report
      tags:
      - Measurements
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Successful response
  /license_usage:
    get:
      operationId: license_usage_index
      tags:
      - License Usage
      parameters:
      - name: start_time
        in: query
        required: false
        schema:
          type: string
        description: ISO-8601 timestamp restricting the report to measurements on or after this point in time. Parsed with
          Ruby's Time.parse so most common formats are accepted.
      - name: end_time
        in: query
        required: false
        schema:
          type: string
        description: ISO-8601 timestamp restricting the report to measurements on or before this point in time. Parsed with
          Ruby's Time.parse so most common formats are accepted.
      - name: extended
        in: query
        required: false
        schema:
          type: boolean
        description: When true, returns the extended monthly breakdown including license units and per-subject distribution.
          When false or omitted, returns the simple monthly unique-client count.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LicenseUsageExtendedIndexResponse'
  /data_owner/settings:
    get:
      operationId: data_owner_settings_show
      tags:
      - Data Owner / Settings
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataOwnerSettingsShowResponse'
    put:
      operationId: data_owner_settings_update
      tags:
      - Data Owner / Settings
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DataOwnerSettingsUpdateData'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DataOwnerSettingsUpdateResponse'
  /ai_assistant/status:
    get:
      operationId: ai_assistant_status
      tags:
      - AI Assistant
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AiAssistantStatusResponse'
  /ai_assistant/usage:
    get:
      operationId: ai_assistant_usage
      tags:
      - AI Assistant
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AiUsageResponse'
components:
  schemas:
    ClientIndexResponse:
      description: Response for clients index action
      type: object
      required:
      - clients
      properties:
        clients:
          type: array
          items:
            type: object
            required:
            - id
            - uuid
            - created_at
            - updated_at
            - client_groups
            properties:
              id:
                type: integer
              uuid:
                type: string
              label:
                type: string
                nullable: true
              extra_label:
                type: string
                nullable: true
              tags:
                type: array
                items:
                  type: string
                nullable: true
              created_at:
                type: string
                format: date-time
                example: '2026-01-15T10:30:00Z'
              updated_at:
                type: string
                format: date-time
                example: '2026-01-15T10:30:00Z'
              disabled_at:
                type: string
                format: date-time
                nullable: true
                example: '2026-01-15T10:30:00Z'
              disabled_reason:
                type: string
                nullable: true
              last_measurement_at:
                type: string
                format: date-time
                nullable: true
                example: '2026-01-15T10:30:00Z'
              registration_key:
                type: object
                properties:
                  id:
                    type: integer
                  registration_key:
                    type: string
                  comment:
                    type: string
                    nullable: true
                  valid_from:
                    type: string
                    format: date-time
                    nullable: true
                    example: '2026-01-15T10:30:00Z'
                  valid_until:
                    type: string
                    format: date-time
                    nullable: true
                    example: '2026-01-15T10:30:00Z'
                  num_registrations_left:
                    type: integer
                    nullable: true
                  usage_limit_days:
                    type: integer
                    nullable: true
                nullable: true
              client_groups:
                type: array
                items:
                  type: object
                  required:
                  - id
                  - name
                  properties:
                    id:
                      type: integer
                    name:
                      type: string
              current_isp_contract:
                type: object
                required:
                - id
                - isp_id
                - client_id
                - name
                - valid_from
                properties:
                  id:
                    type: integer
                  isp_id:
                    type: integer
                  isp_name:
                    type: string
                    nullable: true
                  client_id:
                    type: integer
                  upload_speed:
                    type: integer
                    nullable: true
                  download_speed:
                    type: integer
                    nullable: true
                  monthly_price:
                    type: number
                    nullable: true
                  currency:
                    type: string
                    nullable: true
                  assumed_tariff:
                    type: string
                    nullable: true
                  connection_type:
                    type: string
                    nullable: true
                  name:
                    type: string
                  valid_from:
                    type: string
                    format: date-time
                    example: '2026-01-15T10:30:00Z'
                  valid_until:
                    type: string
                    format: date-time
                    nullable: true
                    example: '2026-01-15T10:30:00Z'
                nullable: true
    ClientAdminUserIndexResponse:
      description: Response for client admin user index action
      type: object
      required:
      - users
      properties:
        users:
          type: array
          items:
            type: object
            required:
            - id
            - email
            - username
            - role
            properties:
              id:
                type: integer
              email:
                type: string
                format: email
                example: user@example.com
              username:
                type: string
              role:
                type: string
                enum:
                - org_admin
                - admin
                - editor
                - viewer
              first_name:
                type: string
                nullable: true
              last_name:
                type: string
                nullable: true
              ai_usage_accepted:
                type: boolean
                nullable: true
              ai_custom_prompt:
                type: string
                nullable: true
              pending_email:
                type: string
                nullable: true
              pending_email_token_sent_at:
                type: string
                format: date-time
                nullable: true
                example: '2026-01-15T10:30:00Z'
              pending_email_state:
                type: string
                enum:
                - active
                - expired
                - null
                nullable: true
    ClientAdminUserCreateData:
      description: Data for client admin user create action
      type: object
      required:
      - email
      - username
      - role
      properties:
        email:
          type: string
          format: email
          example: user@example.com
        username:
          type: string
        role:
          type: string
          enum:
          - org_admin
          - admin
          - editor
          - viewer
        first_name:
          type: string
          nullable: true
        last_name:
          type: string
          nullable: true
        notify_user:
          type: boolean
          description: When true, email the new user that their account has been created. Defaults to false when omitted.
    ClientAdminUserCreateResponse:
      description: Response for client admin user create action
      type: object
      required:
      - user
      properties:
        user:
          type: object
          required:
          - id
          - email
          - username
          - role
          properties:
            id:
              type: integer
            email:
              type: string
              format: email
              example: user@example.com
            username:
              type: string
            role:
              type: string
              enum:
              - org_admin
              - admin
              - editor
              - viewer
            first_name:
              type: string
              nullable: true
            last_name:
              type: string
              nullable: true
            ai_usage_accepted:
              type: boolean
              nullable: true
            ai_custom_prompt:
              type: string
              nullable: true
            pending_email:
              type: string
              nullable: true
            pending_email_token_sent_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            pending_email_state:
              type: string
              enum:
              - active
              - expired
              - null
              nullable: true
    ClientAdminUserShowResponse:
      description: Response for client admin user show action
      type: object
      required:
      - user
      properties:
        user:
          type: object
          required:
          - id
          - email
          - username
          - role
          properties:
            id:
              type: integer
            email:
              type: string
              format: email
              example: user@example.com
            username:
              type: string
            role:
              type: string
              enum:
              - org_admin
              - admin
              - editor
              - viewer
            first_name:
              type: string
              nullable: true
            last_name:
              type: string
              nullable: true
            ai_usage_accepted:
              type: boolean
              nullable: true
            ai_custom_prompt:
              type: string
              nullable: true
            pending_email:
              type: string
              nullable: true
            pending_email_token_sent_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            pending_email_state:
              type: string
              enum:
              - active
              - expired
              - null
              nullable: true
    ClientAdminUserUpdateData:
      description: Request data for client admin user update action
      type: object
      properties:
        first_name:
          type: string
          nullable: true
        last_name:
          type: string
          nullable: true
        ai_usage_accepted:
          type: boolean
          nullable: true
        ai_custom_prompt:
          type: string
          nullable: true
    ClientAdminUserUpdateResponse:
      description: Response for client admin user update action
      type: object
      required:
      - user
      properties:
        user:
          type: object
          required:
          - id
          - email
          - username
          - role
          properties:
            id:
              type: integer
            email:
              type: string
              format: email
              example: user@example.com
            username:
              type: string
            role:
              type: string
              enum:
              - org_admin
              - admin
              - editor
              - viewer
            first_name:
              type: string
              nullable: true
            last_name:
              type: string
              nullable: true
            ai_usage_accepted:
              type: boolean
              nullable: true
            ai_custom_prompt:
              type: string
              nullable: true
            pending_email:
              type: string
              nullable: true
            pending_email_token_sent_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            pending_email_state:
              type: string
              enum:
              - active
              - expired
              - null
              nullable: true
    ClientAdminUserDestroyResponse:
      description: Response for client admin user destroy action
      type: object
      properties: {}
    ClientGroupIndexResponse:
      description: Response for client groups index action
      type: object
      required:
      - client_groups
      properties:
        client_groups:
          type: array
          items:
            type: object
            required:
            - id
            - name
            - client_count
            properties:
              id:
                type: integer
              name:
                type: string
              description:
                type: string
                nullable: true
              client_count:
                type: integer
    ClientGroupShowResponse:
      description: Response for client group show action
      type: object
      required:
      - client_group
      properties:
        client_group:
          type: object
          required:
          - id
          - name
          - client_count
          - clients
          properties:
            id:
              type: integer
            name:
              type: string
            description:
              type: string
              nullable: true
            client_count:
              type: integer
            clients:
              type: array
              items:
                type: object
                required:
                - id
                - uuid
                properties:
                  id:
                    type: integer
                  uuid:
                    type: string
                  type:
                    type: string
                    nullable: true
                  label:
                    type: string
                    nullable: true
                  extra_label:
                    type: string
                    nullable: true
                  owner_name:
                    type: string
                    nullable: true
                  build_flavor:
                    type: string
                    nullable: true
                  project:
                    type: string
                    nullable: true
                  tags:
                    type: array
                    items:
                      type: string
                    nullable: true
                  client_groups:
                    type: array
                    items:
                      type: object
                      required:
                      - id
                      - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        description:
                          type: string
                          nullable: true
    ClientGroupCreateData:
      description: Data for client group create action
      type: object
      required:
      - name
      properties:
        name:
          type: string
        description:
          type: string
          nullable: true
    ClientGroupCreateResponse:
      description: Response for client group create action
      type: object
      required:
      - client_group
      properties:
        client_group:
          type: object
          required:
          - id
          - name
          - client_count
          properties:
            id:
              type: integer
            name:
              type: string
            description:
              type: string
              nullable: true
            client_count:
              type: integer
    ClientGroupUpdateData:
      description: Data for client group update action
      type: object
      properties:
        name:
          type: string
        description:
          type: string
          nullable: true
        client_ids:
          type: array
          items:
            type: integer
    ClientGroupUpdateResponse:
      description: Response for client group update action
      type: object
      required:
      - client_group
      properties:
        client_group:
          type: object
          required:
          - id
          - name
          - client_count
          properties:
            id:
              type: integer
            name:
              type: string
            description:
              type: string
              nullable: true
            client_count:
              type: integer
    ClientGroupDestroyResponse:
      description: Response for client group destroy action
      type: object
      properties: {}
    ClientCheckLabelAvailabilityResponse:
      description: Response for client label availability check action
      type: object
      required:
      - available
      properties:
        available:
          type: boolean
          description: Whether the label is available for use
        label:
          type: string
          description: The label that was checked (echoed back)
    ClientShowResponse:
      description: Response for client show action
      type: object
      required:
      - client
      properties:
        client:
          type: object
          required:
          - id
          - uuid
          - created_at
          - updated_at
          - client_groups
          properties:
            id:
              type: integer
            uuid:
              type: string
            label:
              type: string
              nullable: true
            extra_label:
              type: string
              nullable: true
            tags:
              type: array
              items:
                type: string
              nullable: true
            created_at:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            updated_at:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            disabled_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            disabled_reason:
              type: string
              nullable: true
            last_measurement_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            registration_key:
              type: object
              properties:
                id:
                  type: integer
                registration_key:
                  type: string
                comment:
                  type: string
                  nullable: true
                valid_from:
                  type: string
                  format: date-time
                  nullable: true
                  example: '2026-01-15T10:30:00Z'
                valid_until:
                  type: string
                  format: date-time
                  nullable: true
                  example: '2026-01-15T10:30:00Z'
                num_registrations_left:
                  type: integer
                  nullable: true
                usage_limit_days:
                  type: integer
                  nullable: true
              nullable: true
            client_groups:
              type: array
              items:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
            current_isp_contract:
              type: object
              required:
              - id
              - isp_id
              - client_id
              - name
              - valid_from
              properties:
                id:
                  type: integer
                isp_id:
                  type: integer
                isp_name:
                  type: string
                  nullable: true
                client_id:
                  type: integer
                upload_speed:
                  type: integer
                  nullable: true
                download_speed:
                  type: integer
                  nullable: true
                monthly_price:
                  type: number
                  nullable: true
                currency:
                  type: string
                  nullable: true
                assumed_tariff:
                  type: string
                  nullable: true
                connection_type:
                  type: string
                  nullable: true
                name:
                  type: string
                valid_from:
                  type: string
                  format: date-time
                  example: '2026-01-15T10:30:00Z'
                valid_until:
                  type: string
                  format: date-time
                  nullable: true
                  example: '2026-01-15T10:30:00Z'
              nullable: true
    ClientUpdateData:
      description: Data for client update action
      type: object
      properties:
        label:
          type: string
          nullable: true
        extra_label:
          type: string
          nullable: true
        tags:
          type: array
          items:
            type: string
          nullable: true
        client_group_ids:
          type: array
          items:
            type: integer
    ClientUpdateResponse:
      description: Response for client update action
      type: object
      required:
      - client
      properties:
        client:
          type: object
          required:
          - id
          - uuid
          - created_at
          - updated_at
          - client_groups
          properties:
            id:
              type: integer
            uuid:
              type: string
            label:
              type: string
              nullable: true
            extra_label:
              type: string
              nullable: true
            tags:
              type: array
              items:
                type: string
              nullable: true
            created_at:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            updated_at:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            disabled_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            disabled_reason:
              type: string
              nullable: true
            last_measurement_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            registration_key:
              type: object
              properties:
                id:
                  type: integer
                registration_key:
                  type: string
                comment:
                  type: string
                  nullable: true
                valid_from:
                  type: string
                  format: date-time
                  nullable: true
                  example: '2026-01-15T10:30:00Z'
                valid_until:
                  type: string
                  format: date-time
                  nullable: true
                  example: '2026-01-15T10:30:00Z'
                num_registrations_left:
                  type: integer
                  nullable: true
                usage_limit_days:
                  type: integer
                  nullable: true
              nullable: true
            client_groups:
              type: array
              items:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
    ClientDisableResponse:
      description: Response for client disable action
      type: object
      required:
      - client
      properties:
        client:
          type: object
          required:
          - id
          - uuid
          - created_at
          - updated_at
          - client_groups
          properties:
            id:
              type: integer
            uuid:
              type: string
            label:
              type: string
              nullable: true
            extra_label:
              type: string
              nullable: true
            tags:
              type: array
              items:
                type: string
              nullable: true
            created_at:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            updated_at:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            disabled_at:
              type: string
              format: date-time
              nullable: true
              example: '2026-01-15T10:30:00Z'
            disabled_reason:
              type: string
              nullable: true
            registration_key:
              type: object
              properties:
                id:
                  type: integer
                registration_key:
                  type: string
                comment:
                  type: string
                  nullable: true
                valid_from:
                  type: string
                  format: date-time
                  nullable: true
                  example: '2026-01-15T10:30:00Z'
                valid_until:
                  type: string
                  format: date-time
                  nullable: true
                  example: '2026-01-15T10:30:00Z'
                num_registrations_left:
                  type: integer
                  nullable: true
                usage_limit_days:
                  type: integer
                  nullable: true
              nullable: true
            client_groups:
              type: array
              items:
                type: object
                required:
                - id
                - name
                properties:
                  id:
                    type: integer
                  name:
                    type: string
    IspContractIndexResponse:
      description: Response for isp_contracts index action
      type: object
      required:
      - isp_contracts
      properties:
        isp_contracts:
          type: array
          items:
            type: object
            required:
            - id
            - isp_id
            - client_id
            - name
            - valid_from
            properties:
              id:
                type: integer
              isp_id:
                type: integer
              isp_name:
                type: string
                nullable: true
              client_id:
                type: integer
              upload_speed:
                type: integer
                nullable: true
              download_speed:
                type: integer
                nullable: true
              monthly_price:
                type: number
                nullable: true
              currency:
                type: string
                nullable: true
              assumed_tariff:
                type: string
                nullable: true
              connection_type:
                type: string
                nullable: true
              name:
                type: string
              valid_from:
                type: string
                format: date-time
                example: '2026-01-15T10:30:00Z'
              valid_until:
                type: string
                format: date-time
                nullable: true
                example: '2026-01-15T10:30:00Z'
    IspContractData:
      description: Request body for isp_contracts create and update actions
      type: object
      required:
      - isp_id
      - name
      properties:
        isp_id:
          type: integer
        name:
          type: string
        download_speed:
          type: integer
          nullable: true
        upload_speed:
          type: integer
          nullable: true
        connection_type:
          type: string
          nullable: true
        monthly_price:
          type: number
          nullable: true
        currency:
          type: string
          nullable: true
        assumed_tariff:
          type: string
          nullable: true
        valid_from:
          type: string
          format: date-time
          nullable: true
          example: '2026-01-15T10:30:00Z'
        valid_until:
          type: string
          format: date-time
          nullable: true
          example: '2026-01-15T10:30:00Z'
    IspsAllIndexResponse:
      description: Response for ISPs index with all ISPs and full details (no pagination)
      type: object
      required:
      - isps
      properties:
        isps:
          type: array
          items:
            type: object
            required:
            - id
            - name
            - type
            - country
            properties:
              id:
                type: integer
              name:
                type: string
              type:
                type: string
              alternative_names:
                type: array
                items:
                  type: string
              as_numbers:
                type: array
                items:
                  type: string
              country:
                type: string
              is_vpn:
                type: boolean
                nullable: true
              verified:
                type: boolean
                nullable: true
              created_at:
                type: string
              isp_contracts_count:
                type: integer
    IspShowResponse:
      description: Response for ISP show action with full details and contracts
      type: object
      required:
      - isp
      properties:
        isp:
          type: object
          required:
          - id
          - name
          - type
          - country
          properties:
            id:
              type: integer
            name:
              type: string
            type:
              type: string
            alternative_names:
              type: array
              items:
                type: string
            as_numbers:
              type: array
              items:
                type: string
            country:
              type: string
            is_vpn:
              type: boolean
              nullable: true
            verified:
              type: boolean
              nullable: true
            created_at:
              type: string
            isp_contracts_count:
              type: integer
            isp_contracts:
              type: array
              items:
                type: object
                required:
                - id
                - isp_id
                - client_id
                properties:
                  id:
                    type: integer
                  isp_id:
                    type: integer
                  client_id:
                    type: integer
                  upload_speed:
                    type: integer
                    nullable: true
                  download_speed:
                    type: integer
                    nullable: true
                  monthly_price:
                    type: number
                    nullable: true
                  currency:
                    type: string
                    nullable: true
                  assumed_tariff:
                    type: string
                    nullable: true
                  connection_type:
                    type: string
                    nullable: true
                  name:
                    type: string
                  valid_from:
                    type: string
                    nullable: true
                  valid_until:
                    type: string
                    nullable: true
                  client_uuid:
                    type: string
                    nullable: true
                  client_label:
                    type: string
                    nullable: true
    IspCreateData:
      description: Data for ISP create action
      type: object
      required:
      - name
      - country
      - type
      properties:
        name:
          type: string
        country:
          type: string
        type:
          type: string
        is_vpn:
          type: boolean
          nullable: true
    IspCreateResponse:
      description: Response for ISP create action
      type: object
      required:
      - isp
      properties:
        isp:
          type: object
          required:
          - id
          - name
          - type
          - country
          properties:
            id:
              type: integer
            name:
              type: string
            type:
              type: string
            alternative_names:
              type: array
              items:
                type: string
            as_numbers:
              type: array
              items:
                type: string
            country:
              type: string
            is_vpn:
              type: boolean
              nullable: true
            verified:
              type: boolean
              nullable: true
            created_at:
              type: string
            isp_contracts_count:
              type: integer
    IspUpdateData:
      description: Data for ISP update action
      type: object
      properties:
        name:
          type: string
        country:
          type: string
        type:
          type: string
        is_vpn:
          type: boolean
          nullable: true
    IspUpdateResponse:
      description: Response for ISP update action
      type: object
      required:
      - isp
      properties:
        isp:
          type: object
          required:
          - id
          - name
          - type
          - country
          properties:
            id:
              type: integer
            name:
              type: string
            type:
              type: string
            alternative_names:
              type: array
              items:
                type: string
            as_numbers:
              type: array
              items:
                type: string
            country:
              type: string
            is_vpn:
              type: boolean
              nullable: true
            verified:
              type: boolean
              nullable: true
            created_at:
              type: string
            isp_contracts_count:
              type: integer
    IspDestroyResponse:
      description: Response for ISP destroy action
      type: object
      properties: {}
    ExportApiKeyIndexResponse:
      type: object
      properties:
        export_api_keys:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              name:
                type: string
                nullable: true
              valid_from:
                type: string
              valid_until:
                type: string
              key_preview:
                type: string
            required:
            - id
            - valid_from
            - valid_until
            - key_preview
      required:
      - export_api_keys
    ExportApiKeyCreateData:
      description: Request data for creating an export API key
      type: object
      properties:
        name:
          type: string
        valid_until:
          type: string
    ExportApiKeyCreateResponse:
      description: Response for export API key create action
      type: object
      required:
      - export_api_key
      properties:
        export_api_key:
          type: object
          required:
          - id
          - valid_from
          - valid_until
          - api_key
          properties:
            id:
              type: integer
            valid_from:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            valid_until:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            name:
              type: string
              nullable: true
            api_key:
              type: string
    ExportApiKeyShowResponse:
      description: Response for export API key show action
      type: object
      required:
      - export_api_key
      properties:
        export_api_key:
          type: object
          required:
          - id
          - valid_from
          - valid_until
          - key_preview
          properties:
            id:
              type: integer
            valid_from:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            valid_until:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            name:
              type: string
              nullable: true
            key_preview:
              type: string
    ExportApiKeyDestroyResponse:
      description: Response for export API key destroy action
      type: object
      properties: {}
      additionalProperties: false
    ClientAdminApiKeyIndexResponse:
      type: object
      properties:
        client_admin_api_keys:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              name:
                type: string
                nullable: true
              valid_from:
                type: string
              valid_until:
                type: string
              key_preview:
                type: string
              effective_role:
                type: string
                nullable: true
              last_used_at:
                type: string
                nullable: true
              created_at:
                type: string
              client_admin_user_id:
                type: integer
            required:
            - id
            - valid_from
            - valid_until
            - key_preview
            - client_admin_user_id
      required:
      - client_admin_api_keys
    ClientAdminApiKeyCreateData:
      description: Request data for creating a client admin API key
      type: object
      properties:
        name:
          type: string
        valid_until:
          type: string
          format: date-time
          example: '2026-01-15T10:30:00Z'
        effective_role:
          type: string
          enum:
          - org_admin
          - admin
          - editor
          - viewer
    ClientAdminApiKeyCreateResponse:
      description: Response for client admin API key create action
      type: object
      required:
      - client_admin_api_key
      properties:
        client_admin_api_key:
          type: object
          required:
          - id
          - valid_from
          - valid_until
          - api_key
          - client_admin_user_id
          properties:
            id:
              type: integer
            valid_from:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            valid_until:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            name:
              type: string
              nullable: true
            api_key:
              type: string
            key_preview:
              type: string
            effective_role:
              type: string
              nullable: true
            last_used_at:
              type: string
              nullable: true
            created_at:
              type: string
            client_admin_user_id:
              type: integer
    ClientAdminApiKeyShowResponse:
      description: Response for client admin API key show action
      type: object
      required:
      - client_admin_api_key
      properties:
        client_admin_api_key:
          type: object
          required:
          - id
          - valid_from
          - valid_until
          - key_preview
          - client_admin_user_id
          properties:
            id:
              type: integer
            valid_from:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            valid_until:
              type: string
              format: date-time
              example: '2026-01-15T10:30:00Z'
            name:
              type: string
              nullable: true
            key_preview:
              type: string
            effective_role:
              type: string
              nullable: true
            last_used_at:
              type: string
              nullable: true
            created_at:
              type: string
            client_admin_user_id:
              type: integer
    ClientAdminApiKeyDestroyResponse:
      description: Response for client admin API key destroy action
      type: object
      properties: {}
      additionalProperties: false
    RegistrationKeyIndexResponse:
      type: object
      properties:
        registration_keys:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              registration_key:
                type: string
              comment:
                type: string
                nullable: true
              valid_from:
                type: string
              valid_until:
                type: string
              num_registrations_left:
                type: integer
              usage_limit_days:
                type: integer
                nullable: true
              testing:
                type: boolean
              capability:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  comment:
                    type: string
                    nullable: true
                  allowed_measurement_types:
                    type: array
                    items:
                      type: string
                  allowed_measurement_subjects:
                    type: array
                    items:
                      type: string
                  forbidden_measurement_types:
                    type: array
                    items:
                      type: string
                  forbidden_measurement_subjects:
                    type: array
                    items:
                      type: string
                required:
                - id
                - name
                - allowed_measurement_types
                - allowed_measurement_subjects
                - forbidden_measurement_types
                - forbidden_measurement_subjects
                nullable: true
              clients_count:
                type: integer
            required:
            - id
            - registration_key
            - valid_from
            - valid_until
            - num_registrations_left
            - testing
            - clients_count
      required:
      - registration_keys
    RegistrationKeyCreateData:
      type: object
      properties:
        comment:
          type: string
          nullable: true
        valid_until:
          type: string
          nullable: true
        num_registrations_left:
          type: integer
          nullable: true
        capability_id:
          type: integer
          nullable: true
        usage_limit_days:
          type: integer
          nullable: true
        testing:
          type: boolean
          nullable: true
      required: []
    RegistrationKeyCreateResponse:
      type: object
      properties:
        registration_key:
          type: object
          properties:
            id:
              type: integer
            registration_key:
              type: string
            comment:
              type: string
              nullable: true
            valid_from:
              type: string
            valid_until:
              type: string
            num_registrations_left:
              type: integer
            usage_limit_days:
              type: integer
              nullable: true
            testing:
              type: boolean
            capability:
              type: object
              properties:
                id:
                  type: integer
                name:
                  type: string
                comment:
                  type: string
                  nullable: true
                allowed_measurement_types:
                  type: array
                  items:
                    type: string
                allowed_measurement_subjects:
                  type: array
                  items:
                    type: string
                forbidden_measurement_types:
                  type: array
                  items:
                    type: string
                forbidden_measurement_subjects:
                  type: array
                  items:
                    type: string
              required:
              - id
              - name
              - allowed_measurement_types
              - allowed_measurement_subjects
              - forbidden_measurement_types
              - forbidden_measurement_subjects
              nullable: true
          required:
          - id
          - registration_key
          - valid_from
          - valid_until
          - num_registrations_left
          - testing
      required:
      - registration_key
    RegistrationKeyShowResponse:
      type: object
      properties:
        registration_key:
          type: object
          properties:
            id:
              type: integer
            registration_key:
              type: string
            comment:
              type: string
              nullable: true
            valid_from:
              type: string
            valid_until:
              type: string
            num_registrations_left:
              type: integer
            usage_limit_days:
              type: integer
              nullable: true
            testing:
              type: boolean
            capability:
              type: object
              properties:
                id:
                  type: integer
                name:
                  type: string
                comment:
                  type: string
                  nullable: true
                allowed_measurement_types:
                  type: array
                  items:
                    type: string
                allowed_measurement_subjects:
                  type: array
                  items:
                    type: string
                forbidden_measurement_types:
                  type: array
                  items:
                    type: string
                forbidden_measurement_subjects:
                  type: array
                  items:
                    type: string
              required:
              - id
              - name
              - allowed_measurement_types
              - allowed_measurement_subjects
              - forbidden_measurement_types
              - forbidden_measurement_subjects
              nullable: true
            clients:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: integer
                  uuid:
                    type: string
                  label:
                    type: string
                    nullable: true
          required:
          - id
          - registration_key
          - valid_from
          - valid_until
          - num_registrations_left
          - testing
          - clients
      required:
      - registration_key
    RegistrationKeyUpdateData:
      type: object
      properties:
        comment:
          type: string
          nullable: true
        valid_until:
          type: string
          nullable: true
        num_registrations_left:
          type: integer
          nullable: true
        capability_id:
          type: integer
          nullable: true
        usage_limit_days:
          type: integer
          nullable: true
        testing:
          type: boolean
          nullable: true
      required: []
    RegistrationKeyUpdateResponse:
      type: object
      properties:
        registration_key:
          type: object
          properties:
            id:
              type: integer
            registration_key:
              type: string
            comment:
              type: string
              nullable: true
            valid_from:
              type: string
            valid_until:
              type: string
            num_registrations_left:
              type: integer
            usage_limit_days:
              type: integer
              nullable: true
            testing:
              type: boolean
            capability:
              type: object
              properties:
                id:
                  type: integer
                name:
                  type: string
                comment:
                  type: string
                  nullable: true
                allowed_measurement_types:
                  type: array
                  items:
                    type: string
                allowed_measurement_subjects:
                  type: array
                  items:
                    type: string
                forbidden_measurement_types:
                  type: array
                  items:
                    type: string
                forbidden_measurement_subjects:
                  type: array
                  items:
                    type: string
              required:
              - id
              - name
              - allowed_measurement_types
              - allowed_measurement_subjects
              - forbidden_measurement_types
              - forbidden_measurement_subjects
              nullable: true
          required:
          - id
          - registration_key
          - valid_from
          - valid_until
          - num_registrations_left
          - testing
      required:
      - registration_key
    RegistrationKeyDestroyResponse:
      type: object
      properties: {}
      required: []
    CapabilityIndexResponse:
      type: object
      properties:
        capabilities:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              name:
                type: string
              comment:
                type: string
                nullable: true
              allowed_measurement_types:
                type: array
                items:
                  type: string
              allowed_measurement_subjects:
                type: array
                items:
                  type: string
              forbidden_measurement_types:
                type: array
                items:
                  type: string
              forbidden_measurement_subjects:
                type: array
                items:
                  type: string
              registration_keys_count:
                type: integer
            required:
            - id
            - name
            - registration_keys_count
      required:
      - capabilities
    CapabilityCreateData:
      type: object
      properties:
        name:
          type: string
        comment:
          type: string
          nullable: true
        allowed_measurement_types:
          type: array
          items:
            type: string
        allowed_measurement_subjects:
          type: array
          items:
            type: string
        forbidden_measurement_types:
          type: array
          items:
            type: string
        forbidden_measurement_subjects:
          type: array
          items:
            type: string
      required:
      - name
    CapabilityCreateResponse:
      type: object
      properties:
        capability:
          type: object
          properties:
            id:
              type: integer
            name:
              type: string
            comment:
              type: string
              nullable: true
            allowed_measurement_types:
              type: array
              items:
                type: string
            allowed_measurement_subjects:
              type: array
              items:
                type: string
            forbidden_measurement_types:
              type: array
              items:
                type: string
            forbidden_measurement_subjects:
              type: array
              items:
                type: string
          required:
          - id
          - name
      required:
      - capability
    CapabilityShowResponse:
      type: object
      properties:
        capability:
          type: object
          properties:
            id:
              type: integer
            name:
              type: string
            comment:
              type: string
              nullable: true
            allowed_measurement_types:
              type: array
              items:
                type: string
            allowed_measurement_subjects:
              type: array
              items:
                type: string
            forbidden_measurement_types:
              type: array
              items:
                type: string
            forbidden_measurement_subjects:
              type: array
              items:
                type: string
            registration_keys:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: integer
                  registration_key:
                    type: string
                  comment:
                    type: string
                    nullable: true
                  valid_from:
                    type: string
                  valid_until:
                    type: string
                  num_registrations_left:
                    type: integer
                  usage_limit_days:
                    type: integer
                    nullable: true
                  testing:
                    type: boolean
                  clients_count:
                    type: integer
                required:
                - id
                - registration_key
          required:
          - id
          - name
      required:
      - capability
    CapabilityUpdateData:
      type: object
      properties:
        name:
          type: string
        comment:
          type: string
          nullable: true
        allowed_measurement_types:
          type: array
          items:
            type: string
        allowed_measurement_subjects:
          type: array
          items:
            type: string
        forbidden_measurement_types:
          type: array
          items:
            type: string
        forbidden_measurement_subjects:
          type: array
          items:
            type: string
      required: []
    CapabilityUpdateResponse:
      type: object
      properties:
        capability:
          type: object
          properties:
            id:
              type: integer
            name:
              type: string
            comment:
              type: string
              nullable: true
            allowed_measurement_types:
              type: array
              items:
                type: string
            allowed_measurement_subjects:
              type: array
              items:
                type: string
            forbidden_measurement_types:
              type: array
              items:
                type: string
            forbidden_measurement_subjects:
              type: array
              items:
                type: string
          required:
          - id
          - name
      required:
      - capability
    CapabilityDestroyResponse:
      type: object
      properties: {}
      required: []
    MeasurementOptionsIndexResponse:
      type: object
      properties:
        measurement_types:
          type: array
          items:
            type: string
        measurement_subjects:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
      required:
      - measurement_types
      - measurement_subjects
    MeasurementSearchData:
      description: Request data for the measurements search action. Wraps an Elasticsearch search request against the current
        data owner's analytics index. The `body` property is passed through to Elasticsearch as a Query DSL payload; additional
        top-level properties (`size`, `from`, `search_after`, `scroll`) control pagination and streaming behavior and are
        forwarded to the Elasticsearch client alongside the body.
      type: object
      additionalProperties: false
      required:
      - body
      properties:
        body:
          additionalProperties: true
          description: 'Elasticsearch Query DSL payload. Treated as a passthrough: any valid Elasticsearch search request
            body (`query`, `aggs`, `sort`, `size`, `from`, `search_after`, `_source`, etc.) is accepted. May also be provided
            as a JSON-formatted string, in which case it is parsed server-side.'
          oneOf:
          - type: object
          - type: string
        source_only:
          type: boolean
          description: If true, the response is reduced to a plain array of `_source` documents instead of the full Elasticsearch
            response envelope.
        size:
          type: integer
          description: Maximum number of hits to return. Forwarded to the Elasticsearch client as a top-level parameter; equivalent
            to setting `size` inside `body`.
        from:
          type: integer
          description: Offset of the first hit to return, used for basic pagination. Forwarded to the Elasticsearch client
            as a top-level parameter.
        search_after:
          type: array
          description: Opaque cursor for deep pagination. Pass the `sort` array from the last hit of the previous page; requires
            a stable `sort` clause in `body`.
          items: {}
        scroll:
          type: string
          description: Enables Elasticsearch scroll search with the given timeout (e.g. `"1m"`). When set, the response is
            streamed as NDJSON (`application/x-ndjson`) instead of a single JSON object.
    MeasurementSearchResponse:
      description: 'Response for the measurements search action. Shape depends on the request: when `source_only=true` the
        response is an array of measurement source documents; otherwise it is the raw Elasticsearch search response envelope
        (hits, aggregations, etc.). When `scroll` is set, results are streamed as NDJSON and this schema does not apply.'
      oneOf:
      - description: 'Returned when `source_only=true`: a plain array of measurement `_source` documents, without Elasticsearch
          metadata. Each item is a measurement document; its concrete shape depends on the measurement type (video, web, etc.).'
        type: array
        items:
          type: object
          additionalProperties: true
      - description: 'Default response: the Elasticsearch search response envelope. Only the outermost keys are described
          here; everything inside is passed through unchanged.'
        type: object
        additionalProperties: true
        properties:
          took:
            type: integer
            description: Time in milliseconds Elasticsearch spent executing the search.
          timed_out:
            type: boolean
            description: Whether the search timed out before completing.
          _shards:
            type: object
            additionalProperties: true
            description: Per-shard execution summary reported by Elasticsearch.
          hits:
            type: object
            additionalProperties: true
            description: Container for matching documents. Includes `total`, `max_score`, and `hits` (an array of hit objects
              with `_index`, `_id`, `_source`, `sort`, etc.).
          aggregations:
            type: object
            additionalProperties: true
            description: Aggregation results, present only when the request `body` contained an `aggs` clause.
          _scroll_id:
            type: string
            description: Scroll cursor, present only when the request used the `scroll` parameter.
    LicenseUsageExtendedIndexResponse:
      description: Response for extended license usage index action with license units
      type: object
      required:
      - monthly_usage
      - total_units
      properties:
        monthly_usage:
          type: array
          items:
            type: object
            required:
            - month
            - license_units
            - unique_clients
            - breakdown_by_subject_count
            properties:
              month:
                type: string
                description: Month in YYYY-MM format
              license_units:
                type: integer
                description: Total license units consumed in this month
              unique_clients:
                type: integer
                description: Number of unique clients in this month
              breakdown_by_subject_count:
                type: object
                description: Breakdown by number of subjects measured per client
                additionalProperties:
                  type: object
                  required:
                  - clients
                  - units
                  properties:
                    clients:
                      type: integer
                      description: Number of clients with this subject count
                    units:
                      type: integer
                      description: License units consumed by clients with this subject count
        total_units:
          type: integer
          description: Total license units across all months
    DataOwnerSettingsShowResponse:
      description: Response for data owner settings show action
      type: object
      required:
      - settings
      properties:
        settings:
          type: object
          properties:
            ai_system_prompt:
              type: string
              nullable: true
    DataOwnerSettingsUpdateData:
      description: Request data for data owner settings update action
      type: object
      properties:
        ai_system_prompt:
          type: string
          nullable: true
    DataOwnerSettingsUpdateResponse:
      description: Response for data owner settings update action
      type: object
      required:
      - settings
      properties:
        settings:
          type: object
          properties:
            ai_system_prompt:
              type: string
              nullable: true
    AiAssistantStatusResponse:
      description: Response for AI assistant status action
      type: object
      required:
      - enabled
      - data_owner
      properties:
        enabled:
          type: boolean
          description: Whether AI assistant is enabled for this data owner
        data_owner:
          type: string
          description: Name of the data owner
    AiUsageResponse:
      type: object
      required:
      - usage
      properties:
        usage:
          type: object
          required:
          - total_tokens
          - limit
          - remaining
          - percentage_used
          - request_count
          - conversation_count
          properties:
            total_tokens:
              type: integer
              description: Total tokens used this month
            limit:
              type: integer
              description: Monthly token limit for this data owner
            remaining:
              type: integer
              description: Tokens remaining this month
            percentage_used:
              type: number
              description: Percentage of monthly limit used
            request_count:
              type: integer
              description: Total AI requests this month
            conversation_count:
              type: integer
              description: Total unique conversations this month
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: 'API key used on every request. Create keys in the Surfmeter Dashboard

        under Keys → Surfmeter API Keys.'
servers:
- url: https://surfmeter-server.{host}/client_admin_api/v1
  variables:
    host:
      default: your-customer-name.aveq.info
      description: Your specific customer hostname.
security:
- ApiKeyAuth: []
