openapi: 3.1.0
info:
  title: Surfmeter Export API
  version: v1
  description: |-
    API for exporting data from the Surfmeter platform.
    Provides access to measurements, client reports, event bundles, client information, user feedback, and network requests.
    Also supports advanced search capabilities via Elasticsearch Query DSL and ES|QL.
servers:
  - url: https://surfmeter-server.{host}/export_api/v1
    variables:
      host:
        default: your-customer-name.aveq.info
        description: Your specific customer hostname.
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
  parameters:
    StartTime:
      name: start_time
      in: query
      description: "Define a start time in ISO-8601 format (e.g., 2021-01-01T00:00:00Z) from which records will be queried. This applies to the created_at attribute of the record."
      required: false
      schema:
        type: string
        format: date-time
    EndTime:
      name: end_time
      in: query
      description: "Define an end time in ISO-8601 format (e.g., 2021-01-02T00:00:00Z) up until which records will be queried. This applies to the created_at attribute of the record."
      required: false
      schema:
        type: string
        format: date-time
    ClientUuid:
      name: client_uuid
      in: query
      description: "Specify a client UUID to query data from. Note: overrides any tags specified."
      required: false
      schema:
        type: string
    Tags:
      name: tags
      in: query
      description: "Filter by client's tags. If multiple tags are specified, all of them must be assigned to the client. Can be specified multiple times (e.g., tags=foo&tags=bar) or as a comma-separated list (e.g., tags=foo,bar)."
      required: false
      schema:
        type: array
        items:
          type: string
      style: form
      explode: false
    Label:
      name: label
      in: query
      description: "Filter by client's label."
      required: false
      schema:
        type: string
    MeasurementId:
      name: measurement_id
      in: query
      description: "A single measurement ID to query. Note: overrides all other parameters."
      required: false
      schema:
        type: integer
    Page:
      name: page
      in: query
      description: "The page number for pagination."
      required: false
      schema:
        type: integer
        default: 1
    PerPage:
      name: per_page
      in: query
      description: "The number of records per page. Cannot exceed 1000."
      required: false
      schema:
        type: integer
        default: 1000
        maximum: 1000
  schemas:
    ErrorResponse:
      type: object
      properties:
        message:
          type: string
        details:
          type: string
    GeneralRecord:
      type: object
      description: "A generic record structure. Specific fields depend on the resource type."
      additionalProperties: true
    MeasurementRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents a measurement record."
          properties:
            id:
              type: integer
            internal_id:
              type: string
            started_at:
              type: string
              format: date-time
            finished_at:
              type: string
              format: date-time
            aborted_at:
              type: string
              format: date-time
              nullable: true
            aborted_reason:
              type: string
              nullable: true
            finished_reason:
              type: string
              nullable: true
            url:
              type: string
              nullable: true
            domain:
              type: string
              nullable: true
            url_stripped:
              type: boolean
              nullable: true
            client_version:
              type: string
            client_type:
              type: string
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            client:
              type: object
              properties:
                uuid:
                  type: string
                label:
                  type: string
                  nullable: true
                type:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
                extra_label:
                  type: string
                  nullable: true
                created_at:
                  type: string
                  format: date-time
                updated_at:
                  type: string
                  format: date-time
                disabled_at:
                  type: string
                  format: date-time
                  nullable: true
                disabled_reason:
                  type: string
                  nullable: true
            statistic_values:
              type: object
              additionalProperties: true
            params:
              type: object
              additionalProperties: true
            metadata:
              type: object
              additionalProperties: true
            '@timestamp':
              type: string
              format: date-time
              description: "The client-reported start time, abort time, or server-side creation timestamp"
            type:
              type: string
              description: "The actual type in PascalCase (e.g. WebMeasurement)"
            started_at_minute:
              type: integer
              description: "The minute part of the start time, for easier aggregations"
              nullable: true
            video:
              type: object
              description: "Video data (only for VideoMeasurement)"
              nullable: true
              additionalProperties: true
            geolocation:
              type: object
              description: "Geolocation data if available"
              nullable: true
              properties:
                latitude:
                  type: number
                  format: float
                longitude:
                  type: number
                  format: float
                city:
                  type: string
                zip:
                  type: string
                region:
                  type: string
                country:
                  type: string
                lonlat:
                  type: string
                  description: "Elasticsearch geopoint format"
            connection_detail:
              type: object
              description: "Connection detail information if available"
              nullable: true
              additionalProperties: true
            isp_detail:
              type: object
              description: "ISP details"
              nullable: true
              properties:
                ip_address:
                  type: string
                as:
                  type: string
                isp:
                  type: object
                  properties:
                    name:
                      type: string
                latitude:
                  type: number
                  format: float
                  description: "Latitude derived from the IP address (city centroid)"
                longitude:
                  type: number
                  format: float
                  description: "Longitude derived from the IP address (city centroid)"
                lonlat:
                  type: string
                  description: "Elasticsearch geopoint format"
                city:
                  type: string
                region:
                  type: string
                country:
                  type: string
                zip:
                  type: string
            remote_isp_detail:
              type: object
              description: "Remote ISP details"
              nullable: true
              properties:
                ip_address:
                  type: string
                as:
                  type: string
                isp:
                  type: object
                  properties:
                    name:
                      type: string
                latitude:
                  type: number
                  format: float
                  description: "Latitude derived from the remote IP address (city centroid)"
                longitude:
                  type: number
                  format: float
                  description: "Longitude derived from the remote IP address (city centroid)"
                lonlat:
                  type: string
                  description: "Elasticsearch geopoint format"
                city:
                  type: string
                region:
                  type: string
                country:
                  type: string
                zip:
                  type: string
            study:
              type: object
              description: "Study information if available"
              nullable: true
              additionalProperties: true
            study_chain:
              type: object
              description: "Study chain information if available"
              nullable: true
              properties:
                study_ids:
                  type: array
                  items:
                    type: string
              additionalProperties: true
            client_report_values:
              type: array
              description: "Client report values (for web measurements with client reports)"
              nullable: true
              items:
                type: object
                additionalProperties: true
    ClientReportRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents a client report record."
          properties:
            id:
              type: integer
            type:
              type: string
            client_time:
              type: string
              format: date-time
            client_time_skewed:
              type: string
              format: date-time
            data_type:
              type: string
            data:
              type: object
              additionalProperties: true
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            measurement_id:
              type: integer
    NetworkRequestRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents a network request record."
          properties:
            id:
              type: integer
            client_time:
              type: string
              format: date-time
            client_time_skewed:
              type: string
              format: date-time
            data:
              type: object
              properties:
                request:
                  type: object
                  properties:
                    url:
                      type: string
                    method:
                      type: string
                  required:
                    - url
                    - method
                  additionalProperties: true
              additionalProperties: true
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            measurement_id:
              type: integer
            network_response:
              type: object
              additionalProperties: true
    EventBundleRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents an event bundle record."
          properties:
            id:
              type: integer
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            measurement_id:
              type: integer
        - oneOf:
            - type: object
              description: "The events of a VideoEventBundle."
              properties:
                state_events:
                  type: array
                  items:
                    type: object
                video_state_events:
                  type: array
                  items:
                    type: object
                ad_events:
                  type: array
                  items:
                    type: object
                resolution_events:
                  type: array
                  items:
                    type: object
                quality_events:
                  type: array
                  items:
                    type: object
                rate_events:
                  type: array
                  items:
                    type: object
                frame_events:
                  type: array
                  items:
                    type: object
                user_events:
                  type: array
                  items:
                    type: object
                buffer_events:
                  type: array
                  items:
                    type: object
                latency_events:
                  type: array
                  items:
                    type: object
                debug_events:
                  type: array
                  items:
                    type: object
                performance_events:
                  type: array
                  items:
                    type: object
            - type: object
              description: "The events of a WebEventBundle."
              properties:
                alert_events:
                  type: array
                  items:
                    type: object
                dom_events:
                  type: array
                  items:
                    type: object
                tab_events:
                  type: array
                  items:
                    type: object
                performance_events:
                  type: array
                  items:
                    type: object
                paint_events:
                  type: array
                  items:
                    type: object
                window_events:
                  type: array
                  items:
                    type: object
                redirect_events:
                  type: array
                  items:
                    type: object
                user_events:
                  type: array
                  items:
                    type: object
                debug_events:
                  type: array
                  items:
                    type: object
    ClientRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents a client record."
          properties:
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            disabled_at:
              type: string
              format: date-time
              nullable: true
            disabled_reason:
              type: string
              nullable: true
            uuid:
              type: string
            label:
              type: string
              nullable: true
            type:
              type: string
            tags:
              type: array
              items:
                type: string
            extra_label:
              type: string
              nullable: true
            registration_key:
              type: object
              nullable: true
              properties:
                registration_key:
                  type: string
                num_registrations_left:
                  type: integer
    UserFeedbackRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents a user feedback record."
          properties:
            id:
              type: integer
            type:
              type: string
            client_time:
              type: string
              format: date-time
            client_time_skewed:
              type: string
              format: date-time
            data_type:
              type: string
            data:
              type: object
              additionalProperties: true
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
            client:
              type: object
              properties:
                uuid:
                  type: string
    SearchRequestBody:
      type: object
      properties:
        body:
          type: object
          description: "The Elasticsearch query body. See Elasticsearch Query DSL documentation for details."
          additionalProperties: true
        scroll:
          type: string
          description: "Enable scrolling search with specified scroll timeout (e.g. \"1m\")."
          nullable: true
        source_only:
          type: boolean
          description: "If true, returns only the source documents without Elasticsearch metadata."
          nullable: true
      required:
        - body
    ElasticsearchResponse:
      type: object
      description: "Standard Elasticsearch JSON response including metadata."
      additionalProperties: true
    SourceDocumentsArray:
      type: array
      items:
        type: object
        additionalProperties: true
      description: "An array of source documents, without Elasticsearch metadata."
    EsqlRequestBody:
      type: object
      properties:
        query:
          type: string
          description: "The ES|QL query string."
      required:
        - query
    EsqlResponse:
      type: array
      items:
        type: object
        additionalProperties: true
      description: "An array of documents matching the ES|QL query."
    VersionResponse:
      type: object
      description: "The version of the Surfmeter Server."
      properties:
        version:
          type: string
      required:
        - version
    GeolocationRecord:
      type: object
      description: "A single geolocation sample recorded within a trace."
      properties:
        id:
          type: integer
        type:
          type: string
        client_time:
          type: string
          format: date-time
        client_time_skewed:
          type: string
          format: date-time
        latitude:
          type: number
          format: float
        longitude:
          type: number
          format: float
        accuracy:
          type: number
          format: float
          nullable: true
        speed:
          type: number
          format: float
          nullable: true
      additionalProperties: true
    GeolocationTraceRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents a geolocation trace, i.e. the series of geolocation samples recorded while one or more measurements ran."
          properties:
            id:
              type: integer
            client_uuid:
              type: string
              nullable: true
            measurement_ids:
              type: array
              description: "The IDs of the measurements that reference this trace, restricted to the measurements matching the current request's filters."
              items:
                type: integer
            geolocations:
              type: array
              items:
                $ref: '#/components/schemas/GeolocationRecord'
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time
    ConnectionDetailRecord:
      type: object
      description: "A single connection detail sample recorded within a trace. Which fields are present depends on the connection type (e.g. WiFi or mobile)."
      properties:
        id:
          type: integer
        type:
          type: string
        client_time:
          type: string
          format: date-time
        client_time_skewed:
          type: string
          format: date-time
        mobile_network_type:
          type: string
          description: "The type of mobile network, e.g. 4G or 5G."
          nullable: true
        mobile_network_type_general:
          type: string
          description: "The mobile network type, reduced to a general category."
          nullable: true
        ip_address:
          type: string
          nullable: true
        ssid:
          type: string
          description: "The name of the WiFi network."
          nullable: true
        rssi:
          type: number
          description: "Received Signal Strength Indicator."
          nullable: true
        signal_strength:
          type: number
          nullable: true
      additionalProperties: true
    ConnectionDetailTraceRecord:
      allOf:
        - $ref: '#/components/schemas/GeneralRecord'
        - type: object
          description: "Represents a connection detail trace, i.e. the series of connection detail samples recorded while one or more measurements ran."
          properties:
            id:
              type: integer
            client_uuid:
              type: string
              nullable: true
            measurement_ids:
              type: array
              description: "The IDs of the measurements that reference this trace, restricted to the measurements matching the current request's filters."
              items:
                type: integer
            connection_details:
              type: array
              items:
                $ref: '#/components/schemas/ConnectionDetailRecord'
            created_at:
              type: string
              format: date-time
            updated_at:
              type: string
              format: date-time

