openapi: 3.1.0
info:
  title: Users Service API
  version: '1.165.1'
  description: Public API endpoints for the users service
  license:
    name: Proprietary
    url: https://stonal.com
servers:
  - url: https://api.stonal.io/users
    description: Production environment
  - url: https://api-{stack}.stonal.io/users
    description: Custom stack production environment
    variables:
      stack:
        description: Custom stack name
        default: demo
  - url: https://api.stonal-staging.io/users
    description: Staging environment
paths:
  /v2/organizations/{organizationCode}/users:
    get:
      summary: Get paginated users
      description: |
        > [!important]
        > Required permission scope: `stonal.user.read`

        Returns a paginated list of users for the specified organization
      operationId: getUsersPaginated
      tags:
        - Users
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: q
          in: query
          schema:
            type: string
          description: Search query to filter users
          example: john
        - name: permissions
          in: query
          schema:
            type: string
          description: List of permissions to filter users
          example: PROFILE:Administrator,SCOPE_GROUP:All
        - name: userGroups
          in: query
          schema:
            type: string
          description: Comma-separated list of user group labels to filter users. Use \, to escape literal commas in labels.
          example: Administrators,Readers
        - name: pageNumber
          in: query
          required: true
          schema:
            type: integer
            minimum: 1
          description: Page number for pagination
          example: 1
        - name: pageSize
          in: query
          required: true
          schema:
            type: integer
            minimum: 1
            maximum: 100
          description: Number of items per page
          example: 20
        - name: sortField
          in: query
          schema:
            type: string
          description: Field to sort by
          example: email
        - name: sortDirection
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
          description: Sort direction
          example: asc
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserPageResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
    post:
      summary: Create user
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Creates a new user
      operationId: createUser
      tags:
        - Users
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertUserRequest'
      security:
        - BearerAuth: []
      responses:
        '200':
          description: User successfully created or updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v2/organizations/{organizationCode}/users/{uid}:
    get:
      summary: Get user by UID
      description: |
        > [!important]
        > Required permission scope: `stonal.user.read`

        Returns details for a specific user
      operationId: getUserByUID
      tags:
        - Users
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: uid
          in: path
          required: true
          schema:
            type: string
          description: UID of the user
          example: 5dbbc53c-1a22-4f6f-883c-74c04fe905f5
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
    put:
      summary: Update user
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Updates an existing user in the organization
      operationId: updateUser
      tags:
        - Users
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: uid
          in: path
          required: true
          schema:
            type: string
          description: UID of the user
          example: 5dbbc53c-1a22-4f6f-883c-74c04fe905f5
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertUserRequest'
      security:
        - BearerAuth: []
      responses:
        '200':
          description: User successfully updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      summary: Delete user
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Deletes an existing user in the organization
      operationId: deleteUser
      tags:
        - Users
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: uid
          in: path
          required: true
          schema:
            type: string
          description: UID of the user
          example: 5dbbc53c-1a22-4f6f-883c-74c04fe905f5
      security:
        - BearerAuth: []
      responses:
        '204':
          description: User successfully deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v1/organizations/{organizationCode}/groups:
    get:
      summary: Get groups
      description: |
        > [!important]
        > Required permission scope: `stonal.user.read`

        Returns paginated groups for a given organization
      operationId: getGroups
      tags:
        - Groups
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: pageNumber
          in: query
          required: true
          schema:
            type: integer
            minimum: 1
          description: Page number for pagination
          example: 1
        - name: pageSize
          in: query
          required: true
          schema:
            type: integer
            minimum: 1
            maximum: 100
          description: Number of items per page
          example: 20
        - name: sortField
          in: query
          schema:
            type: string
          description: Field to sort by
          example: label
        - name: sortDirection
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
          description: Sort direction
          example: asc
        - name: uids
          in: query
          schema:
            type: array
            items:
              type: string
              format: uuid
          description: Filter by group UUIDs
          example:
            - 019619df-4768-76b3-8ab3-4414dcf29ff1
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupPageResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
    post:
      summary: Create a group
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Creates a new group in the organization
      operationId: createGroup
      tags:
        - Groups
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GroupRequest'
      security:
        - BearerAuth: []
      responses:
        '201':
          description: Group successfully created
        '204':
          description: Group already exists
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v1/organizations/{organizationCode}/groups/{uuid}:
    put:
      summary: Update a group
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Updates an existing group in the organization
      operationId: updateGroup
      tags:
        - Groups
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: uuid
          in: path
          required: true
          schema:
            type: string
          description: UUID of the group to update
          example: 019619df-4768-76b3-8ab3-4414dcf29ff1
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GroupRequest'
      security:
        - BearerAuth: []
      responses:
        '204':
          description: Group successfully updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
    delete:
      summary: Delete a group
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Deletes an existing group from the organization
      operationId: deleteGroup
      tags:
        - Groups
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: uuid
          in: path
          required: true
          schema:
            type: string
          description: UUID of the group to delete
          example: 019619df-4768-76b3-8ab3-4414dcf29ff1
      security:
        - BearerAuth: []
      responses:
        '204':
          description: Group successfully deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v1/organizations/{organizationCode}/permissions:
    get:
      summary: Get permissions
      description: |
        > [!important]
        > Required permission scope: `stonal.user.read`

        Returns paginated permissions for a given organization
      operationId: getPermissions
      tags:
        - Permissions
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: pageNumber
          in: query
          required: true
          schema:
            type: integer
            minimum: 1
          description: Page number for pagination
          example: 1
        - name: pageSize
          in: query
          required: true
          schema:
            type: integer
            minimum: 1
            maximum: 100
          description: Number of items per page
          example: 20
        - name: sortField
          in: query
          schema:
            type: string
          description: Field to sort by
          example: label
        - name: sortDirection
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
          description: Sort direction
          example: asc
        - name: type
          in: query
          schema:
            type: string
          description: |
            Filter by permission type. Can be a single value or comma-separated list of values.
            Possible values: ASSET, PROFILE, SCOPE, SCOPE_GROUP, REPORT, REPORT_GROUP
          example: ASSET,PROFILE
        - name: subType
          in: query
          schema:
            type: string
          description: |
            Filter by permission subtype. Can be a single value or comma-separated list of values.
            Possible values: BUILDING, BUILDING_GROUP, FACILITY, PORTFOLIO, COMPANY, APPLICATION, RIGHT
          example: PORTFOLIO,BUILDING
        - name: uids
          in: query
          schema:
            type: string
          description: Comma-separated list of permission UIDs to filter by
          example: uid1,uid2,uid3
        - name: parentUids
          in: query
          schema:
            type: string
          description: Comma-separated list of parent permission UIDs to filter by. Returns permissions that are children of the specified parent permissions (permissions whose codes match assets, reports, or scopes linked to the parents)
          example: parent-uid1,parent-uid2
        - name: level
          in: query
          schema:
            type: integer
            minimum: 0
          description: Filter permissions by their hierarchical level. Level 0 represents root permissions (permissions without parents), level 1 represents direct children of root permissions, level 2 represents grandchildren, and so on. When filtering by parentUids, only returns children at the specified level relative to the parent
          example: 0
        - name: q
          in: query
          schema:
            type: string
          description: Search query to filter permissions
          example: building
        - name: withUsers
          in: query
          schema:
            type: boolean
          description: Include users associated with permissions
          example: true
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PermissionPageResult'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
    post:
      summary: Create or update permission
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Creates a new permission or updates an existing one
      operationId: createPermission
      tags:
        - Permissions
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertPermissionRequest'
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Permission successfully created or updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
  /v1/organizations/{organizationCode}/permissions/{uid}:
    delete:
      summary: Delete a permission
      description: |
        > [!important]
        > Required permission scope: `stonal.user.write`

        Deletes an existing permission

        Please note that you can only delete permissions of type `SCOPE_GROUP` and `PROFILE`.
      operationId: deletePermission
      tags:
        - Permissions
      parameters:
        - name: organizationCode
          in: path
          required: true
          schema:
            type: string
          description: Code of the organization
          example: DEMO
        - name: uid
          in: path
          required: true
          schema:
            type: string
          description: UID of the permission
          example: 5dbbc53c-1a22-4f6f-883c-74c04fe905f5
      security:
        - BearerAuth: []
      responses:
        '204':
          description: Permission successfully deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Token
  schemas:
    UserGroupResult:
      type: object
      properties:
        uid:
          type: string
          description: Unique identifier of the user group
          examples:
            - 019619df-4768-76b7-81e3-2c56d374df46
        label:
          type: string
          description: Display label of the user group
          examples:
            - Marketing
      required:
        - uid
        - label
    UserResult:
      type: object
      properties:
        uid:
          type: string
          description: Unique identifier of the user
          examples:
            - 019619df-4768-7af9-8167-18ad0b73a399
        email:
          type: string
          format: email
          description: Email address of the user
          examples:
            - john.doe@example.com
        firstName:
          type: string
          description: First name of the user
          examples:
            - John
        lastName:
          type: string
          description: Last name of the user
          examples:
            - Doe
        role:
          type: string
          description: Role of the user
          examples:
            - MEMBER
          enum:
            - ADMIN
            - MEMBER
        allAssets:
          type: boolean
          description: Whether the user has access to all assets
          examples:
            - false
        createdAt:
          type: string
          format: date-time
          description: Date and time when the user was created
          examples:
            - '2025-06-15T10:30:00Z'
        userGroups:
          type: array
          items:
            $ref: '#/components/schemas/UserGroupResult'
          description: Groups the user belongs to
        permissions:
          type: object
          additionalProperties: true
          description: Map of user permissions by type
          examples:
            - ASSET:
                PORTFOLIO:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a63cf3431c1
                  code: b362b8cd-e105-41db-b131-0911fa559aee
                  label: Alpha
                COMPANY:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a63cf3431c2
                  code: stonal
                  label: Stonal
                BUILDING:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a63cf3431c3
                  code: b362b8cd-e105-41db-b131-0911fa559aef
                  label: B01 - Marseille
                BUILDING_GROUP:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a63cf3431c4
                  code: b362b8cd-e105-41db-b131-0911fa559aea
                  label: S01 - Marseille
                FACILITY:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a63cf3431c5
                  code: b362b8cd-e105-41db-b131-0911fa559aeb
                  label: F01 - Marseille
              PROFILE:
                uid: 0bb04f5b-bf5e-4950-acb1-0a3cf3431c6
                code: acquereur
                label: Acquéreur
              SCOPE:
                RIGHT:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a3cf3431c7
                  code: stonal.asset.all
                  label: Access to all assets
              SCOPE_GROUP:
                APPLICATION:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a3cf3431c8
                  code: b362b8cd-e105-41db-b131-0911fa559aec
                  label: All
                RIGHT:
                  uid: 0bb04f5b-bf5e-4950-acb1-0a3cf3431c9
                  code: stonal.read-write
                  label: Read write
              REPORT:
                uid: 0bb04f5b-bf5e-4950-acb1-0a3cf3431ca
                code: 019837df-ab1d-7d13-956f-a4233f0b95a1
                label: FICHE BATIMENT & SITE
              REPORT_GROUP:
                uid: 0bb04f5b-bf5e-4950-acb1-0a3cf3431cb
                code: 75cb735c-7335-42c7-a27f-c26be904c5ed
                label: Admin
      required:
        - uid
        - email
        - firstName
        - lastName
        - role
        - allAssets
        - createdAt
        - userGroups
    UserPageResult:
      type: object
      properties:
        total:
          type: integer
          description: Total number of items
          examples:
            - 42
        result:
          type: array
          items:
            $ref: '#/components/schemas/UserResult'
          description: Array of user items
      required:
        - total
        - result
    UserPermissionParams:
      type: object
      properties:
        uid:
          type: string
          description: UID of the permission
          examples:
            - 019619df-4767-730f-8d31-143712a08141
      required:
        - uid
    UpsertUserRequest:
      type: object
      properties:
        email:
          type: string
          format: email
          description: Email address of the user
          examples:
            - john.doe@example.com
        firstName:
          type: string
          description: First name of the user
          examples:
            - John
        lastName:
          type: string
          description: Last name of the user
          examples:
            - Doe
        uid:
          type: string
          description: Unique identifier of the user (for updates)
          examples:
            - 019619df-4768-76b7-81e3-2c56d374df46
        password:
          type: string
          format: password
          description: Password for the user
          examples:
            - SecureP@ssw0rd!
        fromExternalIdp:
          type: boolean
          description: Whether the user is from an external identity provider
          examples:
            - false
        allAssets:
          type: boolean
          description: Whether the user has access to all assets
          examples:
            - false
        userGroupUids:
          type: array
          items:
            type: string
          description: UIDs of user groups the user belongs to
          examples:
            - - 019619df-4768-76b7-81e3-2c56d374df46
              - 019619df-4768-7b28-ae66-afbee5b857ab
        permissions:
          type: array
          items:
            $ref: '#/components/schemas/UserPermissionParams'
          description: Permissions assigned to the user
      required:
        - email
        - firstName
        - lastName
    GroupResult:
      type: object
      properties:
        uid:
          type: string
          description: Unique identifier of the group
          examples:
            - 019619df-4768-76b3-8ab3-4414dcf29ff1
        label:
          type: string
          description: Display label of the group
          examples:
            - Project Managers
        permissions:
          type: object
          description: Map of permission types to permission details
          additionalProperties:
            type: object
            additionalProperties:
              type: object
              properties:
                label:
                  type: string
                  description: Label of the permission
                  examples:
                    - Building A
                uid:
                  type: string
                  description: UID of the permission
                  examples:
                    - 019619df-4768-76b3-8ab3-4414dcf29ff1
        users:
          type: object
          properties:
            count:
              type: integer
              description: Number of users in the group
              examples:
                - 12
          required:
            - count
      required:
        - uid
        - label
        - permissions
        - users
    GroupPageResult:
      type: object
      properties:
        total:
          type: integer
          description: Total number of items
          examples:
            - 15
        result:
          type: array
          items:
            $ref: '#/components/schemas/GroupResult'
          description: Array of group items
      required:
        - total
        - result
    GroupRequest:
      type: object
      properties:
        label:
          type: string
          description: Display label of the group
          examples:
            - Project Managers
        permissions:
          type: array
          items:
            type: object
            properties:
              uid:
                type: string
                description: UID of the permission to assign to the group
                examples:
                  - 019619df-4768-76b3-8ab3-4414dcf29ff1
            required:
              - uid
      required:
        - label
    PermissionMetadataLogo:
      type: object
      properties:
        format:
          type: string
          description: Format of the logo
          examples:
            - SVG
        resource:
          type: string
          description: Resource of the logo
          examples:
            - <svg></svg>
    ReportThematic:
      type: object
      properties:
        uid:
          type: string
          description: Unique identifier of the thematic
          examples:
            - 550e8400-e29b-41d4-a716-446655440000
        names:
          type: object
          additionalProperties:
            type: string
          description: Localized names of the thematic (locale as key, name as value)
          examples:
            - en-GB: Environmental Sustainability
              fr-FR: Durabilité Environnementale
        order:
          type: integer
          description: Display order of the thematic
          examples:
            - 1
      required:
        - uid
        - names
        - order
    PermissionMetadata:
      type: object
      properties:
        url:
          type: string
          description: URL of the resource held by this permission
          examples:
            - https://example.com
        logo:
          $ref: '#/components/schemas/PermissionMetadataLogo'
        thematic:
          $ref: '#/components/schemas/ReportThematic'
        assetCode:
          type: string
          description: Asset ERP code associated with this permission (for ASSET type permissions)
          examples:
            - ASSET-001
    PermissionChildrenResult:
      type: object
      properties:
        count:
          type: integer
          description: Total number of children
          examples:
            - 5
        uids:
          type: array
          items:
            type: string
          description: UIDs of child permissions
          examples:
            - - 019619df-4767-730f-8d31-143712a08141
              - 019619df-4768-75e4-a334-cde454b9e9e1
      required:
        - count
        - uids
    PermissionUsersResult:
      type: object
      properties:
        count:
          type: integer
          description: Total number of users
          examples:
            - 3
      required:
        - count
    PermissionResult:
      type: object
      properties:
        uid:
          type: string
          description: Unique identifier of the permission
          examples:
            - 019619df-4768-76b3-8ab3-4414dcf29ff1
        type:
          type: string
          description: Type of the permission
          enum:
            - ASSET
            - PROFILE
            - SCOPE
            - SCOPE_GROUP
            - REPORT
            - REPORT_GROUP
          examples:
            - ASSET
        subType:
          type: string
          description: Subtype of the permission
          enum:
            - BUILDING
            - BUILDING_GROUP
            - FACILITY
            - PORTFOLIO
            - COMPANY
            - APPLICATION
            - RIGHT
            - POWERBI
            - METABASE
          examples:
            - PORTFOLIO
        code:
          type: string
          description: Code of the permission
          examples:
            - portfolio-123
        label:
          type: string
          description: Display label of the permission
          examples:
            - Alpha Portfolio
        description:
          type: string
          description: Description of the permission
          examples:
            - The Alpha Portfolio of buildings
        metadata:
          $ref: '#/components/schemas/PermissionMetadata'
        children:
          $ref: '#/components/schemas/PermissionChildrenResult'
        users:
          $ref: '#/components/schemas/PermissionUsersResult'
      required:
        - uid
        - type
        - code
        - label
        - metadata
        - children
    PermissionPageResult:
      type: object
      properties:
        total:
          type: integer
          description: Total number of items
          examples:
            - 42
        result:
          type: array
          items:
            $ref: '#/components/schemas/PermissionResult'
          description: Array of permission items
      required:
        - total
        - result
    UpsertPermissionScopeRequest:
      type: object
      properties:
        code:
          type: string
          description: Code of the permission scope
          examples:
            - stonal.application.etl
            - stonal.application.check
      required:
        - code
    UpsertPermissionReportRequest:
      type: object
      properties:
        uid:
          type: string
          description: UID of the report to associate with this permission
          examples:
            - 550e8400-e29b-41d4-a716-446655440000
      required:
        - uid
    UpsertPermissionRequest:
      type: object
      properties:
        uid:
          type: string
          description: Unique identifier of the permission (optional for create, used for update identification)
          examples:
            - 019619df-4768-76b3-8ab3-4414dcf29ff1
        code:
          type: string
          description: Code of the permission
          examples:
            - portfolio-123
        type:
          type: string
          description: Type of the permission
          enum:
            - ASSET
            - PROFILE
            - SCOPE
            - SCOPE_GROUP
            - REPORT
            - REPORT_GROUP
          examples:
            - ASSET
        subType:
          type: string
          description: Subtype of the permission
          enum:
            - BUILDING
            - BUILDING_GROUP
            - FACILITY
            - PORTFOLIO
            - COMPANY
            - APPLICATION
            - RIGHT
            - POWERBI
            - METABASE
          examples:
            - PORTFOLIO
        label:
          type: string
          description: Display label of the permission
          examples:
            - Alpha Portfolio
        description:
          type: string
          description: Description of the permission
          examples:
            - The Alpha Portfolio of buildings
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/UpsertPermissionScopeRequest'
          description: Scopes associated with this permission
        reports:
          type: array
          items:
            $ref: '#/components/schemas/UpsertPermissionReportRequest'
          description: Reports associated with this permission
      required:
        - code
        - type
        - label
  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                description: Error type identifier
                examples:
                  - tag:InvalidBody
                  - tag:InvalidContentType
              title:
                type: string
                description: Human readable error title
                examples:
                  - Invalid request
              detail:
                type: string
                description: Human readable error description
                examples:
                  - Request body is invalid
            required:
              - type
              - title
              - detail
    Unauthorized:
      description: Unauthorized - Missing authentication
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                description: Error type identifier
                examples:
                  - tag:Unauthenticated
              title:
                type: string
                description: Human readable error title
                examples:
                  - Missing authentication
                  - Token expired
              detail:
                type: string
                description: Human readable error description
                examples:
                  - Please authenticate yourself
                  - The provided authentication token is expired, please generate a new one
            required:
              - type
              - title
              - detail
    Forbidden:
      description: Forbidden - Access denied
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                description: Error type identifier
                examples:
                  - tag:ForbiddenAccess
              title:
                type: string
                description: Human readable error title
                examples:
                  - Access denied
              detail:
                type: string
                description: Human readable error description
                examples:
                  - You do not have permission to access this resource
            required:
              - type
              - title
              - detail
    UnprocessableEntity:
      description: Unprocessable Entity - Validation errors
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                description: Error type identifier
                examples:
                  - tag:ValidationError
              title:
                type: string
                description: Human readable error title
                examples:
                  - Invalid request
              errors:
                type: array
                description: List of validation errors
                items:
                  type: object
                  properties:
                    field:
                      type: string
                      description: Field name that failed validation
                      examples:
                        - email
                        - username
                    detail:
                      type: string
                      description: Error description for the field
                      examples:
                        - Email is required
                        - Username must be at least 3 characters
                  required:
                    - field
                    - detail
            required:
              - type
              - title
              - errors
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                description: Error type identifier
                examples:
                  - tag:InternalError
              title:
                type: string
                description: Human readable error title
                examples:
                  - Internal server error
              detail:
                type: string
                description: Human readable error description
                examples:
                  - An unexpected error occurred
            required:
              - type
              - title
              - detail
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                description: Error type identifier
                examples:
                  - tag:ResourceNotFound
              title:
                type: string
                description: Human readable error title
                examples:
                  - User not found
                  - Group not found
              detail:
                type: string
                description: Human readable error description
                examples:
                  - The requested user does not exist
                  - The requested group does not exist
              resource:
                type: string
                description: Resource identifier
                examples:
                  - users/user-123
                  - groups/group-456
            required:
              - type
              - title
              - detail
              - resource
    Conflict:
      description: Conflict - Resource conflict
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                description: Error type identifier
                examples:
                  - tag:DeletionConflict
                  - tag:ResourceConflict
              title:
                type: string
                description: Human readable error title
                examples:
                  - User cannot self delete
                  - Resource already exists
              detail:
                type: string
                description: Human readable error description
                examples:
                  - You cannot delete yourself
                  - A resource with this identifier already exists
            required:
              - type
              - title
              - detail
