openapi: 3.0.0
info:
  title: Kollective Gateway
  version: 0.0.1

paths:

  /oauth/token:
    post:
      operationId: accessToken
      security:
        - partnerIdAndToken: []
        - jwtAssertion: []
      tags:
        - authorization
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                grant_type:
                  description: The oauth grant type
                  type: string
                  enum: [client_credentials,'urn:ietf:params:oauth:grant-type:jwt-bearer']
              required:
                - grant_type
      responses:
        200:
          description: Return the granted token
          content:
            application/json:
              schema:
                type: object
                required:
                  - access_token
                  - token_type
                properties:
                  access_token:
                    description: The granted access token.
                    type: string
                  token_type:
                    description: The type of access_token.
                    type: string
                    enum: [Bearer]
                  expires_in:
                    description: Expiration time of access_token in seconds.
                    type: integer
        400:
          description: Invalid request
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                properties:
                  error:
                    type: string
                    enum: [invalid_request]
                  error_description:
                    type: string
        401:
          description: Unauthorized
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                properties:
                  error:
                    type: string
                    enum: [access_denied]
                  error_description:
                    type: string
  /oauth/user_claims:
    get:
      operationId: getUserClaims
      description: Get the set of resource claims the connected to the user.
      security:
        - bearerAuth: [get:user:claims]
        - portalToken: [get:user:claims]
        - apiTokenAuth: [get:user:claims]
      tags:
        - authorization
      parameters:
        - name: serviceProvider
          in: query
          required: false
          description: The service provider domain.
          schema:
            type: string
            example: kollective.com
        - name: assignmentId
          in: query
          required: false
          description: The id used to looked users Tenant/Customer. i.e. o365Id or gSuiteId
          schema:
            type: string
        - name: assignmentIdOverride
          in: query
          required: false
          description: When present with a userDomain this is used for generating an impersonation token for the tenant associated with the override id
          schema:
            type: string
        - name: userDomain
          in: query
          required: false
          description: The user's email domain
          schema:
            type: string
            example: kollective.com
        - name: partnerSecret
          in: query
          required: false
          description: A partner secret to override default partner information source
          schema:
            type: string
        - name: includePartnerClaims
          in: query
          description: Determines whether the partner claims are returned
          schema:
            type: boolean
            default: true
      responses:
        200:
          description: The resources connected to the user
          content:
            application/json:
              schema:
                type: object
                properties:
                  https://kollective.app/kollective_customer:
                    type: string
                  https://kollective.app/kollective_tenant:
                    type: string
                  https://kollective.app/service_provider:
                    type: string
                  https://kollective.app/cust:
                    type: array
                    items:
                      type: string
                  https://kollective.app/tid:
                    type: array
                    items:
                      type: string
                  https://kollective.app/pid:
                    type: string
                  https://kollective.app/pd:
                    type: string
                  https://kollective.app/partner_app:
                    type: array
                    items:
                      type: string
                  https://kollective.app/service_providers:
                    type: array
                    items:
                      type: string
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/discovery:
    get:
      operationId: apiDiscoveryGet
      security: []
      tags:
        - gateway
      parameters:
        - name: operation
          in: query
          required: true
          description: The operation to look up
          schema:
            type: string
            enum:
              - getSdkUri
              - getSdkInit
              - getAgentConfig
              - getAccessToken
              - postBootstrapDiagnostic
              - getCustomerDeviceAccessToken
              - getTenantDeviceAccessToken
              - getCustomerDeviceConfig
              - getTenantDeviceConfig
              - postCustomerModuleDevice
              - migrateCustomerAgentLicense
        - name: version
          in: query
          required: true
          description: The api version
          schema:
            type: string
            enum: ['1.0','0.1']
      responses:
        200:
          description: Return the found apis
          content:
            application/json:
              schema:
                type: object
                required:
                  - version
                  - operations
                properties:
                  version:
                    type: string
                    enum: [0.1]
                  operations:
                    type: object
                    additionalProperties:
                      type: object
                      required:
                        - uri
                      properties:
                        uri:
                          type: string
                        params:
                          type: object
                          additionalProperties:
                            type: string
        400:
          $ref: '#/components/responses/BadRequest'

  /api/tenant/{tenantId}/content/{contentId}/coordinator/request:
    post:
      operationId: coordinatorRequest
      description: Send a coordinator request via http
      security:
        - sessionToken: []
      tags:
        - Coordinator
      parameters:
        - $ref: '#/components/parameters/tenantIdParam'
        - $ref: '#/components/parameters/contentIdParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [node]
              properties:
                node:
                  $ref: '#/components/schemas/NodeData'
          application/x-protobuf:
            schema:
              type: object
              required: [node]
              properties:
                node:
                  $ref: '#/components/schemas/NodeData'
      responses:
        200:
          description: Return the potential clusters
          content:
            application/json:
              schema:
                type: object
                properties:
                  options:
                    type: array
                    items:
                      $ref: '#/components/schemas/ClusterAttachment'
                  cluster:
                    $ref: '#/components/schemas/Cluster'
            application/x-protobuf:
              schema:
                type: object
                properties:
                  options:
                    type: array
                    items:
                      $ref: '#/components/schemas/ClusterAttachment'
                  cluster:
                    $ref: '#/components/schemas/Cluster'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'
  /api/tenant/{tenantId}/content/{contentId}/coordinator/notify:
    post:
      operationId: coordinatorNotify
      description: Send a coordinator notify via http
      security:
        - sessionToken: []
      tags:
        - Coordinator
      parameters:
        - $ref: '#/components/parameters/tenantIdParam'
        - $ref: '#/components/parameters/contentIdParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NodeData'
          application/x-protobuf:
            schema:
              $ref: '#/components/schemas/NodeData'
      responses:
        200:
          description: Notify successful
          content:
            application/json:
              schema:
                type: object
            application/x-protobuf:
              schema:
                type: object
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'
  /api/tenant/{tenantId}/content/{contentId}/coordinator/detach:
    post:
      operationId: coordinatorDetach
      description: Send a coordinator detach via http
      security:
        - sessionToken: []
      tags:
        - Coordinator
      parameters:
        - $ref: '#/components/parameters/tenantIdParam'
        - $ref: '#/components/parameters/contentIdParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [nodeId, clusterId, agentId, tenantId, contentId]
              properties:
                nodeId:
                  type: string
                clusterId:
                  type: string
                agentId:
                  type: string
                tenantId:
                  type: string
                contentId:
                  type: string
          application/x-protobuf:
            schema:
              type: object
              required: [nodeId, clusterId, agentId, tenantId, contentId]
              properties:
                nodeId:
                  type: string
                clusterId:
                  type: string
                agentId:
                  type: string
                tenantId:
                  type: string
                contentId:
                  type: string
      responses:
        200:
          description: Detach successful
          content:
            application/json:
              schema:
                type: object
            application/x-protobuf:
              schema:
                type: object
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/agent/{agentId}/detach:
    post:
      operationId: agentBatchDetach
      description: Send batched collection of agent detachment requests
      security:
        - gatewayToken: []
      tags:
        - Agent
      parameters:
        - $ref: '#/components/parameters/agentIdParam'
      requestBody:
        $ref: '#/components/requestBodies/PostAgentDetachBody'
      responses:
        204:
          description: Detach message successfully received
        400:
          $ref: '#/components/responses/BadRequest'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'
  /api/tenant/{tenantId}/content/{contentId}/coordinator/listclusters:
    post:
      operationId: coordinatorListClusters
      description: Send a coordinator listClusters via http
      security:
        - sessionToken: []
      tags:
        - Coordinator
      parameters:
        - $ref: '#/components/parameters/tenantIdParam'
        - $ref: '#/components/parameters/contentIdParam'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClusterListRequest'
          application/x-protobuf:
            schema:
              $ref: '#/components/schemas/ClusterListRequest'
      responses:
        200:
          description: ListClusters successful
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClusterListResponse'
            application/x-protobuf:
              schema:
                $ref: '#/components/schemas/ClusterListResponse'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

  /api/customer/{customerId}/azure/subscribe:
    post:
      operationId: azureMarketplaceSubscribe
      description: Process an Azure Marketplace subscription activation
      security:
        - gatewayToken: [gateway:admin:all]
        - portalToken:
          - update:customer:azure_marketplace_subscription
          - gateway:admin:all
      tags:
        - Azure Marketplace
      parameters:
        - $ref: '#/components/parameters/customerIdParam'
      requestBody:
        description: Azure provided subscription token
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubscribeData'
      responses:
        204:
          description: Subscription successfully processed
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'

