openapi: 3.0.0
info:
  description: 'Stats APIs write records into the Kollective analytics pipeline'
  version: 1.0.0
  title: Kollective Stats Api

tags:
  - name: stats
    description: Report statistics into the system
  - name: live
    description: Fetch statistics for live events
  - name: diagnostics
    description: APIs for reporting diagnostics data

paths:

  /api/stats/play:
    post:
      operationId: postPlay
      summary: Report a play record
      description: Sent from the SDK to capture play session details and player event streams.
      security:
        - bearerHeaderAuth: []
        - bearerBodyAuth: []
      tags:
        - stats
      parameters: []
      requestBody:
        $ref: '#/components/requestBodies/PostDecoratedRecord'
      responses:
        201:
          $ref: '#/components/responses/RecordCreated'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/stats/play/{tenantId}/{contentId}:
    post:
      operationId: postPlayRecord
      summary: Report a play record
      description: Sent from the SDK to capture play session details and player event streams.
      security:
        - bearerHeaderAuth: []
        - bearerBodyAuth: []
      tags:
        - stats
      parameters:
        - $ref: '#/components/parameters/tenantIdParam'
        - $ref: '#/components/parameters/contentIdParam'
      requestBody:
        $ref: '#/components/requestBodies/PostDecoratedRecord'
      responses:
        201:
          $ref: '#/components/responses/RecordCreated'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/live/{tenantId}/{contentId}/transfer/summary:
    get:
      operationId: getLiveStatsTransferSummary
      summary: Get live stats summary from transfer records
      security:
        - bearerHeaderAuth: [get:content:transfer_summary]
        - bearerHeaderAuth: [get:content:transfer_summary:all]
      tags:
        - live
      parameters:
        - $ref: '#/components/parameters/tenantIdParam'
        - $ref: '#/components/parameters/contentIdParam'
        - $ref: '#/components/parameters/recentSecs'
      responses:
        200:
          description: Return the live stats
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LiveTransferSummary'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/traceroute/{customerId}:
    post:
      operationId: postTraceroute
      summary: Post agent traceroute information
      description: Store agent traceroute information for network topology analysis
      security:
        - bearerHeaderAuth: [publish:customer:traceroute]
        - bearerHeaderAuth: [publish:customer:traceroute:all]
      parameters:
        - $ref: '#/components/parameters/customerIdParam'
      tags:
        - traceroute
      requestBody:
        $ref: '#/components/requestBodies/PostTracerouteRecord'
      responses:
        201:
          description: Successfully created traceroute record
          $ref: '#/components/responses/RecordCreated'
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        503:
          description: Traceroute publishing has not been enabled

  /api/diagnostics/type/bootstrap/code/{code}:
    post:
      operationId: postBootstrapDiagnostic
      description: Post bootstrap diagnostics (no session token required)
      security: []
      parameters:
        - $ref: '#/components/parameters/codeParam'
      tags:
        - diagnostics
      requestBody:
        $ref: '#/components/requestBodies/BootstrapDiagnostic'
      responses:
        204:
          description: Successfully received bootstrap diagnostic
        400:
          $ref: '#/components/responses/BadRequest'

  /api/diagnostics/type/runtime/code/{code}:
    post:
      operationId: postRuntimeDiagnostic
      description: Post runtime diagnostics (no session token required)
      security:
        - bearerHeaderAuth: []
      parameters:
        - $ref: '#/components/parameters/codeParam'
      tags:
        - diagnostics
      requestBody:
        $ref: '#/components/requestBodies/RuntimeDiagnostic'
      responses:
        204:
          description: Successfully received runtime diagnostic
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/diagnostics/type/status/code/{code}:
    post:
      operationId: postStatusDiagnostic
      description: For reporting status related diagnostic data outside of a session
      security:
        - bearerHeaderAuth: []
      parameters:
        - $ref: '#/components/parameters/codeParam'
      tags:
        - diagnostics
      requestBody:
        $ref: '#/components/requestBodies/StatusDiagnostic'
      responses:
        204:
          description: Successfully received session diagnostic
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/diagnostics/type/session/code/{code}:
    post:
      operationId: postSessionDiagnostic
      description: Post session diagnostic data
      security:
        - bearerHeaderAuth: [publish:session:diagnostics]
        - bearerHeaderAuth: [publish:session:diagnostics:all]
      parameters:
        - $ref: '#/components/parameters/codeParam'
      tags:
        - diagnostics
      requestBody:
        $ref: '#/components/requestBodies/SessionDiagnostic'
      responses:
        204:
          description: Successfully received session diagnostic
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'