security:
  - ApiKeyAuth: []

paths:
  /version:
    get:
      summary: Get the server version
      operationId: getVersion
      description: "Returns the version of the Surfmeter Server. This is the only endpoint that does not require an API key."
      security: []
      responses:
        '200':
          description: The server version.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VersionResponse'
  /measurements:
    get:
      summary: Get measurements
      operationId: getMeasurements
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - name: type
          in: query
          description: The type of the measurement.
          required: false
          schema:
            type: string
            enum: ["VideoMeasurement", "WebMeasurement", "SpeedtestMeasurement", "NetworkMeasurement"]
        - name: subject
          in: query
          description: The subject of the measurement.
          required: false
          schema:
            type: array
            items:
              type: string
          style: form
          explode: false
        - name: study_id
          in: query
          description: The study ID of the measurement.
          required: false
          schema:
            type: array
            items:
              type: string
          style: form
          explode: false
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of measurements.
          headers:
            Per-Page:
              description: The number of elements shown per page.
              schema:
                type: integer
            Total:
              description: The number of total elements available.
              schema:
                type: integer
            Link:
              description: Links for pagination (RFC 8288).
              schema:
                type: string
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/MeasurementRecord'
        '403':
          description: Forbidden. Invalid or expired API key, or rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get measurement count
      operationId: getMeasurementCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - name: type
          in: query
          description: The type of the measurement.
          required: false
          schema:
            type: string
            enum: ["VideoMeasurement", "WebMeasurement", "SpeedtestMeasurement", "NetworkMeasurement"]
        - name: subject
          in: query
          description: The subject of the measurement.
          required: false
          schema:
            type: array
            items:
              type: string
          style: form
          explode: false
        - name: study_id
          in: query
          description: The study ID of the measurement.
          required: false
          schema:
            type: array
            items:
              type: string
          style: form
          explode: false
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total:
              description: The number of total elements available.
              schema:
                type: integer
        '403':
          description: Forbidden.
  /client_reports:
    get:
      summary: Get client reports
      operationId: getClientReports
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - name: type
          in: query
          description: The type of the client report.
          required: false
          schema:
            type: string
            enum:
              - "AmazonClientReport"
              - "DnsClientReport"
              - "IcmpPingClientReport"
              - "LighthouseClientReport"
              - "NetflixClientReport"
              - "OoklaSpeedtestClientReport"
              - "P1203ClientReport"
              - "PerformanceClientReport"
              - "YoutubeClientReport"
              - "TracerouteClientReport"
              - "NetworkPerformanceClientReport"
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of client reports.
          headers:
            Per-Page:
              schema: { type: integer }
            Total:
              schema: { type: integer }
            Link:
              schema: { type: string }
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ClientReportRecord'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get client report count
      operationId: getClientReportCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - name: type
          in: query
          description: The type of the client report.
          required: false
          schema:
            type: string
            enum:
              - "AmazonClientReport"
              - "DnsClientReport"
              - "IcmpPingClientReport"
              - "LighthouseClientReport"
              - "NetflixClientReport"
              - "OoklaSpeedtestClientReport"
              - "P1203ClientReport"
              - "PerformanceClientReport"
              - "YoutubeClientReport"
              - "TracerouteClientReport"
              - "NetworkPerformanceClientReport"
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total:
              schema: { type: integer }
        '403':
          description: Forbidden.
  /network_requests:
    get:
      summary: Get network requests
      operationId: getNetworkRequests
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of network requests.
          headers:
            Per-Page: { schema: { type: integer } }
            Total: { schema: { type: integer } }
            Link: { schema: { type: string } }
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/NetworkRequestRecord'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get network request count
      operationId: getNetworkRequestCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total: { schema: { type: integer } }
        '403':
          description: Forbidden.
  /event_bundles:
    get:
      summary: Get event bundles
      operationId: getEventBundles
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - name: type
          in: query
          description: The type of the event bundle.
          required: true
          schema:
            type: string
            enum: ["WebEventBundle", "VideoEventBundle"]
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of event bundles.
          headers:
            Per-Page: { schema: { type: integer } }
            Total: { schema: { type: integer } }
            Link: { schema: { type: string } }
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/EventBundleRecord'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get event bundle count
      operationId: getEventBundleCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - name: type
          in: query
          description: The type of the event bundle.
          required: false
          schema:
            type: string
            enum: ["WebEventBundle", "VideoEventBundle"]
            default: "VideoEventBundle"
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total: { schema: { type: integer } }
        '403':
          description: Forbidden.
  /clients:
    get:
      summary: Get clients
      operationId: getClients
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of clients.
          headers:
            Per-Page: { schema: { type: integer } }
            Total: { schema: { type: integer } }
            Link: { schema: { type: string } }
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ClientRecord'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get client count
      operationId: getClientCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total: { schema: { type: integer } }
        '403':
          description: Forbidden.
  /user_feedbacks:
    get:
      summary: Get user feedbacks
      operationId: getUserFeedbacks
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - name: type
          in: query
          description: "The type of the user feedback. Available types depend on your specific application."
          required: false
          schema:
            type: string
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of user feedbacks.
          headers:
            Per-Page: { schema: { type: integer } }
            Total: { schema: { type: integer } }
            Link: { schema: { type: string } }
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/UserFeedbackRecord'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get user feedback count
      operationId: getUserFeedbackCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - name: type
          in: query
          description: "The type of the user feedback."
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total: { schema: { type: integer } }
        '403':
          description: Forbidden.
  /connection_detail_traces:
    get:
      summary: Get connection detail traces
      operationId: getConnectionDetailTraces
      description: "Returns the connection detail traces of the measurements matching the given filters. Measurements without a connection detail trace are skipped."
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of connection detail traces.
          headers:
            Per-Page: { schema: { type: integer } }
            Total: { schema: { type: integer } }
            Link: { schema: { type: string } }
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ConnectionDetailTraceRecord'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get connection detail trace count
      operationId: getConnectionDetailTraceCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total: { schema: { type: integer } }
        '403':
          description: Forbidden.
  /geolocation_traces:
    get:
      summary: Get geolocation traces
      operationId: getGeolocationTraces
      description: "Returns the geolocation traces of the measurements matching the given filters. Measurements without a geolocation trace are skipped."
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
        - $ref: '#/components/parameters/Page'
        - $ref: '#/components/parameters/PerPage'
      responses:
        '200':
          description: A list of geolocation traces.
          headers:
            Per-Page: { schema: { type: integer } }
            Total: { schema: { type: integer } }
            Link: { schema: { type: string } }
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/GeolocationTraceRecord'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    head:
      summary: Get geolocation trace count
      operationId: getGeolocationTraceCount
      parameters:
        - $ref: '#/components/parameters/StartTime'
        - $ref: '#/components/parameters/EndTime'
        - $ref: '#/components/parameters/ClientUuid'
        - $ref: '#/components/parameters/Tags'
        - $ref: '#/components/parameters/Label'
        - $ref: '#/components/parameters/MeasurementId'
      responses:
        '200':
          description: Success. Total count in 'Total' header.
          headers:
            Total: { schema: { type: integer } }
        '403':
          description: Forbidden.
  /search:
    post:
      summary: Search analytics data using Elasticsearch Query DSL
      operationId: searchData
      parameters:
        - name: scroll
          in: query
          description: "Enable scrolling search with specified scroll timeout (e.g. \"1m\"). Returns results as streaming NDJSON."
          required: false
          schema:
            type: string
        - name: source_only
          in: query
          description: "If true, returns only the source documents without Elasticsearch metadata."
          required: false
          schema:
            type: boolean
        - name: q
          in: query
          description: "A Lucene query string (e.g., 'id:123'). Can be used for simple queries."
          required: false
          schema:
            type: string
      requestBody:
        description: Elasticsearch query.
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SearchRequestBody'
      responses:
        '200':
          description: Search results. Format depends on parameters.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ElasticsearchResponse'
                  - $ref: '#/components/schemas/SourceDocumentsArray'
            application/x-ndjson:
              schema:
                type: string
                format: binary
                description: "Stream of NDJSON documents when 'scroll' parameter is used."
        '400':
          description: Bad request. The 'body' parameter is missing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    get:
      summary: Search analytics data using Elasticsearch Query DSL
      operationId: searchDataGet
      description: "Identical to the POST variant, except that the query is passed via the query string. Prefer POST for anything but the simplest queries."
      parameters:
        - name: body
          in: query
          description: "The Elasticsearch query body, as a JSON-encoded string. See the Elasticsearch Query DSL documentation for details."
          required: true
          schema:
            type: string
        - name: scroll
          in: query
          description: "Enable scrolling search with specified scroll timeout (e.g. \"1m\"). Returns results as streaming NDJSON."
          required: false
          schema:
            type: string
        - name: source_only
          in: query
          description: "If true, returns only the source documents without Elasticsearch metadata."
          required: false
          schema:
            type: boolean
        - name: q
          in: query
          description: "A Lucene query string (e.g., 'id:123'). Can be used for simple queries."
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Search results. Format depends on parameters.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/ElasticsearchResponse'
                  - $ref: '#/components/schemas/SourceDocumentsArray'
            application/x-ndjson:
              schema:
                type: string
                format: binary
                description: "Stream of NDJSON documents when 'scroll' parameter is used."
        '400':
          description: Bad request. The 'body' parameter is missing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /esql:
    post:
      summary: Query analytics data using ES|QL
      operationId: queryEsql
      requestBody:
        description: ES|QL query.
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EsqlRequestBody'
      responses:
        '200':
          description: An array of documents matching the query criteria.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EsqlResponse'
        '400':
          description: Bad request. The 'query' parameter is missing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    get:
      summary: Query analytics data using ES|QL
      operationId: queryEsqlGet
      description: "Identical to the POST variant, except that the query is passed via the query string."
      parameters:
        - name: query
          in: query
          description: "The ES|QL query string. The FROM clause must reference your own indices."
          required: true
          schema:
            type: string
      responses:
        '200':
          description: An array of documents matching the query criteria.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EsqlResponse'
        '400':
          description: Bad request. The 'query' parameter is missing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
