openapi: 3.0.1
info:
  title: "Cozify OneAPI"
  version: "1.0"
  termsOfService: https://en.cozify.fi/pages/privacy-policy
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
  description: |-
    This is OpenAPI specification for Cozify ONE platform.

    ### Terminology

    If you are new to Cozify Services, there are some terms you might not be
    familiar with.

    * **resource** - A manageable item that is available through Cozify. Hubs,
    devices and sites are examples of resources. Resource groups, subscriptions
    and tags are also examples of resources.
    * **resource group** - A container that holds related resources for an
    Cozify solution. The resource group includes those resources that you want
    to manage as a group. You decide which resources belong in a resource group
    based on what makes the most sense for your organization.
    * **resource provider** - A service that supplies Cozify resources. For
    example, a common resource provider is `Cozify.Sites`, which supplies the
    structural management of site (aka. Buildings) resource. `Cozify.Devices` is
    another common resource provider.

    ### Receiving events from server using SignalR
    In addition to the REST endpoints described here, there is also SignalR hub for streaming device events and managing event subscriptions at `/hub/v1` endpoint.
    See the following page for more information about SignalR streams and how to use them with a .NET/JavaScript/Java client: [https://learn.microsoft.com/en-us/aspnet/core/signalr/streaming](https://learn.microsoft.com/en-us/aspnet/core/signalr/streaming)

    1. In order to be able to receive events from the hub, **you must open the event stream**, otherwise no events will be delivered regardless of subscriptions:
    - The device events stream name is `DeviceEventsStream`
      - The event type `DeviceEvent` is defined in this OpenApi document
    - For instructions how to use the server-to-client streaming sections [in this article](https://learn.microsoft.com/en-us/aspnet/core/signalr/streaming)

    2. To manage event subscriptions there are the following methods:
    - `DeviceEventsSubscribeAll(string deviceRegisterId)`
      - Subscribe to events from **all** devices in the register
    - `DeviceEventsUnsubscribeAll(string deviceRegisterId)`
      - Unsubscribe from **all** device events from the register
    - `DeviceEventsSubscribe(SubscribeDeviceEvents subscribeRequest)`
      - Subscribe to events from specific devices in the register
      - The `SubscribeDeviceEvents` type is defined in this OpenApi document.
      - **WARNING:** If previously subscribed to **all** events from the same register, this does not change anything; You will still receive events from all devices
    - `DeviceEventsUnsubscribe(UnsubscribeDeviceEvents unsubscribeRequest)`
      - Unsubscribe from specific devices from the register
      - The `UnsubscribeDeviceEvents` type is defined in this OpenApi document.
      - **WARNING:** If previously subscribed to **all** events from the same register, this does not change anything; You will still receive events from all devices
        - Use `DeviceEventsUnsubscribeAll` instead in this case

    ### Note
    > Cozify will only support Transport Layer Security (TLS) 1.2 or later.
  contact:
    email: support@cozify.fi

externalDocs:
  description: Cozify Hub API
  url: https://cozify.github.io/apidocs/hub-apidocs.html

servers:
  - url: https://one.cozify.io

tags:
  - name: Tenants
    description: Tenant commands and querying.

  - name: Subscriptions
    description: Subscriptions commands and querying.

  - name: Resource Groups
    description: Resource groups commands and querying.

  - name: Resources
    description: Resource commands and querying.

  - name: DeviceRegister
    description: Device register operations

  - name: devices templates
    description: Device register template operations

  - name: devices configuration
    description: Device configuration endpoints

  - name: Sites
    description: Site and site entity operations

  - name: sites operations
    description: Special site and entity operations

  - name: site dashboard templates
    description: Site dashboard template operations

security:
  - OAuth2:
      - email

paths:
  /Tenant:
    get:
      summary: GetActiveTenant
      x-deprecated: true
      operationId: GetActiveTenant
      description: |-
        Gets active tenant for current principal.
      tags:
        - Tenants
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tenant"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

    put:
      summary: SetActiveTenant
      x-deprecated: true
      operationId: SetActiveTenant
      description: |-
        Set the currently active tenant for logged in principal.
        When changing the currently active tenant you **must** retrieve new access token and use it
        in order to access resources of that tenant.
      tags:
        - Tenants
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SetCurrentTenant"
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tenant"
        "204":
          description: Operation did not yield any changes
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Tenants:
    get:
      summary: List
      x-deprecated: true
      operationId: ListTenants
      description: |-
        Gets the tenants for your account.
      tags:
        - Tenants
      parameters:
        - $ref: "#/components/parameters/PageSize"
        - $ref: "#/components/parameters/Next"
        - $ref: "#/components/parameters/Prev"
      responses:
        "200":
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TenantsResultPage"
        "400":
          $ref: "#/components/responses/Problem"

    post:
      summary: CreateTenant
      x-internal: true
      x-deprecated: true
      operationId: CreateTenant
      description: |-
        Create tenant details for your account.

        ```
        This is only used internally.
        ```
      tags:
        - Tenants
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTenant"
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tenant"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Tenants/{tenantId}:
    get:
      summary: Get tenant
      x-deprecated: true
      operationId: GetTenant
      description: |-
        Gets an tenant by given id.
      tags:
        - Tenants
      parameters:
        - name: tenantId
          in: path
          schema:
            type: string
          required: true
          description: An tenant id
          example: 2c269807-b266-4b5e-af95-c807d7aca12c
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tenant"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Tenants/{tenantId}/Templates/{templateType}:
    get:
      summary: GetTenantTemplates
      operationId: GetTenantTemplates
      description: |-
        Get all available templates of given type for tenant.
      tags:
        - Tenants
      parameters:
        - name: "tenantId"
          in: "path"
          required: true
          schema:
            type: string
        - name: "templateType"
          in: "path"
          required: true
          schema:
            $ref: "#/components/schemas/TemplateTypes"
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplatesResultPage"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

    post:
      summary: AddTenantTemplate
      operationId: AddTenantTemplate
      description: |-
        This will add template for the tenant.
        Template will be available for all resources owned by the tenant.
      tags:
        - Tenants
      parameters:
        - name: "tenantId"
          in: "path"
          required: true
          schema:
            type: string
        - name: "templateType"
          in: "path"
          required: true
          schema:
            $ref: "#/components/schemas/TemplateTypes"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddTemplate"
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Tenants/{tenantId}/Templates/{templateType}/{templateId}:
    put:
      summary: UpdateTenantTemplate
      operationId: UpdateTenantTemplate
      description: |-
        - This will fully replace the given template.
      tags:
        - Tenants
      parameters:
        - name: "tenantId"
          in: "path"
          required: true
          schema:
            type: string
        - name: "templateId"
          in: "path"
          required: true
          schema:
            type: string
        - name: "templateType"
          in: "path"
          schema:
            $ref: "#/components/schemas/TemplateTypes"
          required: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateTemplate"
        required: true
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

    delete:
      summary: DeleteTenantTemplate
      operationId: DeleteTenantTemplate
      description: |-
        - This will delete given tenant template.
      tags:
        - Tenants
      parameters:
        - name: "tenantId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "templateType"
          in: "path"
          schema:
            $ref: "#/components/schemas/TemplateTypes"
          required: true
        - name: "templateId"
          in: "path"
          required: true
          schema:
            type: string
      responses:
        "204":
          description: Successful operation
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Tenants/{tenantId}/Templates/Device/{deviceType}:
    post:
      summary: AddTenantDeviceTemplate
      operationId: AddTenantDeviceTemplate
      description: |-
        Add device configuration template for device type for tenant.
        This will add device configuration for the tenant.
        Template will be available on all device registers owned by the tenant.
      tags:
        - Tenants
      parameters:
        - name: "tenantId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceType"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddTemplate"
        required: true
      responses:
        "404":
          description: "Tenant not found."
        "401":
          description: "Unauthorized."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"

  /Tenants/{tenantId}/Templates/Device/{deviceType}/{templateId}:
    put:
      summary: UpdateTenantDeviceTemplate
      operationId: UpdateTenantDeviceTemplate
      description: |-
        Update device configuration template for tenant.
        This will fully replace the given template.
      tags:
        - Tenants
      parameters:
        - name: "tenantId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceType"
          in: "path"
          schema:
            type: string
          required: true
        - name: "templateId"
          in: "path"
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateTemplate"
        required: true
      responses:
        "404":
          description: "Tenant or template not found."
        "401":
          description: "Unauthorized."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"

    delete:
      summary: DeleteTenantDeviceTemplate
      operationId: DeleteTenantDeviceTemplate
      description: |-
        Delete device configuration template for tenant
      tags:
        - Tenants
      parameters:
        - name: "tenantId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceType"
          in: "path"
          schema:
            type: string
          required: true
        - name: "templateId"
          in: "path"
          required: true
          schema:
            type: string
      responses:
        "404":
          description: "Tenant or template not found."
        "401":
          description: "Unauthorized."
        "204":
          description: Successful operation

  /Subscriptions:
    get:
      summary: List
      x-deprecated: true
      operationId: ListSubscriptions
      description: |
        Gets the subscriptions for your account.
      tags:
        - Subscriptions
      parameters:
        - $ref: "#/components/parameters/PageSize"
        - $ref: "#/components/parameters/Next"
        - $ref: "#/components/parameters/Prev"
      responses:
        "200":
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionsResultPage"
        "400":
          $ref: "#/components/responses/Problem"

    post:
      summary: Create
      x-deprecated: true
      operationId: CreateSubscription
      description: |
        Create subscription for your account active tenant.
      tags:
        - Subscriptions
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateSubscription"
      responses:
        "200":
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Subscription"
        "400":
          $ref: "#/components/responses/Problem"

  /Subscriptions/{subscriptionId}:
    get:
      summary: Get
      x-deprecated: true
      operationId: GetSubscription
      description: |
        Gets an subscription by given id.
      tags:
        - Subscriptions
      parameters:
        - name: subscriptionId
          in: path
          schema:
            type: string
          required: true
          description: An subscription id
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Subscription"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"
    delete:
      summary: Delete
      x-deprecated: true
      operationId: DeleteSubscription
      description: |
        Delete an subscription by given id.
      tags:
        - Subscriptions
      parameters:
        - name: subscriptionId
          in: path
          schema:
            type: string
          required: true
          description: An subscription id
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
      responses:
        "204":
          description: Successful operation
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Subscriptions/{subscriptionId}/ResourceGroups:
    get:
      summary: List
      x-deprecated: true
      operationId: ListResourceGroups
      description: |
        Gets resource groups in the subscription.
      tags:
        - Resource Groups
      parameters:
        - name: subscriptionId
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/PageSize"
        - $ref: "#/components/parameters/Next"
        - $ref: "#/components/parameters/Prev"
      responses:
        "200":
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResourceGroupsResultPage"
        "400":
          $ref: "#/components/responses/Problem"

    post:
      summary: Create
      x-deprecated: true
      operationId: CreateResourceGroup
      description: |
        Create resource group in the subscription.
      tags:
        - Resource Groups
      parameters:
        - name: subscriptionId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateResourceGroup"
      responses:
        "200":
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResourceGroup"
        "201":
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResourceGroup"
        "400":
          $ref: "#/components/responses/Problem"

  /Subscriptions/{subscriptionId}/ResourceGroups/{resourceGroupName}:
    get:
      summary: Get
      x-deprecated: true
      operationId: GetResourceGroup
      description: |
        Gets an resource group in given subscription.
      tags:
        - Resource Groups
      parameters:
        - name: subscriptionId
          in: path
          schema:
            type: string
          required: true
          description: An subscription id
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
        - name: resourceGroupName
          in: path
          schema:
            type: string
          required: true
          description: An resource group name
          example: west-resources-rg
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResourceGroup"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"
    delete:
      summary: Delete
      x-deprecated: true
      operationId: DeleteResourceGroup
      description: |
        Delete an resource group in given subscription.
      tags:
        - Resource Groups
      parameters:
        - name: subscriptionId
          in: path
          schema:
            type: string
          required: true
          description: An subscription id
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
        - name: resourceGroupName
          in: path
          schema:
            type: string
          required: true
          description: An resource group name
          example: west-resources-rg
      responses:
        "204":
          description: Successful operation
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Subscriptions/{subscriptionId}/ResourceGroups/{resourceGroupName}/Providers:
    post:
      summary: Create
      x-deprecated: true
      operationId: CreateResource
      description: |
        Create resource in given resource group.
      tags:
        - Resources
      parameters:
        - name: subscriptionId
          in: path
          schema:
            type: string
          required: true
          description: An subscription id
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
        - name: resourceGroupName
          in: path
          schema:
            type: string
          required: true
          description: An resource group name
          example: west-resources-rg
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateResource"
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Resource"
        "400":
          $ref: "#/components/responses/Problem"

  ? /Subscriptions/{subscriptionId}/ResourceGroups/{resourceGroupName}/Providers/{resourceProvider}/{resourceName}
  : delete:
      summary: Delete
      x-deprecated: true
      operationId: DeleteResource
      description: |
        Delete resource with given name in resource group.
      tags:
        - Resources
      parameters:
        - name: subscriptionId
          in: path
          schema:
            type: string
          required: true
          description: An subscription id
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
        - name: resourceGroupName
          in: path
          schema:
            type: string
          required: true
          description: An resource group name
          example: west-resources-rg
        - name: resourceProvider
          in: path
          schema:
            type: string
          required: true
          description: An resource group name
          example: west-resources-rg
        - name: resourceName
          in: path
          schema:
            type: string
          required: true
          description: An resource name
          example: my-device-register
      responses:
        "200":
          description: Successful operation
        "400":
          $ref: "#/components/responses/Problem"

  /Subscriptions/{subscriptionId}/ResourceGroups/{resourceGroupName}/Resources:
    get:
      summary: List
      x-deprecated: true
      operationId: ListResources
      description: |
        Gets resource in the resource group.
      tags:
        - Resources
      parameters:
        - name: subscriptionId
          in: path
          required: true
          schema:
            type: string
        - name: resourceGroupName
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/PageSize"
        - $ref: "#/components/parameters/Next"
        - $ref: "#/components/parameters/Prev"
      responses:
        "200":
          description: Successful operation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ResourcesResultPage"
        "400":
          $ref: "#/components/responses/Problem"

  ? /Subscriptions/{subscriptionId}/ResourceGroups/{resourceGroupName}/Resources/{resourceName}
  : get:
      summary: Get
      x-deprecated: true
      operationId: GetResource
      description: |
        Gets an resource in given resource group.
      tags:
        - Resources
      parameters:
        - name: subscriptionId
          in: path
          schema:
            type: string
          required: true
          description: An subscription id
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
        - name: resourceGroupName
          in: path
          schema:
            type: string
          required: true
          description: An resource group name
          example: west-resources-rg
        - name: resourceName
          in: path
          schema:
            type: string
          required: true
          description: An resource name
          example: my-device-register
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Resource"
        "400":
          $ref: "#/components/responses/Problem"
        "404":
          $ref: "#/components/responses/Problem"

  /Providers/Cozify.DeviceRegister/{registerId}/Devices:
    get:
      operationId: ListDevices
      tags:
        - DeviceRegister
      summary: "Get list of devices in the register."
      description: |-
        **Paging**

        The returned results are paged. Default page size is 50 devices.
        This means that to get list all devices it is necessary to retrieve the subsequent result pages.
        This can be done using the `next` cursor that is in `links` property when there are more results available.
        The cursor link contains the endpoint and necessary query parameters.

        **Ordering**

        By default the devices are ordered by `id`. Use the `orderBy` query parameter to change the ordering. Valid values include:
        - name
        - nativeId
        - serialnumber
        - type
        - createdBy
        - modifiedBy

        To have devices ordered in descending order, add `descending` query parameter with value `true`.

        **Search**

        To perform a search/filtering, set value to `search` query parameter.

        **Filter**

        It is also possible to filter the list by specifying value which specific field should contain, in same manner as the `search` query parameter.
        When multiple filters and/or search are specified, the device needs to match ALL of them in order to be returned.
        Possible query parameters include:
        - id
        - name
        - type
        - nativeId
        - serialNumber
        - model
        - manufacturer
        - routing
        - tags (allows multiple parameters, i.e. you can do `&tags=one&tags=two`)
        - capabilities (allows multiple parameters, i.e. you can do `&capabilities=one&capabilities=two`)

      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "pageSize"
          in: "query"
          schema:
            type: integer
            format: int32
          description: "Maximum size of the page. Value must be between 1-2000."
          required: false
          example: 50
        - name: "next"
          in: "query"
          schema:
            type: string
            nullable: true
            default: null
          required: false
          description: "Cursor to get next page of results if there are any."
          example: "ZbXBsZS1kZXZpY2UtMQ"
        - name: "prev"
          in: "query"
          schema:
            type: string
            nullable: true
            default: null
          required: false
          description: "Cursor to get previous page of results if there are any."
          example: "AS1kZXZpY2s"
        - name: "orderBy"
          in: "query"
          required: false
          description: "Name of the field to order devices by."
          schema:
            type: string
          example: "id"
        - name: "descending"
          in: query
          required: false
          example: false
          description: "Set to true to order results in descending order."
          schema:
            type: boolean
        - name: "search"
          in: "query"
          required: false
          description: "Search string that can be used to filter the results. Searches from every field except timestamps. When set, must be at least 3 characters and at most 100."
          schema:
            type: string
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeviceMetadataResultPage"
        "400":
          description: "Bad request. Request body contains invalid data."
    post:
      summary: "Add device to register."
      operationId: RegisterDevice
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegisterDevice"
      responses:
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeviceMetadata"
        "400":
          description: "Bad request. Request body contains invalid data."
        "409":
          description: "Conflict. Device with the ID already exists."

  /Providers/Cozify.DeviceRegister/{registerId}/Devices/{deviceId}:
    get:
      summary: "Get device metadata."
      operationId: GetDeviceMetadata
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeviceMetadata"
    put:
      summary: UpdateDeviceMetadata
      operationId: UpdateDeviceMetadata
      description: "Update device metadata. This will replace existing information."
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateDevice"
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeviceMetadata"

    delete:
      summary: "Remove device from register."
      operationId: DeleteDevice
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register not found."
        "204":
          description: "Device removed from register."

  /Providers/Cozify.DeviceRegister/{registerId}/Devices/{deviceId}/commands:
    post:
      summary: "Send a command to a device."
      operationId: SendDeviceCommand
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "502":
          description: "Could not send command to device: Device is not reachable."
        "202":
          description: Successful operation

  /Providers/Cozify.DeviceRegister/{registerId}/Devices/{deviceId}/execute:
    post:
      summary: "Send a execute command to a device."
      operationId: ExecuteDeviceCommand
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        required: true
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
          application/json:
            schema:
              type: object
      responses:
        "404":
          description: "Register or device not found."
        "502":
          description: "Could not send execute command to device: Device is not reachable."
        "202":
          description: Successful operation

  /Providers/Cozify.DeviceRegister/{registerId}/Devices/{deviceId}/state:
    get:
      summary: "Get latest reported state of a device."
      operationId: GetDeviceState
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: Successful operation

  /Providers/Cozify.DeviceRegister/{registerId}/Hub/Register:
    post:
      operationId: RegisterHubDevice
      summary: "Register Cozify Hub as an gateway device to register."
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegisterHubDevice"
      responses:
        "404":
          description: "Register or hub not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeviceMetadata"

  /Providers/Cozify.DeviceRegister/{registerId}/Hubs/{deviceId}/Restart:
    put:
      operationId: RestartHubDevice
      summary: "Restart Cozify Hub"
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: "Successful operation"

  /Providers/Cozify.DeviceRegister/{registerId}/Hubs/{deviceId}/Reboot:
    put:
      operationId: RebootHubDevice
      summary: "Reboot Cozify Hub"
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: "Successful operation"

  /Providers/Cozify.DeviceRegister/{registerId}/Hubs/{deviceId}/Users:
    get:
      operationId: GetUsersHubDevice
      summary: "Get Cozify Hub users"
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetUsersHubDeviceResponse"

    post:
      operationId: InviteUserHubDevice
      summary: "Invite user to Cozify Hub"
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InviteHubUserRequest"
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HubUserModel"

  /Providers/Cozify.DeviceRegister/{registerId}/Hubs/{deviceId}/Users/{userId}:
    get:
      operationId: GetUserHubDevice
      summary: "Get Cozify Hub user"
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "userId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HubUserModel"

    delete:
      operationId: RevokeUserHubDevice
      summary: "Revoke Cozify Hub user"
      tags:
        - DeviceRegister
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "userId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or device not found."
        "200":
          description: "Successful operation"

  /Providers/Cozify.DeviceRegister/{registerId}/Templates/Device:
    get:
      operationId: GetTenantDeviceTemplates
      summary: "Get all available device templates for all device types"
      tags:
        - DeviceRegister templates
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or templates not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplatesResultPage"

  /Providers/Cozify.DeviceRegister/{registerId}/Templates/Device/{deviceType}:
    get:
      operationId: GetTenantDeviceTemplatesForType
      summary: "Get templates for device type"
      tags:
        - DeviceRegister templates
      parameters:
        - name: "registerId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "deviceType"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Register or templates not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplateCollection"

  ? /Providers/Cozify.DeviceRegister/{registerId}/Devices/{deviceId}/Configuration
  : get:
      operationId: GetDeviceConfiguration
      summary: "Get device configuration"
      tags:
        - DeviceRegister configuration
      parameters:
        - name: "registerId"
          in: "path"
          required: true
          schema:
            type: string
        - name: "deviceId"
          in: "path"
          required: true
          schema:
            type: string
      responses:
        "404":
          description: "Not found"
        "503":
          description: "Internal error"
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                type: object
                description: "Device configuration JSON"
                additionalProperties: true
    post:
      operationId: SetDeviceConfiguration
      summary: "Update device configuration"
      tags:
        - DeviceRegister configuration
      parameters:
        - name: "registerId"
          in: "path"
          required: true
          schema:
            type: string
        - name: "deviceId"
          in: "path"
          required: true
          schema:
            type: string
      requestBody:
        description: "Configuration value to set for device"
        required: true
        content:
          application/json:
            schema:
              type: object
              description: "Any JSON object"
              additionalProperties: true
      responses:
        "404":
          description: "Not found"
        "503":
          description: "Internal error"
        "200":
          description: Successful operation

  # Cozify.Sites

  /Providers/Cozify.Sites/Site/{siteId}:
    get:
      operationId: GetSite
      summary: "Get site metadata."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Site not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Site"
    patch:
      operationId: UpdateSite
      tags:
        - Sites
      summary: "Update site. This is partial update."
      description: |-
        - This is a partial update. Only content in the request will be updated.
        - To remove an attribute, set it's `value` field to `null`.
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateSite"
        required: true
      responses:
        "404":
          description: "Site not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Site"

  /Providers/Cozify.Sites/Site/{siteId}/{globPattern}:
    get:
      operationId: QuerySiteEntities
      tags:
        - Sites
      summary: "Find entities in the site."
      description: |-
        **TIPS:**
        - To get single entity, set the `globPattern` parameter to entity path.
          - For example `building/1` (get building 1)
        - To find multiple entities, set the `glob` to be a glob.
          - For example `++/area` (get all areas)
        - To get all entities of a site, use `*`

        **NOTE:** The results are paged.
        To get next page of results use the `next` cursor in the response when it is not null.
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "globPattern"
          in: "path"
          schema:
            type: string
          required: true
          example: "building/1/floor/a"
        - name: "pageSize"
          in: "query"
          schema:
            type: integer
            format: int32
          description: "Maximum size of the page. Value must be between 1-2000."
          required: false
          example: 50
        - name: "next"
          in: "query"
          schema:
            type: string
            nullable: true
            default: null
          required: false
          description: "Cursor to get next page of results if there are any."
          example: "ZXBsZS1kZXZpY2UtMQ"
        - name: "prev"
          in: "query"
          schema:
            type: string
            nullable: true
            default: null
          required: false
          description: "Cursor to get previous page of results if there are any."
          example: "ZS1kZXZpY2"
      responses:
        "404":
          description: "Site not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteEntityResultPage"

    post:
      operationId: CreateSiteEntity
      tags:
        - Sites
      summary: "Create new site entity under the current resource."
      description: |-
        - The parent entity must exist.
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "globPattern"
          in: "path"
          required: true
          schema:
            type: string
          example: "building/1"
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateSiteEntity"
            examples:
              Add new entity:
                description: "Add new entity"
                value:
                  type: "building"
                  name: "1"
              Add device from register:
                description: "How to add device that exists in the device register as a device entity to a site."
                value:
                  type: "device"
                  name: "my-entity-name"
                  attributes:
                    - name: "deviceid"
                      value: "id-of-the-device-in-register"
      responses:
        "404":
          description: "Site not found."
        "400":
          description: "Bad request. For example parent does not exist, or request body contains invalid data."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Site"

    patch:
      operationId: PatchSiteEntity
      tags:
        - Sites
      summary: "Update site entity."
      description: |-
        - This is a partial update. Only content in the request will be updated.
        - To remove an attribute, set it's `value` field to `null`.
        - Entity can only be moved when:
          - It does not have child entities
          - The new parent entity exists
          - Entity with the _would be_ new path does not exist before the move
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "globPattern"
          in: "path"
          schema:
            type: string
          required: true
          example: "building/1/floor/a/area/2"
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateSiteEntity"
      responses:
        "404":
          description: "Site or entity not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Site"

    delete:
      operationId: DeleteSiteEntity
      summary: "Delete site entity"
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "globPattern"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Site not found."
        "204":
          description: "Entity removed successfully."

  /Providers/Cozify.Sites/Properties/{siteId}:
    get:
      operationId: GetSiteProperties
      summary: "Get site properties."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Site not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteProperties"

    put:
      operationId: UpdateSiteProperties
      tags:
        - Sites
      summary: "Update site properties. This is full update."
      description: |-
        - This is full update. All properties will be replaced.
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SiteProperties"
        required: true
      responses:
        "404":
          description: "Site not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteProperties"

  /Providers/Cozify.Sites/Schema/{siteId}:
    get:
      operationId: GetSiteSchema
      summary: "Get site schema used for validating the site structure."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          required: true
          schema:
            type: string
      responses:
        "404":
          description: "Site not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteDefinition"

    put:
      operationId: SetSiteSchema
      tags:
        - Sites
      summary: "Replace existing site schema."
      description: |-
        - This will replace any existing site schema. The schema is used to validate changes made to the site and it's entities.
        - When there are attributes defined that have `typeSchemaName` set, the schemas **must** contain the JSON schema used to validate the attribute.
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SiteDefinition"
      responses:
        "404":
          description: "Site not found."
        "400":
          description: "Invalid schema."
        "409":
          description: "Site does not pass validation with the new schema definition"
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteDefinition"

  # Cozify Sites Egress

  /Providers/Cozify.Sites/Egress/{siteId}:
    get:
      deprecated: true
      operationId: ListSiteEgressTargets
      summary: "Get site events egress targets."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "next"
          in: "query"
          schema:
            type: string
            nullable: true
            default: null
          required: false
          description: "Cursor to get next page of results if there are any."
          example: "ZbXBsZS1kZXZpY2UtMQ"
        - name: "prev"
          in: "query"
          schema:
            type: string
            nullable: true
            default: null
          required: false
          description: "Cursor to get previous page of results if there are any."
          example: "AssZS1kZXZpY2s"
      responses:
        "404":
          description: "Site not found"
        "400":
          description: "Bad request"
        "200":
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteEgressResultPage"

    post:
      deprecated: true
      operationId: CreateSiteEgressTarget
      summary: "Create site events egress target."
      description: "This endpoint accepts any egress target as long as the type discriminator is used."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SiteEgressTarget"
      responses:
        "404":
          description: "Site not found"
        "400":
          description: "Bad request"
        "200":
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteEgressTarget"

    put:
      deprecated: true
      operationId: UpdateSiteEgressTarget
      summary: "Update existing site events egress target."
      description: "This endpoint accepts any egress target as long as the type discriminator is used and matches the existing target."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/schemas/SiteEgressTarget"
      responses:
        "404":
          description: "Site not found."
        "400":
          description: "Bad request"
        "200":
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteEgressTarget"

  /Providers/Cozify.Sites/Egress/{siteId}/{targetId}:
    delete:
      deprecated: true
      operationId: DeleteSiteEgressTarget
      summary: "Delete site events egress target."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "targetId"
          in: "path"
          required: true
          schema:
            type: string
      responses:
        "404":
          description: "Site not found."
        "200":
          description: "Successful operation"

    get:
      deprecated: true
      operationId: GetSiteEgressTarget
      summary: "Get site event egress targets."
      tags:
        - Sites
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
          example: customer-site-1
        - name: "targetId"
          in: "path"
          required: true
          schema:
            type: string
          example: monitor
      responses:
        default:
          description: "Unexpected error"
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "404":
          description: "Site not found."
        "400":
          description: "Bad request"
        "200":
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SiteEgressTarget"

  /Providers/Cozify.Sites/Templates/{siteId}/{templateType}:
    get:
      operationId: GetSiteTemplates
      summary: "Get all available templates for site"
      tags:
        - site dashboard templates
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "templateType"
          in: "path"
          description: "Only 'schema' and 'dashboard' are valid options for site."
          schema:
            $ref: "#/components/schemas/TemplateTypes"
          required: true
      responses:
        "404":
          description: "Site or templates not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TemplatesResultPage"

  /Providers/Cozify.Sites/Templates/{siteId}/{templateType}/{templateId}:
    get:
      operationId: GetSiteTemplate
      summary: "Get template"
      tags:
        - site dashboard templates
      parameters:
        - name: "siteId"
          in: "path"
          schema:
            type: string
          required: true
        - name: "templateType"
          in: "path"
          description: "Only 'schema' and 'dashboard' are valid options for site."
          schema:
            $ref: "#/components/schemas/TemplateTypes"
          required: true
        - name: "templateId"
          in: "path"
          schema:
            type: string
          required: true
      responses:
        "404":
          description: "Site or template not found."
        "200":
          description: Successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Template"

components:
  schemas:
    Tenant:
      type: object
      additionalProperties: false
      properties:
        id:
          type: string
          example: /Tenant/2c269807-b266-4b5e-af95-c807d7aca12c
        tenantId:
          type: string
          example: 2c269807-b266-4b5e-af95-c807d7aca12c
        displayName:
          type: string
          example: My Company Ab
      required:
        - id
        - tenantId

    Problem:
      type: object
      description: The Problem Details JSON Object [[RFC7807](https://tools.ietf.org/html/rfc7807)].
      minProperties: 1
      additionalProperties: true
      properties:
        type:
          type: string
          description: A URI reference [[RFC3986](https://tools.ietf.org/html/rfc3986)] that identifies the problem type.
          format: uri
          example: https://www.rfc-editor.org/rfc/rfc7807
        title:
          type: string
          description: A short, human-readable summary of the problem type.
          example: Example error happened.
        status:
          type: integer
          description: The HTTP status code.
          minimum: 400
          maximum: 599
        detail:
          type: string
          description: A human-readable explanation specific to this occurrence of the problem.
          example: Example error happened for request.
        instance:
          type: string
          description: A URI reference that identifies the specific occurrence of the problem.
          example: /some/Resource

    TenantsResultPage:
      type: object
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Tenant"
        links:
          $ref: "#/components/schemas/ResultPageLinks"
      required:
        - data

    DisplayName:
      type: string
      minLength: 1
      maxLength: 50
      example: West wing

    CreateTenant:
      type: object
      additionalProperties: false
      properties:
        displayName:
          $ref: "#/components/schemas/DisplayName"
      required:
        - displayName

    Subscription:
      type: object
      additionalProperties: false
      properties:
        id:
          type: string
          example: /Subscriptions/ae3fc088-3446-4d93-b105-d18700a2dac3
        subscriptionId:
          type: string
          example: ae3fc088-3446-4d93-b105-d18700a2dac3
        displayName:
          type: string
          example: West wing
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - id
        - subscriptionId

    SubscriptionsResultPage:
      type: object
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Subscription"
        links:
          $ref: "#/components/schemas/ResultPageLinks"
      required:
        - data

    CreateSubscription:
      type: object
      additionalProperties: false
      properties:
        displayName:
          $ref: "#/components/schemas/DisplayName"
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - displayName

    ResourceGroup:
      type: object
      additionalProperties: false
      properties:
        id:
          type: string
          example: /Subscriptions/ae3fc088-3446-4d93-b105-d18700a2dac3/ResourceGroups/west-resources-rg
        name:
          type: string
          example: west-resources-rg
        location:
          type: string
          example: eu-north-1
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - id
        - name
        - location

    ResourceGroupsResultPage:
      type: object
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ResourceGroup"
        links:
          $ref: "#/components/schemas/ResultPageLinks"
      required:
        - data

    CreateResourceGroup:
      type: object
      additionalProperties: false
      properties:
        name:
          type: string
          minLength: 3
          maxLength: 50
          example: west-resources-rg
        location:
          type: string
          example: eu-north-1
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - name
        - location

    CreateResource:
      type: object
      x-abstract: true
      additionalProperties: false
      discriminator:
        propertyName: provider
        mapping:
          Cozify.Sites: "#/components/schemas/CreateSiteResource"
          Cozify.DeviceRegister: "#/components/schemas/CreateDeviceRegisterResource"
      properties:
        name:
          type: string
          minLength: 3
          maxLength: 50
          example: device-register
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - type
        - name

    CreateSiteResource:
      allOf:
        - type: object
          additionalProperties: false
          properties:
            init:
              $ref: "#/components/schemas/CreateSite"
          required:
            - init
        - $ref: "#/components/schemas/CreateResource"

    CreateDeviceRegisterResource:
      allOf:
        - type: object
          additionalProperties: false
          properties:
            init:
              $ref: "#/components/schemas/CreateDeviceRegister"
          required:
            - init
        - $ref: "#/components/schemas/CreateResource"

    SiteType:
      type: object
      x-abstract: true
      description: Base type for site types
      additionalProperties: false
      discriminator:
        propertyName: type
        mapping:
          unknown: "#/components/schemas/UnknownSiteType"
          hub: "#/components/schemas/HubSiteType"
          knx: "#/components/schemas/KnxSiteType"

    UnknownSiteType:
      allOf:
        - $ref: "#/components/schemas/SiteType"
        - type: object
          additionalProperties: false

    HubSiteType:
      allOf:
        - $ref: "#/components/schemas/SiteType"
        - type: object
          additionalProperties: false

    KnxSiteType:
      allOf:
        - $ref: "#/components/schemas/SiteType"
        - type: object
          additionalProperties: false
          properties:
            awaySceneSave:
              type: boolean

    SiteFeature:
      type: object
      additionalProperties: false
      properties:
        enabled:
          type: boolean
          description: Is feature enabled
          default: false

    DeviceRegisterSiteFeature:
      allOf:
        - $ref: "#/components/schemas/SiteFeature"
        - type: object
          additionalProperties: false
          properties:
            registerId:
              type: string
              pattern: ^([a-z0-9-_]){3,50}$
              description: Device register id
              maxLength: 50
              minLength: 3
            generateDeviceName:
              type: boolean
              description: Generate device name from register id
              default: false
            generateGatewayChildDevicesEnabled:
              type: boolean
              description: Generate gateway child devices
              default: false
            forceGenerateChildDevicesAtRoot:
              type: boolean
              description: Force generate child devices at root only
              default: false

    SiteFeatures:
      type: object
      additionalProperties: false
      description: Features enabled for the site.
      properties:
        consumptionHistory:
          $ref: "#/components/schemas/SiteFeature"
        conditionsHistory:
          $ref: "#/components/schemas/SiteFeature"
        compareWater:
          $ref: "#/components/schemas/SiteFeature"
        compareElectricity:
          $ref: "#/components/schemas/SiteFeature"
        deviceRegister:
          $ref: "#/components/schemas/DeviceRegisterSiteFeature"
        siteEvents:
          $ref: "#/components/schemas/SiteFeature"

    SiteProperties:
      type: object
      additionalProperties: false
      properties:
        siteType:
          $ref: "#/components/schemas/SiteType"
        timeZone:
          type: string
          description: Time zone of the site in TZ format.
          example: Europe/Helsinki
        features:
          $ref: "#/components/schemas/SiteFeatures"

    AttributeTypeDefinition:
      type: string
      description: Attribute type definition
      enum:
        - string
        - boolean
        - number
        - json
      example: string

    AttributeDefinition:
      type: object
      additionalProperties: false
      description: Defines an attribute. Asterisk in name indicates that any attributes of the specific type are allowed.
      properties:
        name:
          type: string
          example: displayName
        type:
          $ref: "#/components/schemas/AttributeTypeDefinition"
        isRequired:
          type: boolean
          default: false
      required:
        - name
        - type

    EntityDefinition:
      type: object
      additionalProperties: false
      description: Defines an entity. Asterisk in type indicates that custom entity types are allowed.
      properties:
        type:
          type: string
          example: stair
        scopes:
          type: array
          description: Defines where in the site structure entity can be created. This is a glob.
          example:
            - /building/+
        attributes:
          type: array
          description: Attributes the entity can or should have. When empty no attributes are allowed for the entity. To allow arbitrary attributes define wildcard attributes with asterisk.
          items:
            $ref: "#/components/schemas/AttributeDefinition"
      required:
        - type
        - scopes
        - attributes

    SiteDefinition:
      type: object
      additionalProperties: false
      description: Defines a site.
      properties:
        attributes:
          type: array
          description: Attributes the site can or must have. When empty no attributes are allowed. To allow arbitrary attributes define wildcard attributes with asterisk.
          items:
            $ref: "#/components/schemas/AttributeDefinition"
        entities:
          type: array
          description: Entities which can be added to the site.
          items:
            $ref: "#/components/schemas/EntityDefinition"

    SiteAttributes:
      type: array
      description: Any of the attribute values inheriting from AttributeValue
      default: null
      nullable: true
      items:
        anyOf:
          - $ref: "#/components/schemas/StringAttributeValue"
          - $ref: "#/components/schemas/LongAttributeValue"
          - $ref: "#/components/schemas/IntAttributeValue"
          - $ref: "#/components/schemas/DoubleAttributeValue"
          - $ref: "#/components/schemas/BooleanAttributeValue"
          - $ref: "#/components/schemas/JsonAttributeValue"

    CreateSite:
      type: object
      additionalProperties: false
      properties:
        displayName:
          type: string
          pattern: ^([a-z0-9-_]){3,50}$
          minLength: 3
          maxLength: 50
        properties:
          $ref: "#/components/schemas/SiteProperties"
        definition:
          $ref: "#/components/schemas/SiteDefinition"
        attributes:
          $ref: "#/components/schemas/SiteAttributes"

    CreateDeviceRegister:
      type: object
      additionalProperties: false

    Resource:
      type: object
      additionalProperties: false
      properties:
        id:
          type: string
          example: /Subscriptions/ae3fc088-3446-4d93-b105-d18700a2dac3/ResourceGroups/west-resources-rg/Providers/Cozify.DeviceRegister/my-device-register
        name:
          type: string
          example: my-device-register
        type:
          type: string
          example: Cozify.DeviceRegister
        location:
          type: string
          example: eu-north-1
        displayName:
          type: string
          example: My devices
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - id
        - name
        - type
        - location

    ResourcesResultPage:
      type: object
      additionalProperties: false
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/Resource"
        links:
          $ref: "#/components/schemas/ResultPageLinks"
      required:
        - data

    Tags:
      type: object
      additionalProperties:
        type: string
        maxLength: 100
      description: "The collection of tags"
      example:
        env: "dev"

    ResultPageLinks:
      type: object
      additionalProperties: false
      properties:
        next:
          type: string
          nullable: true
          default: null
          description: "Link for retrieving next page of results. Null if there are no more results."
        prev:
          type: string
          nullable: true
          default: null
          description: "Link for retrieving previous page of results. Null if there is no previous results."

    AttributeValue:
      type: object
      description: "Base type for other AttributeValues"
      properties:
        name:
          type: string
          description: "Name of the attribute."
          example: "displayName"
          pattern: "^([a-zd)]+((d)|([A-Z0-9-_.][a-z0-9]+))*){2,50}$"

    StringAttributeValue:
      allOf:
        - $ref: "#/components/schemas/AttributeValue"
        - type: object
          properties:
            value:
              type: string
              description: "String attribute value. Setting the value to null will remove the attribute if it exists."

    DoubleAttributeValue:
      allOf:
        - $ref: "#/components/schemas/AttributeValue"
        - type: object
          properties:
            value:
              type: number
              format: double
              description: "Double attribute value"

    IntAttributeValue:
      allOf:
        - $ref: "#/components/schemas/AttributeValue"
        - type: object
          properties:
            value:
              type: integer
              format: int32
              description: "Integer attribute value"

    LongAttributeValue:
      allOf:
        - $ref: "#/components/schemas/AttributeValue"
        - type: object
          properties:
            value:
              type: integer
              format: int64
              description: "Integer attribute value"

    BooleanAttributeValue:
      allOf:
        - $ref: "#/components/schemas/AttributeValue"
        - type: object
          properties:
            value:
              type: boolean
              description: "Boolean attribute value"

    JsonAttributeValue:
      allOf:
        - $ref: "#/components/schemas/AttributeValue"
        - type: object
          properties:
            value:
              type: object
              description: "Json data attribute value"

    SetCurrentTenant:
      properties:
        tenantId:
          type: string
          minLength: 1
          maxLength: 50
          example: "abcdefgh-1234-5678-9834-73661824c1bc"
      required:
        - tenantId

    DeviceMetadataResultPage:
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DeviceMetadata"
        links:
          $ref: "#/components/schemas/ResultPageLinks"

    DeviceRoutingInfo:
      type: object
      additionalProperties: false
      description: "Describes proxy which handles routing commands for the device."
      properties:
        hubId:
          type: string
          nullable: true
          default: null
          description: "Cozify hub id"
        deviceId:
          type: string
          nullable: true
          default: null
          description: "Id of another device in the register"

    DeviceMetadata:
      type: object
      additionalProperties: false
      properties:
        id:
          type: string
          description: "Device id"
          example: "ec83e906-2ea7-4bd8-8d61-75196761c3eb"
        isActive:
          type: boolean
          description: "Determines is an device active or disabled for a"
          example: true
        name:
          type: string
          description: "Device name"
          example: "Device 12345"
        type:
          type: string
          description: "Type of the device for display purpose."
          example: "COZIFY_HUB"
        capabilities:
          type: array
          items:
            type: string
        createdAt:
          type: integer
          format: int64
          description: "Unix timestamp in milliseconds"
          example: 1600255801000
        modifiedAt:
          type: integer
          format: int64
          description: "Unix timestamp in milliseconds"
          example: 1663327801000
        routing:
          anyOf:
            - $ref: "#/components/schemas/DeviceRoutingInfo"
        nativeId:
          type: string
          description: "Native ID of the device"
          example: "EXAMPLE_2_1_00035536"
          default: ""
        serialNumber:
          type: string
          maxLength: 100
          description: "Serial number of the device"
          default: ""
        model:
          type: string
          maxLength: 100
          description: "Model of the device"
          default: ""
        manufacturer:
          type: string
          maxLength: 100
          description: "Manufacturer of the device"
          default: ""
        tags:
          $ref: "#/components/schemas/Tags"

    RegisterDevice:
      type: object
      additionalProperties: false
      properties:
        id:
          type: string
          description: "Device id."
          example: "ec83e906-2ea7-4bd8-8d61-75196761c3eb"
          pattern: "^([a-z0-9-_])+$"
          maxLength: 50
          minLength: 3
        name:
          type: string
          description: Device name
          example: "Device 12345"
          maxLength: 100
        type:
          type: string
          description: Type of the device for display purpose.
          example: COZIFY_HUB
        capabilities:
          type: array
          description: An list of capabilities of the device.
          items:
            type: string
            description: Capability of the device. See DeviceCapabilityEnum for good known values.
            example: COZIFY_HUB
        routing:
          anyOf:
            - $ref: "#/components/schemas/DeviceRoutingInfo"
        nativeId:
          type: string
          maxLength: 100
          description: "Native ID of the device"
          example: "EXAMPLE_2_1_00035536"
          default: ""
        serialNumber:
          type: string
          maxLength: 100
          description: "Serial number of the device"
          default: ""
        model:
          type: string
          maxLength: 100
          description: "Model of the device"
          default: ""
        manufacturer:
          type: string
          maxLength: 100
          description: "Manufacturer of the device"
          default: ""
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - id
        - name

    RegisterHubDevice:
      type: object
      additionalProperties: false
      properties:
        serialNumber:
          type: string
          minLength: 2
          maxLength: 100
          description: "Serial number of the Hub device"
          example: "20021212-X-0202"
        name:
          type: string
          description: "Device name"
          minLength: 3
          maxLength: 100
          example: "Hub 0202"
        model:
          type: string
          maxLength: 100
          description: "Model of the device"
          default: ""
        manufacturer:
          type: string
          maxLength: 100
          description: "Manufacturer of the device"
          default: ""
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - serialNumber

    UpdateDevice:
      type: object
      additionalProperties: false
      properties:
        name:
          type: string
          description: "Device name"
          example: "Device 12345"
          maxLength: 100
        capabilities:
          type: array
          description: An list of capabilities of the device.
          items:
            type: string
            description: Capability of the device. See DeviceCapabilityEnum for good known values.
            example: COZIFY_HUB
        routing:
          type: object
          description: "Routing information for commands"
          anyOf:
            - $ref: "#/components/schemas/DeviceRoutingInfo"
          nullable: true
        nativeId:
          type: string
          maxLength: 100
          description: "Native ID of the device"
          example: "EXAMPLE_2_1_00035536"
          default: ""
        serialNumber:
          type: string
          maxLength: 100
          description: "Serial number of the device"
          default: ""
        model:
          type: string
          maxLength: 100
          description: "Model of the device"
          default: ""
        manufacturer:
          type: string
          maxLength: 100
          description: "Manufacturer of the device"
          default: ""
        tags:
          $ref: "#/components/schemas/Tags"
      required:
        - name

    GetUsersHubDeviceResponse:
      type: object
      additionalProperties: false
      description: "Response model of Cozify Hub users"
      properties:
        users:
          type: array
          items:
            $ref: "#/components/schemas/HubUserModel"

    HubUserModel:
      type: object
      additionalProperties: false
      properties:
        userId:
          type: string
          description: "User Id"
          example: "fbb836df-b52d-4e77-a89d-1a36a403b2e4"
          maxLength: 36
        email:
          type: string
          description: "Email address"
          example: "mail@example.com"
          maxLength: 256
        role:
          type: string
          description: "One of the known values: OWNER, ADMIN, USER, REMOTEGUEST, GUEST, ANONYMOUS"
          example: "ADMIN"
          maxLength: 64

    InviteHubUserRequest:
      type: object
      additionalProperties: false
      properties:
        email:
          type: string
          description: "Email address"
          example: "mail@example.com"
          maxLength: 256
        role:
          type: string
          description: "One of the known values: OWNER, ADMIN, USER, REMOTEGUEST, GUEST, ANONYMOUS"
          example: "ADMIN"
          maxLength: 64

    SiteEntityResultPage:
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/SiteEntity"
        links:
          $ref: "#/components/schemas/ResultPageLinks"

    Site:
      type: object
      additionalProperties: false
      properties:
        displayName:
          type: string
          maxLength: 50
          example: My Site
        createdAt:
          type: integer
          format: int64
          description: "Unix timestamp in milliseconds"
          example: 1600255801000
        modifiedAt:
          type: integer
          format: int64
          description: "Unix timestamp in milliseconds"
          example: 1663327801000
        attributes:
          $ref: "#/components/schemas/SiteAttributes"

    UpdateSite:
      type: object
      additionalProperties: false
      description: "Updated site information."
      properties:
        displayName:
          type: string
          maxLength: 50
          example: My Site
        attributes:
          $ref: "#/components/schemas/SiteAttributes"
      required:
        - attributes

    SiteEgressResultPage:
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/SiteEgressTarget"
        links:
          $ref: "#/components/schemas/ResultPageLinks"

    SiteEgressTarget:
      description: "Site events egress target"
      type: object
      additionalProperties: false
      properties:
        $type:
          description: "A discriminator to identify the type of egress target."
          type: string
          example: rest
        id:
          description: "A unique identifier for this specific egress configuration at the site. The identifier must be between 3 and 50 characters in length and consist only of alphanumeric characters (no special characters or spaces)."
          type: string
          pattern: "^[a-zA-Z0-9]+$"
          minLength: 3
          maxLength: 50
          example: monitor
        isEnabled:
          description: "Indicates whether the egress target is enabled. If false, events will not be sent to the target."
          type: boolean
          default: true
        fetchMaxEvents:
          description: "The maximum number of events to include in each batch sent to the target URL. Must be between 1 and 10000."
          type: integer
          minimum: 1
          maximum: 10000
          default: 10
        fetchWaitMaxMs:
          description: "The maximum amount of time in milliseconds to wait before sending a batch of events, even if the batch size has not been reached. Must be between 2 ms and 60000 ms."
          type: integer
          minimum: 2
          maximum: 60000
          default: 10
      discriminator:
        propertyName: $type
        mapping:
          rest: "#/components/schemas/RestSiteEgressTarget"
          dummy: "#/components/schemas/DummySiteEgressTarget"
      required:
        - $type
        - id

    DummySiteEgressTarget:
      type: object
      additionalProperties: false
      allOf:
        - $ref: "#/components/schemas/SiteEgressTarget"
      properties:
        dummy:
          type: string

    RestSiteEgressTarget:
      description: "Represents the configuration for sending batches of site events to a specified REST endpoint."
      type: object
      additionalProperties: false
      allOf:
        - $ref: "#/components/schemas/SiteEgressTarget"
      properties:
        url:
          description: "The URL of the REST endpoint to which event batches will be sent."
          type: string
        method:
          description: "The HTTP method (POST or PUT) used to send the event batch to the target URL."
          type: string
          enum:
            - POST
            - PUT
          default: POST
        headers:
          description: "A collection of HTTP headers to be included in each request to the target URL."
          type: object
          additionalProperties:
            type: string
        serverScript:
          description: "JavaScript code to be executed on the server for filtering or manipulating events before they are sent in the request."
          type: string
          default: null
          nullable: true
        requestTimeoutSeconds:
          description: "The timeout for the HTTP request in seconds. Must be between 1 and 60 seconds."
          type: number
          format: double
          minimum: 1
          maximum: 60
          default: null
          nullable: true
      required:
        - url
        - method

    SiteEntity:
      type: object
      additionalProperties: false
      properties:
        siteEntityId:
          type: string
          description: "Id assigned for the entity."
          example: "ec83e906-2ea7-4bd8-8d61-75196761c3eb"
        path:
          type: string
          description: "Full path to the entity in the site which can be used to access it."
          example: "/building/1/floor/a"
        type:
          type: string
          pattern: "^([a-z0-9-_])+$"
          example: area
          minLength: 1
          maxLength: 50
        name:
          type: string
          example: "a"
        displayName:
          type: string
          maxLength: 50
          example: My Beautiful Entity
        createdAt:
          type: integer
          format: int64
          description: "Unix timestamp in milliseconds"
          example: 1600255801000
        modifiedAt:
          type: integer
          format: int64
          description: "Unix timestamp in milliseconds"
          example: 1663327801000
        attributes:
          $ref: "#/components/schemas/SiteAttributes"

    CreateSiteEntity:
      type: object
      additionalProperties: false
      description: "Create site entity."
      properties:
        type:
          type: string
          pattern: "^([a-z0-9-_])+$"
          example: area
          minLength: 1
          maxLength: 50
        name:
          type: string
          pattern: "^([a-z0-9-_])+$"
          example: "a"
          minLength: 1
          maxLength: 50
        displayName:
          type: string
          maxLength: 50
          example: My Beautiful Entity
        attributes:
          $ref: "#/components/schemas/SiteAttributes"

    UpdateSiteEntity:
      type: object
      additionalProperties: false
      description: "Updated site entity."
      properties:
        displayName:
          type: string
          maxLength: 50
          example: My Beautiful Entity
        attributes:
          $ref: "#/components/schemas/SiteAttributes"
        changeParentPath:
          type: string
          nullable: true
          default: null
          description: "Move the entity under this parent path. The parent must exist. Only set this value if you intend to move the entity in the site."

    TemplateTypes:
      type: string
      enum:
        - device
        - dashboard
        - schema

    Template:
      properties:
        id:
          type: string
          minimum: 1
          maximum: 100
          example: "my-unique-template-id"
          pattern: "^([a-z0-9-_])+$"
        name:
          type: string
          minimum: 1
          maximum: 100
          example: "ZEN"
        content:
          type: object
          description: "Template content. Expects a JSON object."
          example:
            ENABLED: false

    TemplateCollection:
      properties:
        type:
          type: string
          example: "COZIFY_HUB"
          description: |
            Template type/category.
            - For device configuration templates this could be device type such as "COZIFY_HUB" or "WATER_METER".
            - For dashboards this would be simply "DASHBOARD".
        defaultTemplateId:
          type: string
          description: Id of the template that should be considered default template. When empty string, no default has been defined.
          default: ""
        templates:
          type: array
          items:
            $ref: "#/components/schemas/Template"

    TemplatesResultPage:
      type: array
      items:
        $ref: "#/components/schemas/TemplateCollection"

    AddTemplate:
      properties:
        id:
          type: string
          minimum: 1
          maximum: 100
          example: "my-unique-template-id"
          pattern: "^([a-z0-9-_])+$"
        displayName:
          type: string
          minimum: 1
          maximum: 100
          example: "My template"
        content:
          type: object
          description: Template content. Expects a JSON object.
        setAsDefault:
          type: boolean
          description: Set the template as default for the template type.
          default: false

    UpdateTemplate:
      properties:
        displayName:
          type: string
          minimum: 1
          maximum: 100
          example: "Renamed template"
        content:
          type: object
          description: Template content. Expects a JSON object.
        setAsDefault:
          type: boolean
          description: Set the template as default for the template type.

  parameters:
    PageSize:
      name: pageSize
      in: query
      schema:
        type: integer
        format: int32
      description: Maximum size of the page. Value must be between 1-2000.
      example: 50
    Next:
      name: next
      in: query
      schema:
        type: string
      description: Cursor to get next page of results if there are any.
      example: ZbXBsZS1kZXZpY2UtMQ
    Prev:
      name: prev
      in: query
      schema:
        type: string
      description: Cursor to get previous page of results if there are any.
      example: ASDsZS1kZXZpY2Us

  responses:
    Problem:
      description: Problem
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"

  securitySchemes:
    Bearer:
      type: http
      scheme: bearer
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://login.cozify.fi/auth/realms/cozify/protocol/openid-connect/auth
          tokenUrl: https://login.cozify.fi/auth/realms/cozify/protocol/openid-connect/token
          scopes:
            email: Grants access to your email
