openapi: 3.2.0
info:
  title: Network Weather Partner API
  version: 1.1.0
  description: |
    Tenant-scoped fleet management and analytics API for Managed Service Providers (MSPs).

    ## Authentication

    All endpoints require OAuth 2.0 client credentials authentication. Obtain tokens from:
    - Production: `https://partner.networkweather.com/oauth/token`
    - Staging: `https://partner.staging.networkweather.com/oauth/token`

    Include the access token in the Authorization header:
    ```
    Authorization: Bearer <access_token>
    ```

    ## Rate Limits

    - Default: 1000 requests/minute per MSP
    - Burst: 100 requests/second
    - Rate limit headers are included in all responses

    ## Pagination

    List endpoints support cursor-based pagination via `cursor` and `limit` parameters.
    The response includes a `nextCursor` field when more results are available.
  contact:
    name: Network Weather API Support
    email: support@networkweather.com
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
servers:
  - url: https://partner.networkweather.com
    description: Production
  - url: https://partner.staging.networkweather.com
    description: Staging
security:
  - oauth_client_credentials:
      - fleet:read
tags:
  - name: MSP
    description: MSP account and dashboard operations
  - name: Organizations
    description: Customer organization management
  - name: Devices
    description: Device fleet management
  - name: Analytics
    description: Aggregated metrics and reporting