components:

  schemas:

    BootstrapDiagnostic:
      type: object
      required:
        - type
        - timestamp
        - reporter
        - reporterId
        - reporterVersion
        - code
      properties:
        type:
          type: string
          enum: [BOOTSTRAP]
        timestamp:
          type: integer
        reporter:
          type: string
          enum: [SDK, AGENT]
        reporterId:
          type: string
        reporterVersion:
          type: string
        code:
          type: integer
        agentId:
          type: string
        customerId:
          type: string
        tenantId:
          type: string

    RuntimeDiagnostic:
      type: object
      required:
        - type
        - timestamp
        - reporter
        - reporterId
        - reporterVersion
        - code
      properties:
        type:
          type: string
          enum: [RUNTIME]
        timestamp:
          type: integer
        reporter:
          type: string
          enum: [SDK, AGENT]
        reporterId:
          type: string
        reporterVersion:
          type: string
        code:
          type: integer
        agentId:
          type: string
        customerId:
          type: string
        tenantId:
          type: string

    StatusDiagnostic:
      type: object
      required:
        - code
        - type
        - timestamp
        - reporter
        - reporterId
        - reporterVersion
        - systemInfo
      properties:
        code:
          type: integer
        type:
          type: string
          enum: [STATUS]
        timestamp:
          type: integer
        reporter:
          type: string
          enum: [SDK, AGENT]
        reporterId:
          type: string
        reporterVersion:
          type: string
        agentId:
          type: string
        customerId:
          type: string
        systemInfo:
          $ref: '#/components/schemas/SystemInfo'

    SessionDiagnostic:
      type: object
      required:
        - type
        - timestamp
        - reporter
        - reporterId
        - reporterVersion
        - code
        - sessionId
        - tenantId
        - contentId
        - agentId
        - app
        - localities
      properties:
        type:
          type: string
          enum: [SESSION]
        timestamp:
          type: integer
        reporter:
          type: string
          enum: [SDK, AGENT]
        reporterId:
          type: string
        reporterVersion:
          type: string
        code:
          type: integer
        sessionId:
          type: string
        tenantId:
          type: string
        contentId:
          type: string
        agentId:
          type: string
        nodeId:
          type: string
        clusterId:
          type: string
        app:
          type: string
        localities:
          type: array
          items:
            type: string
        message:
          type: string
        data:
          type: object
          description: Any json-formatted data related to the session diagnostics

    SystemInfo:
      type: object
      required:
        - platform
        - platformVersion
      properties:
        platform:
          type: string
        platformVersion:
          type: string
        machineName:
          type: string
        internalIP:
          type: string
        externalIP:
          type: string
        gatewayIP:
          type: string

    ReportingContext:
      type: object
      properties:
        internalIps:
          type: array
          items:
            type: string
        externalIps:
          type: array
          items:
            type: string
        routerIps:
          type: array
          items:
            type: string
        eventTitle:
          type: string
        sessionPlayType:
          type: string
          enum: [LIVE,VOD]
        userEmail:
          type: string
        browser:
          type: string
        browserVersion:
          type: string
        platform:
          type: string
        platformVersion:
          type: string
        agentVersion:
          type: string
        legacyAgentVersion:
          type: string
        legacyArenaId:
          type: integer
        legacyArenaGroup:
          type: string
        iceCandidates:
          type: array
          items:
            $ref: '#/components/schemas/IceCandidate'

    IceCandidate:
      type: object
      required:
        - candidate
      properties:
        candidate:
          type: string
        component:
          type: string
        foundation:
          type: string
        ip:
          type: string
        port:
          type: string
        priority:
          type: string
        protocol:
          type: string
        relatedAddress:
          type: string
        relatedPort:
          type: string
        sdpMid:
          type: string
        sdpMLineIndex:
          type: string
        tcpType:
          type: string
        type:
          type: string
        usernameFragment:
          type: string


    DecoratedRecord:
      type: object
      required:
        - tenantId
        - contentId
        - record
      properties:
        tenantId:
          type: string
        contentId:
          type: string
        record:
          type: object
        hasReportingContext:
          type: boolean
        reportingContext:
          $ref: '#/components/schemas/ReportingContext'

    LiveContentSummary:
      type: object
      description: Summary stats for live content.
      required:
        - contentId
        - reach
      properties:
        contentId:
          type: string
        title:
          type: string
        reach:
          type: integer
        qoe:
          type: number
          description: QoE score between 0.0 and 1.0
        avgViewDuration:
          type: integer
          description: Average view duration in milliseconds
        startTime:
          type: integer
          description: Milliseconds since epoch
        endTime:
          type: integer
          description: Milliseconds since epoch

    LiveContentSummaryList:
      type: array
      items:
        $ref: '#/components/schemas/LiveContentSummary'

    LiveTransferSummary:
      type: object
      properties:
        reach:
          type: integer
          description: Total number of unique viewers
        mbpsWithPeering:
          type: number
          description: Mbps with peering (actual)
        mbpsWithoutPeering:
          type: number
          description: Mbps without peering (hypothetical)
        bandwidthSavings:
          type: number
          description: Bandwidth saved as a percentage (0.0 - 1.0)
        peeringEfficiency:
          type: number
          description: Peering efficiency as a percentage (0.0 - 1.0)

    LivePlaySummary:
      type: object
      description: Summary stats for live content.
      required:
        - contentId
        - reach
      properties:
        contentId:
          type: string
        title:
          type: string
        reach:
          type: integer
        qoe:
          type: number
          description: QoE score between 0.0 and 1.0
        avgViewDuration:
          type: integer
          description: Average view duration in milliseconds
        startTime:
          type: integer
          description: Milliseconds since epoch
        endTime:
          type: integer
          description: Milliseconds since epoch

    LivePlaySession:
      type: object
      description: Summary stats for live content.
      required:
        - contentId
      properties:
        playGuid:
          type: string
        sdkVersion:
          type: string
        title:
          type: string
        startTime:
          type: integer
          description: Milliseconds since epoch
        endTime:
          type: integer
          description: Milliseconds since epoch
        bufferTime:
          type: integer
          description: In milliseconds
        stallTime:
          type: integer
          description: In milliseconds
        stallCount:
          type: integer
        playDuration:
          type: integer
          description: In milliseconds
        browser:
          type: string
          description: Extracted from the user-agent
        browserVersion:
          type: string
          description: Extracted from the user-agent
        browserUserGuid:
          type: string
          description: Browser-generated semi-persistent guid to track machine / user identity
        platform:
          type: string
          description: Extracted from the user-agent
        platformVersion:
          type: string
          description: Extracted from the user-agent
        user:
          type: string
          description: (Optional) integrator-provided user identity data; may be a stable hash or may be email/username

    LivePlaySessionList:
      type: array
      items:
        $ref: '#/components/schemas/LivePlaySession'

    TracerouteRecord:
      type: object
      description: Traceroute information from agent
      required:
        - customerId
        - agentId
        - traceroute
      properties:
        customerId:
          type: string
        agentId:
          type: string
        traceroute:
          type: object

  securitySchemes:
    bearerHeaderAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

    bearerBodyAuth:
      description: Only used for JWT tokens embedded within the POST JSON body (Note, values added here will be ignored)
      type: apiKey
      in: query
      name: Token

  parameters:
    tenantIdParam:
      name: tenantId
      in: path
      description: ID of a Tenant item
      required: true
      schema:
        type: string
    contentIdParam:
      name: contentId
      in: path
      description: ID of a Content item
      required: true
      schema:
        type: string
    recentSecs:
      name: recentSecs
      in: query
      description: Number of seconds to include in recent stats
      required: false
      schema:
        type: integer
        minimum: 10
    customerIdParam:
      name: customerId
      in: path
      description: ID of a customer agent
      required: true
      schema:
        type: string

    codeParam:
      name: code
      in: path
      description: Diagnostic Status Code
      required: true
      schema:
        type: integer

  requestBodies:
    PostDecoratedRecord:
      required: true
      description: Post request data
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/DecoratedRecord'
        text/html:
          schema:
            $ref: '#/components/schemas/DecoratedRecord'
        text/plain:
          schema:
            $ref: '#/components/schemas/DecoratedRecord'
    PostTracerouteRecord:
      required: true
      description: Post traceroute record
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/TracerouteRecord'
    BootstrapDiagnostic:
      required: true
      description: Post bootstrap diagnostic
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/BootstrapDiagnostic'
    RuntimeDiagnostic:
      required: true
      description: Post runtime diagnostic
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RuntimeDiagnostic'
    StatusDiagnostic:
      required: true
      description: Status diagnostic message (Pre-Session)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/StatusDiagnostic'
    SessionDiagnostic:
      required: true
      description: Post session diagnostic
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SessionDiagnostic'


  responses:
    RecordCreated:
      description: New record created.
    BadRequest:
      description: Invalid request or missing parameters.
    UnauthorizedError:
      description: The access token is missing or invalid.
    ForbiddenError:
      description: You don't have permission to access this resource.

  links: {}
  callbacks: {}

security:
  - bearerHeaderAuth: []