components:
  securitySchemes:
    sessionToken:
      description: Signed-JWT from content service
      type: http
      scheme: bearer
      bearerFormat: JWT
    bearerAuth:
      description: Same as 'portalToken' but allows adding an existing token via swagger UI
      type: http
      scheme: bearer
      bearerFormat: JWT
    gatewayToken:
      description: Uses the authorization tokens originating from Gateway
      type: http
      scheme: bearer
      bearerFormat: JWT
    portalToken:
      type: oauth2
      description: Uses the authorization tokens from Kollective portal Auth0
      flows:
        implicit:
          authorizationUrl: '/authorize?audience=https%3A%2F%2Ftenant.kollective.app'
          scopes:
            get:user:claims: Allows for the retrieval of user claims
            update:customer: Allows for the update of a Customer associated to the user
            update:customer:azure_marketplace_subscription: Allows for Azure Marketplace subscriptions to be processed
            # Admin
            gateway:admin:all: Allows administrators to perform restricted operations
    partnerIdAndToken:
      description: The Partner ID and Partner token as Basic auth header
      type: http
      scheme: basic
    jwtAssertion:
      description: The Agent License or Auth0 JWT in 'assertion' as defined by RFC7523
      type: apiKey
      in: query
      name: assertion
    apiTokenAuth:
      type: apiKey
      in: header
      name: X-API-KEY

  parameters:
    agentIdParam:
      name: agentId
      in: path
      description: Agent ID
      required: true
      schema:
        type: string
        minLength: 1

    tenantIdParam:
      name: tenantId
      in: path
      description: Tenant ID within the application
      required: true
      schema:
        type: string
        minLength: 1

    contentIdParam:
      name: contentId
      in: path
      description: Content ID within the application
      required: true
      schema:
        type: string

    customerIdParam:
      name: customerId
      in: path
      description: Customer ID within the application
      required: true
      schema:
        type: string
        minLength: 1

  schemas:
    ProblemResponse:
      type: object
      required:
        - title
        - status
        - detail
      properties:
        title:
          type: string
          description: A short, human-readable summary of the problem type.
        status:
          type: integer
          description: The HTTP status code.
        detail:
          type: string
          description: A human-readable explanation specific to this occurrence of the problem.

    # Coordinator types
    TransportType:
      type: string
      enum: [TCP, WEBRTC]
    PeeringProtocol:
      type: object
      required:
        - type
        - majorVersion
        - minorVersion
      properties:
        type:
          $ref: '#/components/schemas/TransportType'
        majorVersion:
          type: integer
        minorVersion:
          type: integer
        uris:
          type: array
          items:
            type: string
    NodeState:
      type: object
      required:
        - upCapacity
        - midCapacity
        - downCapacity
      properties:
        upCapacity:
          type: integer
        midCapacity:
          type: integer
        downCapacity:
          type: integer
    Cluster:
      type: object
      required:
        - id
        - transportType
        - protocolMajorVersion
      properties:
        id:
          type: string
        transportType:
          $ref: '#/components/schemas/TransportType'
        protocolMajorVersion:
          type: integer
    Attachment:
      type: object
      required:
          - activeCluster
          - depth
      properties:
        activeCluster:
          $ref: '#/components/schemas/Cluster'
        upstreams:
          type: array
          items:
            type: string
        depth:
          type: integer
    PeerCandidate:
      type: object
      required:
        - nodeId
        - agentId
        - tenantId
        - contentId
        - depth
        - protocol
        - state
      properties:
        nodeId:
          type: string
        agentId:
          type: string
        tenantId:
          type: string
        contentId:
          type: string
        depth:
          type: integer
        upstreams:
          type: array
          items:
            type: string
        protocol:
          $ref: '#/components/schemas/PeeringProtocol'
        state:
          $ref: '#/components/schemas/NodeState'
    ClusterAttachment:
      type: object
      required:
        - cluster
      properties:
        peers:
          type: array
          items:
            $ref: '#/components/schemas/PeerCandidate'
        cluster:
          $ref: '#/components/schemas/Cluster'

    NodeData:
      type: object
      required:
        - id
        - agentId
        - tenantId
        - contentId
        - protocol
        - locality
        - state
      properties:
        id:
          type: string
        agentId:
          type: string
        tenantId:
          type: string
        contentId:
          type: string
        attachment:
          $ref: '#/components/schemas/Attachment'
        protocol:
          $ref: '#/components/schemas/PeeringProtocol'
        locality:
          type: string
        state:
          $ref: '#/components/schemas/NodeState'

    ClusterListRequest:
      type: object
      required:
        - node
      properties:
        node:
          $ref: '#/components/schemas/NodeData'

    ClusterListResponse:
      type: object
      required:
        - clusters
      properties:
        clusters:
          type: array
          items:
            $ref: '#/components/schemas/Cluster'

    AgentDetachNotification:
      type: object
      required:
        - nodeId
        - clusterId
        - agentId
        - tenantId
        - contentId
        - sessionToken
      properties:
        nodeId:
          type: string
        clusterId:
          type: string
        agentId:
          type: string
        tenantId:
          type: string
        contentId:
          type: string
        sessionToken:
          type: string

    # Azure Marketplace types
    SubscribeData:
      type: object
      required:
        - token
      properties:
        token:
          description: Subscription token provided by the originating Azure Marketplace call
          type: string

  requestBodies:

    PostAgentDetachBody:
      required: true
      description: Multiple Detach Notification records indicating completion
      content:
        application/json:
          schema:
            type: object
            required:
              - nodes
            properties:
              nodes:
                type: array
                items:
                  $ref: '#/components/schemas/AgentDetachNotification'

  responses:
    UnauthorizedError:
      description: The access token is missing or invalid.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemResponse'
    ForbiddenError:
      description: You don't have permission to access this resource.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemResponse'
    BadRequest:
      description: Invalid request or missing parameters.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemResponse'
    NotFound:
      description: Request content not found.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemResponse'