paths:
  /v1/msp/current:
    get:
      tags:
        - MSP
      summary: Get current MSP
      description: Returns information about the authenticated MSP.
      operationId: getCurrentMsp
      responses:
        '200':
          description: MSP information
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/MSP'
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/msp/{mspId}/stats:
    get:
      tags:
        - MSP
      summary: Get MSP dashboard statistics
      description: Returns high-level statistics for the MSP dashboard including device health breakdown.
      operationId: getMspDashboardStats
      parameters:
        - name: mspId
          in: path
          required: true
          schema:
            type: string
          description: MSP identifier
      responses:
        '200':
          description: Dashboard statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/MspDashboardStats'
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/msp/members:
    get:
      tags:
        - MSP
      summary: List MSP members
      description: Returns all identities (users) linked to the authenticated MSP.
      operationId: listMspMembers
      responses:
        '200':
          description: List of MSP members
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/MspMember'
                  meta:
                    type: object
                    properties:
                      total:
                        type: integer
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/organizations:
    get:
      tags:
        - Organizations
      summary: List organizations
      description: |
        Returns all customer organizations for the authenticated MSP with their statistics.
        Results are sorted by overall health (critical first, then warning, then healthy).
      operationId: listOrganizations
      parameters:
        - name: mspId
          in: query
          required: true
          schema:
            type: string
          description: Filter by MSP identifier
        - $ref: '#/components/parameters/PagingLimit'
        - $ref: '#/components/parameters/PagingCursor'
      responses:
        '200':
          description: List of organizations with statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/OrgWithStats'
                  meta:
                    type: object
                    properties:
                      total:
                        type: integer
                        description: Total number of organizations
                      nextCursor:
                        type:
                          - string
                          - 'null'
                        description: Cursor for next page (null if no more results)
                required:
                  - data
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/organizations/{orgId}:
    get:
      tags:
        - Organizations
      summary: Get organization details
      description: Returns detailed information and statistics for a specific organization.
      operationId: getOrganization
      parameters:
        - name: orgId
          in: path
          required: true
          schema:
            type: string
          description: Organization identifier
      responses:
        '200':
          description: Organization with statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/OrgWithStats'
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/devices:
    get:
      tags:
        - Devices
      summary: List devices
      description: |
        Returns devices in the MSP's fleet with health status and network quality.

        Default sort is by status (critical first), then by lastSeen descending.
      operationId: listDevices
      parameters:
        - name: mspId
          in: query
          schema:
            type: string
          description: Filter by MSP identifier
        - name: orgId
          in: query
          schema:
            type: string
          description: Filter by organization identifier
        - name: status
          in: query
          schema:
            $ref: '#/components/schemas/DeviceStatus'
          description: Filter by device health status
        - name: connectionState
          in: query
          schema:
            $ref: '#/components/schemas/ConnectionState'
          description: Filter by connection state
        - name: locationType
          in: query
          schema:
            $ref: '#/components/schemas/LocationType'
          description: Filter by location type
        - name: q
          in: query
          schema:
            type: string
          description: Search by assetId, serialNumber, userName, or userEmail
        - name: sortBy
          in: query
          schema:
            type: string
            enum:
              - status
              - lastSeen
              - version
              - assetId
            default: status
          description: Field to sort by
        - name: sortOrder
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
            default: asc
          description: Sort direction
        - $ref: '#/components/parameters/PagingLimit'
        - $ref: '#/components/parameters/PagingCursor'
      responses:
        '200':
          description: List of devices with status
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/DeviceWithStatus'
                  meta:
                    type: object
                    properties:
                      total:
                        type: integer
                      nextCursor:
                        type:
                          - string
                          - 'null'
                required:
                  - data
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/devices/{clientId}:
    get:
      tags:
        - Devices
      summary: Get device details
      description: |
        Returns detailed information for a specific device including:
        - Current status and network quality
        - Location and network context
        - Recent activity log
        - Historical network measurements (last 24 hours)
      operationId: getDevice
      parameters:
        - name: clientId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Device client identifier
      responses:
        '200':
          description: Device details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/DeviceDetail'
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/devices/{clientId}/logs:
    get:
      tags:
        - Devices
      summary: Get device logs
      description: |
        Returns recent telemetry logs for a device.

        Note: This endpoint returns data from the hot path (recent logs).
        For historical log analysis, use the Analytics API.
      operationId: getDeviceLogs
      parameters:
        - name: clientId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Device client identifier
        - name: from
          in: query
          schema:
            type: string
            format: date-time
          description: 'Start of time range (default: 24 hours ago)'
        - name: to
          in: query
          schema:
            type: string
            format: date-time
          description: 'End of time range (default: now)'
        - name: level
          in: query
          schema:
            type: string
            enum:
              - debug
              - info
              - warn
              - error
          description: Filter by log level
        - $ref: '#/components/parameters/PagingLimit'
      responses:
        '200':
          description: Device logs
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/LogEvent'
                  meta:
                    type: object
                    properties:
                      total:
                        type: integer
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/devices/{clientId}/network-history:
    get:
      tags:
        - Devices
      summary: Get device network history
      description: Returns historical network quality measurements for charting.
      operationId: getDeviceNetworkHistory
      parameters:
        - name: clientId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: Device client identifier
        - name: hours
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 168
            default: 24
          description: Number of hours of history to return (max 168 = 7 days)
        - name: resolution
          in: query
          schema:
            type: string
            enum:
              - 1m
              - 5m
              - 15m
              - 1h
            default: 5m
          description: Data point resolution
      responses:
        '200':
          description: Network history measurements
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/NetworkMeasurement'
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/analytics/version-distribution:
    get:
      tags:
        - Analytics
      summary: Get version distribution
      description: Returns the distribution of client versions across the fleet.
      operationId: getVersionDistribution
      security:
        - oauth_client_credentials:
            - analytics:read
      parameters:
        - name: mspId
          in: query
          schema:
            type: string
          description: Filter by MSP (defaults to authenticated MSP)
        - name: orgId
          in: query
          schema:
            type: string
          description: Filter by organization
      responses:
        '200':
          description: Version distribution
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      latestVersion:
                        type: string
                        description: Current latest version
                      versions:
                        type: array
                        items:
                          type: object
                          properties:
                            version:
                              type: string
                            count:
                              type: integer
                            percentage:
                              type: number
                              format: float
                          required:
                            - version
                            - count
                            - percentage
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/analytics/network-quality:
    get:
      tags:
        - Analytics
      summary: Get network quality summary
      description: Returns aggregated network quality metrics across the fleet.
      operationId: getNetworkQualitySummary
      security:
        - oauth_client_credentials:
            - analytics:read
      parameters:
        - name: mspId
          in: query
          schema:
            type: string
          description: Filter by MSP
        - name: orgId
          in: query
          schema:
            type: string
          description: Filter by organization
        - name: from
          in: query
          schema:
            type: string
            format: date-time
          description: Start of time range
        - name: to
          in: query
          schema:
            type: string
            format: date-time
          description: End of time range
      responses:
        '200':
          description: Network quality summary
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      statusBreakdown:
                        $ref: '#/components/schemas/NetworkQualityStats'
                      avgLatencyMs:
                        type: number
                        format: float
                      avgLossPercent:
                        type: number
                        format: float
                      avgJitterMs:
                        type: number
                        format: float
                      p95LatencyMs:
                        type: number
                        format: float
                    required:
                      - statusBreakdown
                required:
                  - data
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/analytics/metrics:
    get:
      tags:
        - Analytics
      summary: Get time-series metrics
      description: |
        Returns time-series metric data for charting.

        Available metrics:
        - `device_count`: Total device count over time
        - `online_count`: Online device count over time
        - `avg_latency`: Average network latency
        - `avg_loss`: Average packet loss
        - `check_in_count`: Check-in volume
      operationId: getMetrics
      security:
        - oauth_client_credentials:
            - analytics:read
      parameters:
        - name: metric
          in: query
          required: true
          schema:
            type: string
            enum:
              - device_count
              - online_count
              - avg_latency
              - avg_loss
              - check_in_count
          description: Metric to retrieve
        - name: mspId
          in: query
          schema:
            type: string
          description: Filter by MSP
        - name: orgId
          in: query
          schema:
            type: string
          description: Filter by organization
        - name: from
          in: query
          required: true
          schema:
            type: string
            format: date-time
          description: Start of time range
        - name: to
          in: query
          required: true
          schema:
            type: string
            format: date-time
          description: End of time range
        - name: resolution
          in: query
          schema:
            type: string
            enum:
              - 1m
              - 5m
              - 15m
              - 1h
              - 1d
            default: 1h
          description: Data point resolution
      responses:
        '200':
          description: Metric time series
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      metric:
                        type: string
                      points:
                        type: array
                        items:
                          type: object
                          properties:
                            time:
                              type: string
                              format: date-time
                            value:
                              type: number
                          required:
                            - time
                            - value
                    required:
                      - metric
                      - points
                required:
                  - data
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    oauth_client_credentials:
      type: oauth2
      description: |
        OAuth 2.0 client credentials flow for MSP/Partner API access.
        Tokens are obtained using client_id and client_secret.
      flows:
        clientCredentials:
          tokenUrl: https://partner.networkweather.com/oauth/token
          scopes:
            fleet:read: Read devices, organizations, and logs
            fleet:write: Modify device assignments and organization settings
            analytics:read: Read aggregate metrics and reports
  schemas:
    MSP:
      type: object
      description: A Managed Service Provider
      properties:
        mspId:
          type: string
        name:
          type: string
      required:
        - mspId
        - name
    Error:
      type: object
      properties:
        error:
          type: string
          description: Machine-readable error code
        message:
          type: string
          description: Human-readable error message
        retryAfterSec:
          type: integer
          minimum: 0
          description: Suggested retry delay in seconds
      required:
        - error
    MspMember:
      type: object
      description: A user identity linked to an MSP
      properties:
        email:
          type: string
          format: email
        name:
          type: string
        picture:
          type: string
          format: uri
          description: Avatar URL (omitted if not available)
        provider:
          type: string
          enum:
            - google
            - microsoft
            - password
          description: Authentication provider
        lastLoginAt:
          type: string
          format: date-time
      required:
        - email
        - name
        - provider
        - lastLoginAt
    MspDashboardStats:
      type: object
      description: High-level MSP dashboard statistics
      properties:
        totalDevices:
          type: integer
          description: Total devices across all organizations
        totalOrgs:
          type: integer
          description: Number of customer organizations
        healthy:
          type: integer
          description: Devices in healthy status
        warning:
          type: integer
          description: Devices in warning status
        critical:
          type: integer
          description: Devices in critical status
        onlineNow:
          type: integer
          description: Devices seen in the last hour
      required:
        - totalDevices
        - totalOrgs
        - healthy
        - warning
        - critical
        - onlineNow
    Organization:
      type: object
      description: A customer organization managed by an MSP
      properties:
        orgId:
          type: string
        name:
          type: string
        mspId:
          type: string
      required:
        - orgId
        - name
        - mspId
    NetworkQualityStatus:
      type: string
      enum:
        - good
        - degraded
        - poor
        - offline
      description: |
        Overall network quality assessment:
        - good: Latency <50ms, loss <1%, jitter <10ms
        - degraded: Latency <150ms, loss <5%, jitter <30ms
        - poor: Any metric exceeds degraded thresholds
        - offline: No recent measurements
    NetworkQualityStats:
      type: object
      description: Aggregate network quality device counts
      properties:
        good:
          type: integer
          description: Devices with good network quality
        degraded:
          type: integer
          description: Devices with degraded network quality
        poor:
          type: integer
          description: Devices with poor network quality
        offline:
          type: integer
          description: Devices with no recent measurements
        overall:
          $ref: '#/components/schemas/NetworkQualityStatus'
          description: Worst status affecting any device
      required:
        - good
        - degraded
        - poor
        - offline
        - overall
    LocationStats:
      type: object
      description: Device location breakdown
      properties:
        office:
          type: integer
        home:
          type: integer
        remote:
          type: integer
        unknown:
          type: integer
      required:
        - office
        - home
        - remote
        - unknown
    ConnectionStateStats:
      type: object
      description: Device connection state breakdown
      properties:
        streaming:
          type: integer
          description: Actively streaming telemetry
        idle:
          type: integer
          description: Connected but idle
        offline:
          type: integer
          description: Not connected
      required:
        - streaming
        - idle
        - offline
    OrgStats:
      type: object
      description: Aggregate statistics for an organization
      properties:
        orgId:
          type: string
        total:
          type: integer
          description: Total device count
        healthy:
          type: integer
          description: Devices in healthy status
        warning:
          type: integer
          description: Devices in warning status
        critical:
          type: integer
          description: Devices in critical status
        onlineNow:
          type: integer
          description: Devices seen in the last hour
        currentVersion:
          type: integer
          description: Devices running the latest version
        networkQuality:
          $ref: '#/components/schemas/NetworkQualityStats'
        locations:
          $ref: '#/components/schemas/LocationStats'
        connectionStates:
          $ref: '#/components/schemas/ConnectionStateStats'
      required:
        - orgId
        - total
        - healthy
        - warning
        - critical
        - onlineNow
        - currentVersion
        - networkQuality
        - locations
        - connectionStates
    DeviceStatus:
      type: string
      enum:
        - healthy
        - warning
        - critical
      description: |
        Overall device health status:
        - healthy: Online, current version, no issues
        - warning: Minor issues (outdated version, idle >1h)
        - critical: Major issues (offline >24h)
    OrgWithStats:
      allOf:
        - $ref: '#/components/schemas/Organization'
        - type: object
          description: Organization with computed statistics
          properties:
            stats:
              $ref: '#/components/schemas/OrgStats'
            overallHealth:
              $ref: '#/components/schemas/DeviceStatus'
              description: Worst device status in the organization
          required:
            - stats
            - overallHealth
    ConnectionState:
      type: string
      enum:
        - streaming
        - idle
        - offline
      description: |
        Current telemetry connection status:
        - streaming: Actively sending telemetry data
        - idle: Connected but no recent telemetry
        - offline: No connection in the last hour
    LocationType:
      type: string
      enum:
        - office
        - home
        - remote
        - unknown
      description: Where the device is connecting from
    LocationInference:
      type: object
      description: Inferred device location with confidence score
      properties:
        type:
          $ref: '#/components/schemas/LocationType'
        confidence:
          type: integer
          minimum: 0
          maximum: 100
          description: Confidence level 0-100
        signals:
          type: array
          items:
            type: string
          description: Signals that contributed to this inference (e.g., "corporate_asn", "radius_auth", "known_office_ip")
        officeName:
          type:
            - string
            - 'null'
          description: Known office location name if matched
      required:
        - type
        - confidence
        - signals
    NetworkType:
      type: string
      enum:
        - corporate
        - residential
        - mobile
        - datacenter
        - unknown
      description: Inferred network environment type based on ASN and other signals
    NetworkContext:
      type: object
      description: Information about the device's network environment
      properties:
        publicIp:
          type: string
          description: Partially masked public IP (e.g., 203.45.xxx.xxx)
        ispName:
          type: string
          description: ISP or ASN organization name
        asn:
          type: integer
          description: Autonomous System Number
        networkType:
          $ref: '#/components/schemas/NetworkType'
        radiusAuthenticated:
          type: boolean
          description: Whether 802.1X/RADIUS authentication was detected
        ssid:
          type:
            - string
            - 'null'
          description: WiFi network name if available
        gatewayVendor:
          type:
            - string
            - 'null'
          description: Gateway device vendor (from MAC OUI lookup)
      required:
        - publicIp
        - ispName
        - asn
        - networkType
        - radiusAuthenticated
    Device:
      type: object
      description: A managed device in the fleet
      properties:
        clientId:
          type: string
          format: uuid
          description: Unique device identifier
        mspId:
          type: string
          description: MSP that manages this device
        orgId:
          type: string
          description: Organization this device belongs to
        currentVersion:
          type: string
          description: Currently installed client version
        os:
          type: string
          enum:
            - macOS
            - Windows
            - Linux
            - Android
            - iOS
            - iPadOS
        osVersion:
          type:
            - string
            - 'null'
        arch:
          type: string
          enum:
            - arm64
            - x64
            - x86
            - armv7
        channel:
          type: string
          enum:
            - stable
            - beta
        lastCheckIn:
          type: string
          format: date-time
          description: Last C2 check-in time
        lastTelemetry:
          type: string
          format: date-time
          description: Last telemetry data received
        lastSeen:
          type: string
          format: date-time
          description: Most recent activity (max of lastCheckIn, lastTelemetry)
        connectionState:
          $ref: '#/components/schemas/ConnectionState'
        location:
          $ref: '#/components/schemas/LocationInference'
        network:
          $ref: '#/components/schemas/NetworkContext'
        checkInCount:
          type: integer
          description: Total number of check-ins
        serialNumber:
          type:
            - string
            - 'null'
        assetId:
          type:
            - string
            - 'null'
          description: Customer-assigned asset identifier
        referrer:
          type:
            - string
            - 'null'
          description: Deployment/partner attribution
        userName:
          type:
            - string
            - 'null'
          description: Enrolled user's display name
        userEmail:
          type:
            - string
            - 'null'
          format: email
          description: Enrolled user's email address
      required:
        - clientId
        - mspId
        - orgId
        - currentVersion
        - os
        - arch
        - channel
        - lastSeen
        - connectionState
        - location
        - network
    NetworkQuality:
      type: object
      description: Current network quality metrics
      properties:
        latencyMs:
          type: integer
          minimum: 0
          description: Round-trip latency to gateway/internet in milliseconds
        lossPercent:
          type: number
          format: float
          minimum: 0
          maximum: 100
          description: Packet loss percentage (0-100)
        jitterMs:
          type: integer
          minimum: 0
          description: Latency variation (jitter) in milliseconds
        status:
          $ref: '#/components/schemas/NetworkQualityStatus'
        measuredAt:
          type: string
          format: date-time
          description: When this measurement was taken
      required:
        - latencyMs
        - lossPercent
        - jitterMs
        - status
        - measuredAt
    DeviceWithStatus:
      allOf:
        - $ref: '#/components/schemas/Device'
        - type: object
          description: Device with computed health status
          properties:
            status:
              $ref: '#/components/schemas/DeviceStatus'
            isCurrentVersion:
              type: boolean
              description: Whether device is running the latest available version
            networkQuality:
              oneOf:
                - $ref: '#/components/schemas/NetworkQuality'
                - type: 'null'
              description: |
                Current network quality metrics derived from the latest health
                snapshot. Populated from destination-level ping metrics. Null if
                the device has no snapshot or is offline.
            snapshotAt:
              type:
                - string
                - 'null'
              format: date-time
              description: When the latest health snapshot was captured by the client. Null if no snapshot exists.
          required:
            - status
            - isCurrentVersion
    DeviceActivity:
      type: object
      description: A device activity log entry
      properties:
        timestamp:
          type: string
          format: date-time
        event:
          type: string
          enum:
            - check-in
            - update
            - install
            - error
        detail:
          type: string
          description: Human-readable event description
      required:
        - timestamp
        - event
        - detail
    NetworkMeasurement:
      type: object
      description: Historical network measurement data point
      properties:
        timestamp:
          type: string
          format: date-time
        latencyMs:
          type: integer
        lossPercent:
          type: number
          format: float
        jitterMs:
          type: integer
        target:
          type:
            - string
            - 'null'
          description: Measurement target (gateway, internet, specific host)
      required:
        - timestamp
        - latencyMs
        - lossPercent
        - jitterMs
    DeviceDetail:
      allOf:
        - $ref: '#/components/schemas/DeviceWithStatus'
        - type: object
          description: Extended device information for detail view
          properties:
            activity:
              type: array
              items:
                $ref: '#/components/schemas/DeviceActivity'
              description: Recent activity log entries
            networkHistory:
              type: array
              items:
                $ref: '#/components/schemas/NetworkMeasurement'
              description: Historical network quality measurements
          required:
            - activity
            - networkHistory
    LogEvent:
      type: object
      description: A log event for MSP viewing
      properties:
        time:
          type: string
          format: date-time
        level:
          type: string
          enum:
            - debug
            - info
            - warn
            - error
        event:
          type: string
        attrs:
          type: object
          additionalProperties: true
  responses:
    Unauthorized:
      description: Invalid or expired authentication token
      headers:
        WWW-Authenticate:
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: unauthorized
            message: Token expired
    Forbidden:
      description: Authenticated but not authorized for this resource
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: forbidden
            message: Access denied to organization org_123
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: not_found
            message: Device not found
    BadRequest:
      description: Bad request - invalid parameters or malformed payload
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: invalid_request
            message: orgId must be a valid UUID
  parameters:
    PagingLimit:
      in: query
      name: limit
      schema:
        type: integer
        minimum: 1
        maximum: 1000
        default: 100
      description: Maximum number of items to return
    PagingCursor:
      in: query
      name: cursor
      schema:
        type: string
      description: Opaque cursor for pagination (from previous response)
