# Auto-generated from specs/routes.yaml
# DO NOT EDIT — regenerate with: make generate
openapi: 3.1.0
info:
  title: Chirp Public API
  version: 1.0.0
  description: 'Public API for the Chirp IoT platform.


    ## Authentication


    All endpoints require API key authentication:


    | Header | Description |

    |--------|-------------|

    | `X-API-Key` | Your API key (format: `chirp_<key>`) |

    | `X-Organization-Id` | Your organization UUID |


    ## Protocols


    This API exposes two types of endpoints:


    - **REST** — standard HTTP methods (GET, POST, PUT, DELETE). Use REST for cloud
    and SaaS integrations.

    - **gRPC** — available via gRPC clients; intended for on-premises deployments.
    Documented here as POST endpoints at their gRPC path for reference.


    If you are unsure which protocol to use, **choose REST** unless you are running
    an on-premises installation.


    ## Scopes


    API keys are scoped. Each endpoint lists its required scope (e.g. `devices:read`).
    Requests with insufficient scopes receive a `403 Forbidden` response.

    '
servers:
- url: https://api.chirpwireless.io
  description: Chirp API
security:
- ApiKeyAuth: []
  OrgId: []
tags:
- name: Users
- name: Devices
- name: Sensors
- name: Commands
- name: Telemetry
- name: Connections
- name: Connectors
- name: Dashboards
- name: Orgs
- name: Subscriptions
- name: Api-Keys
- name: Rules
- name: User Profile (gRPC)
  description: gRPC service `userprofile.UserProfileService` — use a gRPC client to
    call these methods.
- name: Digital Device (gRPC)
  description: gRPC service `digitaldevice.v2.DigitalDeviceService` — use a gRPC client
    to call these methods.
- name: Sensor Template (gRPC)
  description: gRPC service `sensor_template.v2.SensorTemplateService` — use a gRPC
    client to call these methods.
- name: Connector (gRPC)
  description: gRPC service `connector.ConnectorService` — use a gRPC client to call
    these methods.
- name: Connection (gRPC)
  description: gRPC service `connection.ConnectionService` — use a gRPC client to
    call these methods.
- name: Dashboard (gRPC)
  description: gRPC service `dashboard.v2.DashboardService` — use a gRPC client to
    call these methods.
- name: Widget (gRPC)
  description: gRPC service `widget.v2.WidgetService` — use a gRPC client to call
    these methods.
- name: Actuator Command (gRPC)
  description: gRPC service `actuator_command.v2.ActuatorCommandService` — use a gRPC
    client to call these methods.
- name: Sensor Query (gRPC)
  description: gRPC service `sensorquery.v1.SensorQueryService` — use a gRPC client
    to call these methods.
- name: Organizations (gRPC)
  description: gRPC service `OrganizationsService` — use a gRPC client to call these
    methods.
- name: Access Control (gRPC)
  description: gRPC service `organization_access_control.AccessControlService` — use
    a gRPC client to call these methods.
paths:
  /api/users/personal:
    get:
      operationId: getPersonalUser
      summary: Get personal user profile
      description: 'Retrieve the authenticated user''s profile information.


        **Required scope:** `users:read`'
      tags:
      - Users
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /api/v2/devices:
    get:
      operationId: listDigitalDevices
      summary: List digital devices
      description: 'Retrieve all digital devices for the organization.


        **Required scope:** `devices:read`'
      tags:
      - Devices
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  devices:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        organizationId:
                          type: string
                        lastSeen:
                          type: string
                        physicalDevice:
                          type: object
                          properties:
                            id:
                              type: string
                            clientDeviceId:
                              type: string
                            connectionId:
                              type: string
                        sensors:
                          type: array
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                              sensorTemplateId:
                                type: string
                        createdAt:
                          type: string
                        updatedAt:
                          type: string
                  total:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: limit
        in: query
        required: false
        description: Number of items per page
        schema:
          type: integer
      - name: offset
        in: query
        required: false
        description: Number of items to skip
        schema:
          type: integer
      - name: search
        in: query
        required: false
        description: Search by device name
        schema:
          type: string
    post:
      operationId: createDigitalDevice
      summary: Create digital device
      description: 'Provision a new digital device with optional sensor attachment.


        **Required scope:** `devices:write`'
      tags:
      - Devices
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  organizationId:
                    type: string
                  physicalDevice:
                    type: object
                    properties:
                      id:
                        type: string
                      clientDeviceId:
                        type: string
                      connectionId:
                        type: string
                      configuration:
                        type: object
                      createdAt:
                        type: string
                      updatedAt:
                        type: string
                  sensors:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        sensorTemplateId:
                          type: string
                        createdAt:
                          type: string
                        updatedAt:
                          type: string
                  images:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        filename:
                          type: string
                        contentType:
                          type: string
                        url:
                          type: string
                        isCover:
                          type: boolean
                        position:
                          type: integer
                        sizeBytes:
                          type: integer
                        createdAt:
                          type: string
                  createdAt:
                    type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Device name
                physicalDevice:
                  type: object
                  description: Physical device configuration (required for physical
                    devices)
                  properties:
                    clientDeviceId:
                      type: string
                      description: Client device ID (e.g. DevEUI for LoRaWAN)
                    connectionId:
                      type: string
                      description: Connection ID to bind this device to
                    configuration:
                      type: object
                      description: Connection-specific configuration (e.g. LoRaWAN
                        keys)
                      additionalProperties: true
                  required:
                  - clientDeviceId
                  - connectionId
                images:
                  type: array
                  description: Media attachments for the device
                  items:
                    type: object
                    properties:
                      mediaId:
                        type: string
                        example: 550e8400-e29b-41d4-a716-446655440000
                      isCover:
                        type: boolean
                        example: false
                      position:
                        type: integer
                        example: 0
                    required:
                    - mediaId
              required:
              - name
  /api/v2/devices/{id}:
    get:
      operationId: getDigitalDevice
      summary: Get digital device
      description: 'Retrieve a single device by ID.


        **Required scope:** `devices:read`'
      tags:
      - Devices
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
    patch:
      operationId: updateDigitalDevice
      summary: Update digital device
      description: 'Update device properties (name, connection, config).


        **Required scope:** `devices:write`'
      tags:
      - Devices
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                physicalDevice:
                  type: object
                  properties:
                    clientDeviceId:
                      type: string
                    connectionId:
                      type: string
                    configuration:
                      type: object
                      additionalProperties: true
    delete:
      operationId: deleteDigitalDevice
      summary: Delete digital device
      description: 'Delete a device by ID.


        **Required scope:** `devices:write`'
      tags:
      - Devices
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/devices/{id}/connector-keys:
    get:
      operationId: getConnectorKeys
      summary: Get connector keys
      description: 'Retrieve connector keys for a device.


        **Required scope:** `devices:read`'
      tags:
      - Devices
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  connectorKeys:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                        timestamp:
                          type: integer
                        value:
                          type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: connectionId
        in: query
        required: true
        description: Connection ID
        schema:
          type: string
      - name: clientDeviceId
        in: query
        required: true
        description: Client Device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/devices/{id}/sensors:
    post:
      operationId: addSensorsToDevice
      summary: Add sensors to device
      description: 'Attach sensors to a device by template IDs.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  dataSendingInterval:
                    type: object
                    properties:
                      unit:
                        type: string
                        enum: &id001
                        - minute
                        - hour
                        - day
                        - week
                        - month
                        example: minute
                      value:
                        type: integer
                        example: 60
                  id:
                    type: string
                  images:
                    type: array
                    items:
                      type: object
                      properties:
                        contentType:
                          type: string
                          example: image/jpeg
                        createdAt:
                          type: string
                          example: '2026-01-02T15:04:05Z'
                        filename:
                          type: string
                          example: device-photo.jpg
                        id:
                          type: string
                          example: 550e8400-e29b-41d4-a716-446655440000
                        isCover:
                          type: boolean
                          example: false
                        position:
                          type: integer
                          example: 0
                        sizeBytes:
                          type: integer
                          example: 123456
                        url:
                          type: string
                          example: https://media.example.com/v1/media/{id}
                  lastSeen:
                    type: string
                  name:
                    type: string
                  organizationId:
                    type: string
                  physicalDevice:
                    type: object
                    properties:
                      clientDeviceId:
                        type: string
                      configuration:
                        type: object
                      connectionId:
                        type: string
                      createdAt:
                        type: string
                      id:
                        type: string
                      sensorMappings:
                        type: array
                        items:
                          type: object
                          properties:
                            createdAt:
                              type: object
                            id:
                              type: object
                            sensorId:
                              type: object
                            sourcePath:
                              type: object
                            updatedAt:
                              type: object
                      updatedAt:
                        type: string
                  sensors:
                    type: array
                    items:
                      type: object
                      properties:
                        createdAt:
                          type: string
                        id:
                          type: string
                        sensorTemplateId:
                          type: string
                        updatedAt:
                          type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                sensorTemplateIds:
                  type: array
                  items:
                    type: string
              required:
              - sensorTemplateIds
    delete:
      operationId: removeSensorsFromDevice
      summary: Remove sensors from device
      description: 'Detach sensors from a device.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  dataSendingInterval:
                    type: object
                    properties:
                      unit:
                        type: string
                        enum: *id001
                        example: minute
                      value:
                        type: integer
                        example: 60
                  id:
                    type: string
                  images:
                    type: array
                    items:
                      type: object
                      properties:
                        contentType:
                          type: string
                          example: image/jpeg
                        createdAt:
                          type: string
                          example: '2026-01-02T15:04:05Z'
                        filename:
                          type: string
                          example: device-photo.jpg
                        id:
                          type: string
                          example: 550e8400-e29b-41d4-a716-446655440000
                        isCover:
                          type: boolean
                          example: false
                        position:
                          type: integer
                          example: 0
                        sizeBytes:
                          type: integer
                          example: 123456
                        url:
                          type: string
                          example: https://media.example.com/v1/media/{id}
                  lastSeen:
                    type: string
                  name:
                    type: string
                  organizationId:
                    type: string
                  physicalDevice:
                    type: object
                    properties:
                      clientDeviceId:
                        type: string
                      configuration:
                        type: object
                      connectionId:
                        type: string
                      createdAt:
                        type: string
                      id:
                        type: string
                      sensorMappings:
                        type: array
                        items:
                          type: object
                          properties:
                            createdAt:
                              type: object
                            id:
                              type: object
                            sensorId:
                              type: object
                            sourcePath:
                              type: object
                            updatedAt:
                              type: object
                      updatedAt:
                        type: string
                  sensors:
                    type: array
                    items:
                      type: object
                      properties:
                        createdAt:
                          type: string
                        id:
                          type: string
                        sensorTemplateId:
                          type: string
                        updatedAt:
                          type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                sensorIds:
                  type: array
                  items:
                    type: string
              required:
              - sensorIds
  /api/v2/devices/{id}/sensors/{sensorId}:
    patch:
      operationId: updateDeviceSensor
      summary: Update device sensor
      description: 'Update a sensor attached to a device.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  dataSendingInterval:
                    type: object
                    properties:
                      unit:
                        type: string
                        enum: *id001
                        example: minute
                      value:
                        type: integer
                        example: 60
                  id:
                    type: string
                  images:
                    type: array
                    items:
                      type: object
                      properties:
                        contentType:
                          type: string
                          example: image/jpeg
                        createdAt:
                          type: string
                          example: '2026-01-02T15:04:05Z'
                        filename:
                          type: string
                          example: device-photo.jpg
                        id:
                          type: string
                          example: 550e8400-e29b-41d4-a716-446655440000
                        isCover:
                          type: boolean
                          example: false
                        position:
                          type: integer
                          example: 0
                        sizeBytes:
                          type: integer
                          example: 123456
                        url:
                          type: string
                          example: https://media.example.com/v1/media/{id}
                  lastSeen:
                    type: string
                  name:
                    type: string
                  organizationId:
                    type: string
                  physicalDevice:
                    type: object
                    properties:
                      clientDeviceId:
                        type: string
                      configuration:
                        type: object
                      connectionId:
                        type: string
                      createdAt:
                        type: string
                      id:
                        type: string
                      sensorMappings:
                        type: array
                        items:
                          type: object
                          properties:
                            createdAt:
                              type: object
                            id:
                              type: object
                            sensorId:
                              type: object
                            sourcePath:
                              type: object
                            updatedAt:
                              type: object
                      updatedAt:
                        type: string
                  sensors:
                    type: array
                    items:
                      type: object
                      properties:
                        createdAt:
                          type: string
                        id:
                          type: string
                        sensorTemplateId:
                          type: string
                        updatedAt:
                          type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: sensorId
        in: path
        required: true
        description: Sensor ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                sensorTemplateId:
                  type: string
              required:
              - sensorTemplateId
  /api/v2/devices/{id}/sensor-mappings:
    put:
      operationId: setSensorMappings
      summary: Set sensor mappings
      description: 'Configure sensor-to-source-path mappings for a device.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  dataSendingInterval:
                    type: object
                    properties:
                      unit:
                        type: string
                        enum: *id001
                        example: minute
                      value:
                        type: integer
                        example: 60
                  id:
                    type: string
                  images:
                    type: array
                    items:
                      type: object
                      properties:
                        contentType:
                          type: string
                          example: image/jpeg
                        createdAt:
                          type: string
                          example: '2026-01-02T15:04:05Z'
                        filename:
                          type: string
                          example: device-photo.jpg
                        id:
                          type: string
                          example: 550e8400-e29b-41d4-a716-446655440000
                        isCover:
                          type: boolean
                          example: false
                        position:
                          type: integer
                          example: 0
                        sizeBytes:
                          type: integer
                          example: 123456
                        url:
                          type: string
                          example: https://media.example.com/v1/media/{id}
                  lastSeen:
                    type: string
                  name:
                    type: string
                  organizationId:
                    type: string
                  physicalDevice:
                    type: object
                    properties:
                      clientDeviceId:
                        type: string
                      configuration:
                        type: object
                      connectionId:
                        type: string
                      createdAt:
                        type: string
                      id:
                        type: string
                      sensorMappings:
                        type: array
                        items:
                          type: object
                          properties:
                            createdAt:
                              type: object
                            id:
                              type: object
                            sensorId:
                              type: object
                            sourcePath:
                              type: object
                            updatedAt:
                              type: object
                      updatedAt:
                        type: string
                  sensors:
                    type: array
                    items:
                      type: object
                      properties:
                        createdAt:
                          type: string
                        id:
                          type: string
                        sensorTemplateId:
                          type: string
                        updatedAt:
                          type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                mappings:
                  type: array
                  items:
                    type: object
                    properties:
                      sensorId:
                        type: string
                      sourcePath:
                        type: string
                    required:
                    - sensorId
                    - sourcePath
              required:
              - mappings
  /api/v2/device-profile-template:
    get:
      operationId: getDeviceProfileTemplate
      summary: Get device profile template
      description: 'Look up a LoRaWAN device profile by brand, model, and band.


        **Required scope:** `devices:read`'
      tags:
      - Devices
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  codec:
                    type: string
                  description:
                    type: string
                  deviceStatusReqInterval:
                    type: integer
                  flushQueueOnActivate:
                    type: boolean
                  id:
                    type: string
                  macVersion:
                    type: string
                  name:
                    type: string
                  payloadCodecRuntime:
                    type: string
                  regParamsRevision:
                    type: string
                  region:
                    type: string
                  supportsClassB:
                    type: boolean
                  supportsClassC:
                    type: boolean
                  supportsOtaa:
                    type: boolean
                  uplinkInterval:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: brand
        in: query
        required: true
        description: Device brand (e.g., dragino)
        schema:
          type: string
      - name: model
        in: query
        required: true
        description: Device model (e.g., lht65)
        schema:
          type: string
      - name: band
        in: query
        required: true
        description: Frequency band (e.g., EU868)
        schema:
          type: string
  /api/v2/devices/{id}/commands:
    post:
      operationId: createCommand
      summary: Create command definition
      description: 'Create an actuator command definition on a digital device. Validation
        enforces mode/encoder/protocol constraints (direct = MQTT JSON payload, encoded
        = encoder pipeline).


        **Required scope:** `commands:write`'
      tags:
      - Commands
      responses:
        '200':
          description: Command created (HTTP 201)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Digital device ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - organizationId
              - command
              properties:
                organizationId:
                  type: string
                  description: Organization ID
                command:
                  type: object
                  description: Command definition.
                  required:
                  - name
                  - mode
                  - verificationStrategy
                  properties:
                    name:
                      type: string
                      example: Set temperature
                    description:
                      type: string
                    mode:
                      type: string
                      enum:
                      - direct
                      - encoded
                      description: direct = MQTT JSON payload; encoded = encoder pipeline.
                    paramsSchema:
                      type: object
                      description: Per-parameter JSON Schema subset, keyed by parameter
                        name.
                      additionalProperties:
                        type: object
                        properties:
                          type:
                            type: string
                            enum:
                            - string
                            - integer
                            - number
                            - boolean
                          default: {}
                          description:
                            type: string
                          min:
                            type: number
                          max:
                            type: number
                          enum:
                            type: array
                            items: {}
                          pattern:
                            type: string
                    encodedParamsTemplate:
                      type: object
                      description: Template rendered into encoder input (encoded mode).
                    directPayload:
                      type: string
                      description: Raw JSON payload (direct mode).
                    customEncoder:
                      type: string
                      description: JavaScript encoder source (encoded mode).
                    fPort:
                      type: integer
                      example: 5
                    mqttTopic:
                      type: string
                      example: shadow/dev/POK019/desired
                    confirmed:
                      type: boolean
                    verificationStrategy:
                      type: string
                      enum:
                      - no_verification
                      - wait_next_uplink
                      - query_after_ack
                    queryCommandId:
                      type: string
                    expectedSensorStates:
                      type: array
                      items:
                        type: object
                        properties:
                          sensorId:
                            type: string
                          valueTemplate:
                            type: string
                    convergenceTimeout:
                      type: integer
  /api/v2/devices/{id}/commands/{commandId}:
    patch:
      operationId: updateCommand
      summary: Update command definition
      description: 'Replace an existing command definition on a digital device.


        **Required scope:** `commands:write`'
      tags:
      - Commands
      responses:
        '200':
          description: Command updated (HTTP 200)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Command'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Digital device ID
        schema:
          type: string
      - name: commandId
        in: path
        required: true
        description: Command ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - organizationId
              - command
              properties:
                organizationId:
                  type: string
                  description: Organization ID
                command:
                  type: object
                  description: Full command definition (replaces the existing one).
                  required:
                  - name
                  - mode
                  - verificationStrategy
                  properties:
                    name:
                      type: string
                    description:
                      type: string
                    mode:
                      type: string
                      enum:
                      - direct
                      - encoded
                    verificationStrategy:
                      type: string
                      enum:
                      - no_verification
                      - wait_next_uplink
                      - query_after_ack
    delete:
      operationId: deleteCommand
      summary: Delete command definition
      description: 'Delete a command definition. Returns 409 (query_command_in_use)
        when another command references it as its query command.


        **Required scope:** `commands:write`'
      tags:
      - Commands
      responses:
        '200':
          description: Command deleted (HTTP 204 No Content)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Digital device ID
        schema:
          type: string
      - name: commandId
        in: path
        required: true
        description: Command ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/devices/{id}/commands/preview-encoder:
    post:
      operationId: previewEncoder
      summary: Preview command encoder
      description: 'Run a custom JavaScript encoder against concrete params in a sandbox
        (no side effects). Returns the rendered downlink bytes (hex / base64) or a
        structured encoder error. The HTTP status stays 200 even when the encoder
        itself fails (see the `error` field).


        **Required scope:** `commands:write`'
      tags:
      - Commands
      responses:
        '200':
          description: Encoder preview result. HTTP stays 200 even when the encoder
            fails (inspect the `error` field).
          content:
            application/json:
              schema:
                type: object
                properties:
                  output:
                    type: object
                    nullable: true
                    properties:
                      bytes:
                        type: array
                        items:
                          type: integer
                      bytesHex:
                        type: string
                      bytesBase64:
                        type: string
                  logs:
                    type: array
                    items:
                      type: string
                  executionTimeMs:
                    type: number
                  error:
                    type: object
                    nullable: true
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      lineNumber:
                        type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Digital device ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - organizationId
              - customEncoder
              properties:
                organizationId:
                  type: string
                  description: Organization ID
                customEncoder:
                  type: string
                  description: JavaScript encoder source to run in the sandbox.
                encodedParamsTemplate:
                  type: object
                  description: Optional template rendered into encoder input.
                params:
                  type: object
                  description: Concrete parameter values supplied to the encoder.
                fPort:
                  type: integer
  /api/v2/devices/{id}/actuator-executions:
    post:
      operationId: executeCommand
      summary: Execute command
      description: 'Trigger execution of a stored command on a device. Returns 202
        when accepted for asynchronous delivery, or 200 when an identical execution
        is already in flight (duplicate).


        **Required scope:** `commands:write`'
      tags:
      - Commands
      responses:
        '200':
          description: Execution accepted for asynchronous delivery (HTTP 202), or
            an identical execution is already in flight (HTTP 200 with duplicate=true).
          content:
            application/json:
              schema:
                type: object
                properties:
                  accepted:
                    type: boolean
                  duplicate:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Digital device ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - organizationId
              - commandId
              properties:
                organizationId:
                  type: string
                  description: Organization ID
                commandId:
                  type: string
                  description: ID of the stored command to execute.
                params:
                  type: object
                  description: Parameter values validated against the command's paramsSchema.
    get:
      operationId: listExecutions
      summary: List command executions
      description: 'List actuator executions for a device, ordered by most-recently-updated
        first, with cursor-based pagination (`before` cursor + `nextCursor`).


        **Required scope:** `commands:read`'
      tags:
      - Commands
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        triggerId:
                          type: string
                        commandId:
                          type: string
                          nullable: true
                        commandNameSnapshot:
                          type: string
                        state:
                          type: string
                          enum:
                          - enqueued
                          - in_transit
                          - delivered
                          - accepted
                          - converged
                          - accepted_no_l4
                          - unconfirmed
                          - protocol_rejected
                          - transport_unreachable
                          - transport_rejected
                          - request_rejected
                        rejectionReason:
                          type: string
                          nullable: true
                          enum:
                          - validation_failed
                          - device_queue_full
                        updatedAt:
                          type: string
                        enqueuedAt:
                          type: string
                  nextCursor:
                    type: string
                    nullable: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Digital device ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: limit
        in: query
        required: false
        description: Page size (default 50, max 200)
        schema:
          type: integer
      - name: before
        in: query
        required: false
        description: Cursor returned from a previous page
        schema:
          type: string
  /api/v2/devices/sensor-templates:
    get:
      operationId: listSensorTemplates
      summary: List sensor templates
      description: 'Retrieve available sensor templates for the organization.


        **Required scope:** `sensors:read`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  sensorTemplates:
                    type: array
                    items:
                      type: object
                      properties:
                        createdAt:
                          type: string
                        description:
                          type: string
                        id:
                          type: string
                        isSystem:
                          type: boolean
                        keyName:
                          type: string
                        keyNameId:
                          type: string
                        organizationId:
                          type: string
                        sensorType:
                          type: string
                        unitMeasurementId:
                          type: string
                        updatedAt:
                          type: string
                        valueType:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
    post:
      operationId: createSensorTemplate
      summary: Create sensor template
      description: 'Create a new sensor template.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                description:
                  type: string
                keyNameId:
                  type: string
                organizationId:
                  type: string
                sensorType:
                  type: string
                unitMeasurementId:
                  type: string
                valueType:
                  type: string
              required:
              - keyNameId
              - organizationId
              - sensorType
              - valueType
    put:
      operationId: updateSensorTemplate
      summary: Update sensor template
      description: 'Update an existing sensor template.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  description:
                    type: string
                  id:
                    type: string
                  isSystem:
                    type: boolean
                  keyName:
                    type: string
                  keyNameId:
                    type: string
                  organizationId:
                    type: string
                  sensorType:
                    type: string
                  unitMeasurementId:
                    type: string
                  updatedAt:
                    type: string
                  valueType:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Sensor template ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                description:
                  type: string
                keyNameId:
                  type: string
                sensorType:
                  type: string
                unitMeasurementId:
                  type: string
                valueType:
                  type: string
              required:
              - keyNameId
    delete:
      operationId: deleteSensorTemplate
      summary: Delete sensor template
      description: 'Delete a sensor template by ID.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Sensor template ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/devices/sensor-templates/normalized-keys:
    get:
      operationId: listNormalizedKeys
      summary: List normalized key names
      description: 'Retrieve all standardized sensor key names for the organization.


        **Required scope:** `sensors:read`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  normalizedKeys:
                    type: array
                    items:
                      type: object
                      properties:
                        createdAt:
                          type: string
                        id:
                          type: string
                        isSystem:
                          type: boolean
                        name:
                          type: string
                        organizationId:
                          type: string
                        updatedAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
    post:
      operationId: createNormalizedKey
      summary: Create normalized key name
      description: 'Create a new normalized sensor key name.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                organizationId:
                  type: string
              required:
              - name
              - organizationId
    put:
      operationId: updateNormalizedKey
      summary: Update normalized key name
      description: 'Update an existing normalized key name.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  id:
                    type: string
                  isSystem:
                    type: boolean
                  name:
                    type: string
                  organizationId:
                    type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Normalized key name ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
              required:
              - name
    delete:
      operationId: deleteNormalizedKey
      summary: Delete normalized key name
      description: 'Delete a normalized key name by ID.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Normalized key name ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/devices/sensor-templates/unit-measurements:
    get:
      operationId: listUnitMeasurements
      summary: List unit measurements
      description: 'Retrieve all unit measurements for the organization.


        **Required scope:** `sensors:read`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  unitMeasurements:
                    type: array
                    items:
                      type: object
                      properties:
                        createdAt:
                          type: string
                        id:
                          type: string
                        isSystem:
                          type: boolean
                        name:
                          type: string
                        organizationId:
                          type: string
                        symbol:
                          type: string
                        updatedAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
    post:
      operationId: createUnitMeasurement
      summary: Create unit measurement
      description: 'Create a new unit measurement.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                organizationId:
                  type: string
                symbol:
                  type: string
              required:
              - name
              - organizationId
              - symbol
    put:
      operationId: updateUnitMeasurement
      summary: Update unit measurement
      description: 'Update an existing unit measurement.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  id:
                    type: string
                  isSystem:
                    type: boolean
                  name:
                    type: string
                  organizationId:
                    type: string
                  symbol:
                    type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Unit measurement ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                symbol:
                  type: string
              required:
              - name
              - symbol
    delete:
      operationId: deleteUnitMeasurement
      summary: Delete unit measurement
      description: 'Delete a unit measurement by ID.


        **Required scope:** `sensors:write`'
      tags:
      - Sensors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Unit measurement ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/sensors/history:
    get:
      operationId: getSensorHistory
      summary: Get telemetry history
      description: 'Retrieve OHLC telemetry history for sensors with configurable
        granularity.


        **Required scope:** `telemetry:read`'
      tags:
      - Telemetry
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        candle:
                          type: object
                        sensorId:
                          type: string
                        ts:
                          type: string
                        type:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: sensorIds
        in: query
        required: true
        description: Comma-separated sensor IDs
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: from
        in: query
        required: true
        description: Start time (ISO8601, e.g. 2024-01-01T00:00:00Z)
        schema:
          type: string
      - name: to
        in: query
        required: true
        description: End time (ISO8601, e.g. 2024-01-02T00:00:00Z)
        schema:
          type: string
      - name: granularity
        in: query
        required: true
        description: Aggregation granularity
        schema:
          type: string
          enum:
          - 1m
          - 5m
          - 15m
          - 30m
          - 1h
          - 4h
          - 1d
          - 1w
      - name: sort
        in: query
        description: 'Sort order: ASC or DESC'
        schema:
          type: string
          default: ASC
  /api/v2/sensors/history/raw:
    get:
      operationId: getSensorHistoryRaw
      summary: Get raw telemetry history
      description: 'Retrieve raw (unaggregated) telemetry data points for sensors.


        **Required scope:** `telemetry:read`'
      tags:
      - Telemetry
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        sensorId:
                          type: string
                        ts:
                          type: string
                        type:
                          type: string
                        value:
                          type: object
                  hasMore:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: sensorIds
        in: query
        required: true
        description: Comma-separated sensor IDs
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: from
        in: query
        required: true
        description: Start time (ISO8601, e.g. 2024-01-01T00:00:00Z)
        schema:
          type: string
      - name: to
        in: query
        required: true
        description: End time (ISO8601, e.g. 2024-01-02T00:00:00Z)
        schema:
          type: string
      - name: sort
        in: query
        description: 'Sort order: ASC or DESC'
        schema:
          type: string
          default: DESC
      - name: limit
        in: query
        description: Page size
        schema:
          type: integer
          default: 50
      - name: offset
        in: query
        description: Number of records to skip
        schema:
          type: integer
          default: 0
  /api/v2/sensors/last-seen:
    get:
      operationId: getSensorLastSeen
      summary: Get last seen timestamps
      description: 'Retrieve the last-seen timestamps for device sensors.


        **Required scope:** `telemetry:read`'
      tags:
      - Telemetry
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        lastSeen:
                          type: string
                        sensorId:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: sensorIds
        in: query
        required: true
        description: Comma-separated sensor IDs
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/connections:
    get:
      operationId: listConnections
      summary: List connections
      description: 'Retrieve device connections, optionally filtered by type.


        **Required scope:** `connections:read`'
      tags:
      - Connections
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  connections:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        type:
                          type: string
                        organizationId:
                          type: string
                        configuration:
                          type: object
                        createdAt:
                          type: string
                        updatedAt:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: type
        in: query
        required: false
        description: Filter by connection type (e.g. lorawan, mqtt_cloud, mqtt_external)
        schema:
          type: string
    post:
      operationId: createConnection
      summary: Create connection
      description: 'Create a new device connection with type and configuration.


        **Required scope:** `connections:write`'
      tags:
      - Connections
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                configuration:
                  type: object
                connectorId:
                  type: integer
                  example: 3
                name:
                  type: string
                  example: My MQTT Cloud Connection
                organizationId:
                  type: string
                  example: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              required:
              - connectorId
              - name
              - organizationId
  /api/connections/{id}:
    get:
      operationId: getConnection
      summary: Get connection
      description: 'Retrieve a device connection by ID.


        **Required scope:** `connections:read`'
      tags:
      - Connections
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  configuration:
                    type: object
                  connectedDevices:
                    type: integer
                    example: 5
                  connectorId:
                    type: integer
                    example: 3
                  connectorType:
                    type: string
                    enum: &id002
                    - lorawan
                    - mqtt_cloud
                    - mqtt_external
                    - tracker
                    example: mqtt_cloud
                  createdAt:
                    type: string
                    example: '2024-01-15T10:30:00Z'
                  id:
                    type: string
                    example: 550e8400-e29b-41d4-a716-446655440000
                  name:
                    type: string
                    example: My MQTT Cloud Connection
                  organizationId:
                    type: string
                    example: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  updatedAt:
                    type: string
                    example: '2024-01-20T14:22:00Z'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Connection UUID
        schema:
          type: string
    put:
      operationId: updateConnection
      summary: Update connection
      description: 'Update a device connection''s configuration.


        **Required scope:** `connections:write`'
      tags:
      - Connections
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  configuration:
                    type: object
                  connectedDevices:
                    type: integer
                    example: 5
                  connectorId:
                    type: integer
                    example: 3
                  connectorType:
                    type: string
                    enum: *id002
                    example: mqtt_cloud
                  createdAt:
                    type: string
                    example: '2024-01-15T10:30:00Z'
                  id:
                    type: string
                    example: 550e8400-e29b-41d4-a716-446655440000
                  name:
                    type: string
                    example: My MQTT Cloud Connection
                  organizationId:
                    type: string
                    example: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  updatedAt:
                    type: string
                    example: '2024-01-20T14:22:00Z'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Connection UUID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                configuration:
                  type: object
                connectorId:
                  type: integer
                  example: 3
                name:
                  type: string
                  example: Updated Connection Name
              required:
              - connectorId
              - name
    delete:
      operationId: deleteConnection
      summary: Delete connection
      description: 'Delete a device connection by ID.


        **Required scope:** `connections:write`'
      tags:
      - Connections
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Connection UUID
        schema:
          type: string
  /api/connectors:
    get:
      operationId: listConnectors
      summary: List connectors
      description: 'Retrieve available connector types (LoRaWAN, MQTT, etc.).


        **Required scope:** `connectors:read`'
      tags:
      - Connectors
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  connectors:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        type:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /api/v2/dashboards:
    get:
      operationId: listDashboards
      summary: List dashboards
      description: 'Retrieve all dashboards and folders as a tree structure.


        **Required scope:** `dashboards:read`'
      tags:
      - Dashboards
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    access:
                      type: string
                      description: '"organization"'
                    configuration:
                      type: string
                      description: JSON string
                    data:
                      type: array
                      description: children (recursive, always array, never null)
                      items:
                        type: object
                        properties:
                          access:
                            type: string
                            description: '"organization"'
                          configuration:
                            type: string
                            description: JSON string
                          data:
                            type: array
                            description: children (recursive, always array, never
                              null)
                            items:
                              type: object
                          description:
                            type: string
                          displayOrder:
                            type: integer
                            description: Client-managed ordering
                          icon:
                            type: string
                          id:
                            type: string
                          name:
                            type: string
                          type:
                            type: string
                            description: '"folder" or "dashboard"'
                          widgetIds:
                            type: array
                            description: List of widget IDs (always array, never null)
                            items:
                              type: object
                    description:
                      type: string
                    displayOrder:
                      type: integer
                      description: Client-managed ordering
                    icon:
                      type: string
                    id:
                      type: string
                    name:
                      type: string
                    type:
                      type: string
                      description: '"folder" or "dashboard"'
                    widgetIds:
                      type: array
                      description: List of widget IDs (always array, never null)
                      items:
                        type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
    post:
      operationId: createDashboard
      summary: Create dashboard
      description: 'Create a new dashboard or folder.


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboards
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  type:
                    type: string
                  organizationId:
                    type: string
                  parentId:
                    type: string
                  displayOrder:
                    type: integer
                  createdAt:
                    type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Dashboard or folder name
                organizationId:
                  type: string
                type:
                  type: string
                  description: '''dashboard'' or ''folder'''
                  enum:
                  - dashboard
                  - folder
                parentId:
                  type: string
                  description: Parent folder ID (null for root)
                description:
                  type: string
                icon:
                  type: string
                displayOrder:
                  type: integer
                configuration:
                  type: string
                  description: JSON configuration string
              required:
              - name
              - organizationId
              - type
  /api/v2/dashboards/{id}:
    put:
      operationId: updateDashboard
      summary: Update dashboard
      description: 'Update dashboard or folder metadata.


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboards
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  success:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Dashboard ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                configuration:
                  type: string
                description:
                  type: string
                icon:
                  type: string
                name:
                  type: string
                organizationId:
                  type: string
              required:
              - organizationId
    delete:
      operationId: deleteDashboard
      summary: Delete dashboard
      description: 'Delete a dashboard by ID.


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboards
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  deletedCount:
                    type: integer
                  message:
                    type: string
                  success:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Dashboard ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: cascade
        in: query
        description: Delete children if true
        schema:
          type: boolean
          default: false
  /api/v2/dashboards/{id}/move:
    post:
      operationId: moveDashboard
      summary: Move dashboard
      description: 'Move a dashboard to a new parent folder and/or position.


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboards
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  access:
                    type: string
                    description: '"organization"'
                  configuration:
                    type: string
                    description: JSON string
                  description:
                    type: string
                  displayOrder:
                    type: integer
                    description: Client-managed ordering
                  icon:
                    type: string
                  id:
                    type: string
                  name:
                    type: string
                  type:
                    type: string
                    description: '"folder" or "dashboard"'
                  widgetIds:
                    type: array
                    description: List of widget IDs (always array, never null)
                    items:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Dashboard ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                insertAfterDashboardId:
                  type: string
                  description: empty = beginning
                newParentId:
                  type: string
                  description: empty = root
                organizationId:
                  type: string
              required:
              - organizationId
  /api/v2/widgets:
    get:
      operationId: getWidgets
      summary: Get widgets
      description: 'Retrieve widget definitions by their IDs.


        **Required scope:** `dashboards:read`'
      tags:
      - Dashboards
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    configuration:
                      type: object
                    createdAt:
                      type: string
                    dashboardId:
                      type: string
                    id:
                      type: string
                    type:
                      type: string
                    updatedAt:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: ids
        in: query
        required: true
        description: Comma-separated widget IDs
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
    post:
      operationId: createWidget
      summary: Create widget
      description: 'Add a widget to a dashboard.


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboards
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                configuration:
                  type: object
                dashboardId:
                  type: string
                organizationId:
                  type: string
                type:
                  type: string
              required:
              - configuration
              - dashboardId
              - organizationId
              - type
  /api/v2/widgets/{id}:
    put:
      operationId: updateWidget
      summary: Update widget
      description: 'Update widget type or configuration.


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboards
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  success:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Widget ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                configuration:
                  type: object
                type:
                  type: string
    delete:
      operationId: deleteWidget
      summary: Delete widget
      description: 'Delete a widget by ID.


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboards
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  success:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Widget ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/organizations/{id}:
    get:
      operationId: getOrganization
      summary: Get organization
      description: 'Retrieve organization details by ID.


        **Required scope:** `orgs:read`'
      tags:
      - Orgs
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  owner_id:
                    type: string
                  is_default:
                    type: boolean
                  is_last_selected:
                    type: boolean
                  created_at:
                    type: string
                  updated_at:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/organizations:
    put:
      operationId: updateOrganization
      summary: Update organization
      description: 'Update organization name or transfer ownership.


        **Required scope:** `orgs:write`'
      tags:
      - Orgs
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  createdAt:
                    type: string
                  id:
                    type: string
                  isDefault:
                    type: boolean
                  name:
                    type: string
                  ownerId:
                    type: string
                  updatedAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: optional
                organizationId:
                  type: string
                  description: required
                ownerId:
                  type: string
                  description: optional
  /api/v2/organizations/{id}/users:
    get:
      operationId: listOrganizationUsers
      summary: List organization members
      description: 'Retrieve all members of the organization.


        **Required scope:** `orgs:read`'
      tags:
      - Orgs
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    email:
                      type: string
                    first_name:
                      type: string
                    is_owner:
                      type: boolean
                    last_name:
                      type: string
                    user_id:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/organizations/users/invite:
    post:
      operationId: inviteOrganizationUser
      summary: Invite user to organization
      description: 'Invite a user to the organization by email.


        **Required scope:** `orgs:write`'
      tags:
      - Orgs
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                organizationId:
                  type: string
                permissions:
                  type: array
                  items:
                    type: object
                    properties:
                      action:
                        description: '"read" | "write"'
                      object_text_code:
                        type: string
                        description: e.g. "device", "organization"
  /api/v2/organizations/users/invites:
    get:
      operationId: listOrganizationInvites
      summary: List pending invitations
      description: 'Retrieve active user invitations for the organization.


        **Required scope:** `orgs:read`'
      tags:
      - Orgs
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    email:
                      type: string
                    permissions:
                      type: array
                      items:
                        type: object
                        properties:
                          action:
                            type: object
                          object_code:
                            type: integer
                          object_text_code:
                            type: string
                          object_title:
                            type: string
                    user_id:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/organizations/users/invites/revoke:
    post:
      operationId: revokeOrganizationInvite
      summary: Revoke invitation
      description: 'Revoke a pending user invitation.


        **Required scope:** `orgs:write`'
      tags:
      - Orgs
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                invited_email:
                  type: string
                organizationId:
                  type: string
  /api/v2/organizations/users/{user_id}:
    delete:
      operationId: deleteOrganizationUser
      summary: Remove user from organization
      description: 'Remove a user from the organization.


        **Required scope:** `orgs:write`'
      tags:
      - Orgs
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: user_id
        in: path
        required: true
        description: User ID
        schema:
          type: string
  /api/v2/organizations/users/{user_id}/permissions:
    get:
      operationId: getUserPermissions
      summary: Get user permissions
      description: 'Retrieve a user''s role and permissions within the organization.


        **Required scope:** `orgs:read`'
      tags:
      - Orgs
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    action:
                      type: string
                      enum:
                      - read
                      - write
                    object_code:
                      type: integer
                    object_text_code:
                      type: string
                    object_title:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: user_id
        in: path
        required: true
        description: User ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
    put:
      operationId: updateUserPermissions
      summary: Update user permissions
      description: 'Update a user''s role within the organization (admin, editor,
        viewer).


        **Required scope:** `orgs:write`'
      tags:
      - Orgs
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: user_id
        in: path
        required: true
        description: User ID
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                permissions:
                  type: array
                  items:
                    type: object
                    properties:
                      action:
                        description: '"read" | "write"'
                      object_text_code:
                        type: string
  /api/v2/organizations/subscription/data:
    get:
      operationId: getSubscriptionData
      summary: Get subscription data
      description: 'Retrieve current subscription plan and usage for the organization.


        **Required scope:** `subscriptions:read`'
      tags:
      - Subscriptions
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  current_usage:
                    type: object
                    properties:
                      dashboard_count:
                        type: integer
                      devices_count:
                        type: integer
                      rules_count:
                        type: integer
                  subscription:
                    type: object
                    properties:
                      current_period_end:
                        type: string
                      current_period_start:
                        type: string
                      features:
                        type: object
                        properties:
                          custom_dashboards:
                            type: integer
                          device_logs:
                            type: integer
                          devices:
                            type: integer
                          email_notifications:
                            type: boolean
                          email_support:
                            type: boolean
                          notification_center:
                            type: boolean
                          phone_push_notifications:
                            type: boolean
                          rules:
                            type: integer
                          unlimited_gateways:
                            type: boolean
                      plan:
                        type: object
                        properties:
                          amount:
                            type: integer
                          currency:
                            type: string
                          interval:
                            type: string
                          name:
                            type: string
                          stripe_price_id:
                            type: string
                          stripe_product_id:
                            type: string
                      status:
                        type: string
                      stripe_customer_id:
                        type: string
                      stripe_subscription_id:
                        type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
  /api/v2/organizations/api-key-scopes:
    get:
      operationId: listApiKeyScopes
      summary: List available API key scopes
      description: 'Retrieve all scopes that can be assigned to API keys.


        **Required scope:** `api-keys:read`'
      tags:
      - Api-Keys
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    labelKey:
                      type: string
                    value:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID (UUID)
        schema:
          type: string
  /api/v2/organizations/api-keys:
    get:
      operationId: listApiKeys
      summary: List API keys
      description: 'Retrieve all API keys for the current user in the organization.


        **Required scope:** `api-keys:read`'
      tags:
      - Api-Keys
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    createdAt:
                      type: string
                    expiresAt:
                      type: string
                    id:
                      type: string
                    lastUsedAt:
                      type: string
                    name:
                      type: string
                    prefix:
                      type: string
                    scopes:
                      type: array
                      items:
                        type: string
                    status:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID (UUID)
        schema:
          type: string
    post:
      operationId: createApiKey
      summary: Create API key
      description: 'Create a new API key with specified scopes.


        **Required scope:** `api-keys:write`'
      tags:
      - Api-Keys
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  key:
                    type: string
                    description: The API key secret (only shown once at creation)
                  scopes:
                    type: array
                    items:
                      type: string
                  expiresAt:
                    type: string
                  createdAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  description: Human-readable API key name
                organizationId:
                  type: string
                scopes:
                  type: array
                  description: List of scopes to assign (e.g. devices:read, devices:write)
                  items:
                    type: string
                expiresAt:
                  type: string
                  description: Optional expiration date (ISO 8601)
              required:
              - name
              - organizationId
  /api/v2/organizations/api-keys/{id}:
    delete:
      operationId: revokeApiKey
      summary: Revoke API key
      description: 'Permanently revoke an API key by ID.


        **Required scope:** `api-keys:write`'
      tags:
      - Api-Keys
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: API key ID (UUID)
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID (UUID)
        schema:
          type: string
  /api/v2/organizations/api-keys/{id}/rotate:
    post:
      operationId: rotateApiKey
      summary: Rotate API key
      description: 'Rotate an API key, generating a new secret while keeping the same
        scopes.


        **Required scope:** `api-keys:write`'
      tags:
      - Api-Keys
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  key:
                    type: string
                  prefix:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: API key ID (UUID)
        schema:
          type: string
      - name: organizationId
        in: query
        required: true
        description: Organization ID (UUID)
        schema:
          type: string
  /api/rule-definitions:
    get:
      operationId: listRuleDefinitions
      summary: Rule definitions (read)
      description: 'List, get, and query rule definitions. Endpoints: GET /api/rule-definitions
        (list), GET /api/rule-definitions/{id} (get by ID), GET /api/rule-definitions/deleted
        (list trashed), GET /api/rule-definitions/{id}/versions (list versions), GET
        /api/rule-definitions/{id}/builds (list builds).


        **Required scope:** `rules:read`'
      tags:
      - Rules
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        description:
                          type: string
                        organizationId:
                          type: string
                        authorId:
                          type: string
                        version:
                          type: integer
                        status:
                          type: string
                        lockedByUserId:
                          type: string
                        createdAt:
                          type: string
                        updatedAt:
                          type: string
                  total:
                    type: integer
                  page:
                    type: integer
                  limit:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: organizationId
        in: query
        required: true
        description: Organization ID
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number (default 1)
        schema:
          type: integer
      - name: limit
        in: query
        required: false
        description: Items per page (default 20)
        schema:
          type: integer
    post:
      operationId: createRuleDefinition
      summary: Rule definitions (write — POST)
      description: 'Create and action rule definitions. Endpoints: POST /api/rule-definitions
        (create), POST /api/rule-definitions/provision (one-click provision), POST
        /api/rule-definitions/{id}/clone (clone), POST /api/rule-definitions/{id}/lock
        (lock for editing), POST /api/rule-definitions/{id}/force-unlock (admin force
        unlock), POST /api/rule-definitions/{id}/restore (restore from trash), POST
        /api/rule-definitions/{id}/restore-version (restore historical version), POST
        /api/rule-definitions/{id}/deploy (deploy rule), POST /api/rule-definitions/{id}/stop
        (stop rule).


        **Required scope:** `rules:write`'
      tags:
      - Rules
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  ruleDefinition:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      description:
                        type: string
                      organizationId:
                        type: string
                      authorId:
                        type: string
                      version:
                        type: integer
                      createdAt:
                        type: string
                      updatedAt:
                        type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                organizationId:
                  type: string
                bpmnXml:
                  type: string
                  description: Base64-encoded BPMN XML diagram
              required:
              - name
              - organizationId
    put:
      operationId: updateRuleDefinition
      summary: Rule definitions (write — PUT)
      description: 'Update rule definitions. Endpoints: PUT /api/rule-definitions/{id}
        (update name/description), PUT /api/rule-definitions/{id}/save (save BPMN
        progress).


        **Required scope:** `rules:write`'
      tags:
      - Rules
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  ruleDefinition:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      description:
                        type: string
                      organizationId:
                        type: string
                      authorId:
                        type: string
                      version:
                        type: integer
                      createdAt:
                        type: string
                      updatedAt:
                        type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Rule definition ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
    delete:
      operationId: deleteRuleDefinition
      summary: Rule definitions (write — DELETE)
      description: 'Delete rule definitions and unlock. Endpoints: DELETE /api/rule-definitions/{id}
        (soft-delete / trash), DELETE /api/rule-definitions/{id}/lock (unlock and
        save), DELETE /api/rule-definitions/{id}/builds/{ruleVersionId} (delete a
        build).


        **Required scope:** `rules:write`'
      tags:
      - Rules
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  success:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Rule definition ID
        schema:
          type: string
    patch:
      operationId: patchRuleDefinition
      summary: Rule definitions (write — PATCH)
      description: 'Patch operations. Endpoints: PATCH /api/rule-definitions/{id}/builds/{ruleVersionId}
        (update build description).


        **Required scope:** `rules:write`'
      tags:
      - Rules
      responses:
        '200':
          description: Successful response
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: ruleDefinitionId
        in: path
        required: true
        description: Rule definition ID
        schema:
          type: string
      - name: ruleVersionId
        in: path
        required: true
        description: Rule version ID of the build
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                description:
                  type: string
                orgId:
                  type: string
              required:
              - orgId
  /api/rule-versions:
    post:
      operationId: buildRuleVersion
      summary: Rule versions (write — POST)
      description: 'Build rule versions. Endpoints: POST /api/rule-versions/{ruleVersionId}/build
        (create a build from version).


        **Required scope:** `rules:write`'
      tags:
      - Rules
      responses:
        '200':
          description: Created
          content:
            application/json:
              schema:
                type: object
                properties:
                  ruleVersionId:
                    type: string
                  ruleDefinitionId:
                    type: string
                  name:
                    type: string
                  description:
                    type: string
                  createdAt:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: ruleVersionId
        in: path
        required: true
        description: Rule version ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                orgId:
                  type: string
                ruleDefinitionId:
                  type: string
              required:
              - orgId
              - ruleDefinitionId
    patch:
      operationId: renameRuleVersion
      summary: Rule versions (write — PATCH)
      description: 'Rename rule versions. Endpoints: PATCH /api/rule-versions/{id}/name
        (rename a version).


        **Required scope:** `rules:write`'
      tags:
      - Rules
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  ruleVersion:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      version:
                        type: integer
                      createdAt:
                        type: string
                      updatedAt:
                        type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
      parameters:
      - name: id
        in: path
        required: true
        description: Rule version ID
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
              required:
              - name
  /userprofile.UserProfileService/GetUser:
    post:
      operationId: grpc_userProfileGet
      summary: Get user profile
      description: 'Retrieve user profile by ID.


        **Protocol:** gRPC


        **Service:** `userprofile.UserProfileService`


        **Method:** `GetUser`


        **Required scope:** `users:read`'
      tags:
      - User Profile (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetUserRequest` message. Refer to the
                service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetUserResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /userprofile.UserProfileService/UpdateUser:
    post:
      operationId: grpc_userProfileUpdate
      summary: Update user profile
      description: 'Update user profile fields (name, phone).


        **Protocol:** gRPC


        **Service:** `userprofile.UserProfileService`


        **Method:** `UpdateUser`


        **Required scope:** `users:write`'
      tags:
      - User Profile (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `UpdateUserRequest` message. Refer to
                the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `UpdateUserResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /digitaldevice.v2.DigitalDeviceService/ListDigitalDevices:
    post:
      operationId: grpc_risListDevices
      summary: List devices
      description: 'Retrieve all digital devices for the organization.


        **Protocol:** gRPC


        **Service:** `digitaldevice.v2.DigitalDeviceService`


        **Method:** `ListDigitalDevices`


        **Required scope:** `devices:read`'
      tags:
      - Digital Device (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `ListDigitalDevicesRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `ListDigitalDevicesResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /digitaldevice.v2.DigitalDeviceService/GetDigitalDevice:
    post:
      operationId: grpc_risGetDevice
      summary: Get device
      description: 'Retrieve a single device by ID or name.


        **Protocol:** gRPC


        **Service:** `digitaldevice.v2.DigitalDeviceService`


        **Method:** `GetDigitalDevice`


        **Required scope:** `devices:read`'
      tags:
      - Digital Device (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetDigitalDeviceRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetDigitalDeviceResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /digitaldevice.v2.DigitalDeviceService/CreateDigitalDevice:
    post:
      operationId: grpc_risCreateDevice
      summary: Create device
      description: 'Provision a new digital device with optional sensor attachment.


        **Protocol:** gRPC


        **Service:** `digitaldevice.v2.DigitalDeviceService`


        **Method:** `CreateDigitalDevice`


        **Required scope:** `devices:write`'
      tags:
      - Digital Device (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `CreateDigitalDeviceRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `CreateDigitalDeviceResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /digitaldevice.v2.DigitalDeviceService/UpdateDigitalDevice:
    post:
      operationId: grpc_risUpdateDevice
      summary: Update device
      description: 'Update device properties (name, connection, config).


        **Protocol:** gRPC


        **Service:** `digitaldevice.v2.DigitalDeviceService`


        **Method:** `UpdateDigitalDevice`


        **Required scope:** `devices:write`'
      tags:
      - Digital Device (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `UpdateDigitalDeviceRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `UpdateDigitalDeviceResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /digitaldevice.v2.DigitalDeviceService/GetDeviceProfileTemplate:
    post:
      operationId: grpc_risGetDeviceProfileTemplate
      summary: Get device profile template
      description: 'Look up a LoRaWAN device profile by brand, model, and band.


        **Protocol:** gRPC


        **Service:** `digitaldevice.v2.DigitalDeviceService`


        **Method:** `GetDeviceProfileTemplate`


        **Required scope:** `devices:read`'
      tags:
      - Digital Device (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetDeviceProfileTemplateRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetDeviceProfileTemplateResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /digitaldevice.v2.DigitalDeviceService/AddSensors:
    post:
      operationId: grpc_risAddSensors
      summary: Add sensors to device
      description: 'Attach sensors to a device by template IDs.


        **Protocol:** gRPC


        **Service:** `digitaldevice.v2.DigitalDeviceService`


        **Method:** `AddSensors`


        **Required scope:** `sensors:write`'
      tags:
      - Digital Device (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `AddSensorsRequest` message. Refer to
                the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `AddSensorsResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /digitaldevice.v2.DigitalDeviceService/SetSensorMappings:
    post:
      operationId: grpc_risSetSensorMappings
      summary: Set sensor mappings
      description: 'Configure sensor-to-source-path mappings for a device.


        **Protocol:** gRPC


        **Service:** `digitaldevice.v2.DigitalDeviceService`


        **Method:** `SetSensorMappings`


        **Required scope:** `sensors:write`'
      tags:
      - Digital Device (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `SetSensorMappingsRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `SetSensorMappingsResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /sensor_template.v2.SensorTemplateService/ListSensorTemplates:
    post:
      operationId: grpc_risListSensorTemplates
      summary: List sensor templates
      description: 'Retrieve available sensor templates for the organization.


        **Protocol:** gRPC


        **Service:** `sensor_template.v2.SensorTemplateService`


        **Method:** `ListSensorTemplates`


        **Required scope:** `sensors:read`'
      tags:
      - Sensor Template (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `ListSensorTemplatesRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `ListSensorTemplatesResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /connector.ConnectorService/GetConnectors:
    post:
      operationId: grpc_risGetConnectors
      summary: List connectors
      description: 'Retrieve available connector types (LoRaWAN, MQTT, etc.).


        **Protocol:** gRPC


        **Service:** `connector.ConnectorService`


        **Method:** `GetConnectors`


        **Required scope:** `connectors:read`'
      tags:
      - Connector (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetConnectorsRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetConnectorsResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /connection.ConnectionService/GetConnections:
    post:
      operationId: grpc_risGetConnections
      summary: List connections
      description: 'Retrieve device connections, optionally filtered by type.


        **Protocol:** gRPC


        **Service:** `connection.ConnectionService`


        **Method:** `GetConnections`


        **Required scope:** `connections:read`'
      tags:
      - Connection (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetConnectionsRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetConnectionsResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /connection.ConnectionService/CreateConnection:
    post:
      operationId: grpc_risCreateConnection
      summary: Create connection
      description: 'Create a new device connection with type and configuration.


        **Protocol:** gRPC


        **Service:** `connection.ConnectionService`


        **Method:** `CreateConnection`


        **Required scope:** `connections:write`'
      tags:
      - Connection (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `CreateConnectionRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `CreateConnectionResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /connection.ConnectionService/DeleteConnection:
    post:
      operationId: grpc_risDeleteConnection
      summary: Delete connection
      description: 'Delete a device connection by ID.


        **Protocol:** gRPC


        **Service:** `connection.ConnectionService`


        **Method:** `DeleteConnection`


        **Required scope:** `connections:write`'
      tags:
      - Connection (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `DeleteConnectionRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `DeleteConnectionResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /dashboard.v2.DashboardService/GetDashboardTree:
    post:
      operationId: grpc_risGetDashboardTree
      summary: List dashboards
      description: 'Retrieve all dashboards and folders as a tree structure.


        **Protocol:** gRPC


        **Service:** `dashboard.v2.DashboardService`


        **Method:** `GetDashboardTree`


        **Required scope:** `dashboards:read`'
      tags:
      - Dashboard (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetDashboardTreeRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetDashboardTreeResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /dashboard.v2.DashboardService/CreateDashboard:
    post:
      operationId: grpc_risCreateDashboard
      summary: Create dashboard
      description: 'Create a new dashboard or folder.


        **Protocol:** gRPC


        **Service:** `dashboard.v2.DashboardService`


        **Method:** `CreateDashboard`


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboard (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `CreateDashboardRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `CreateDashboardResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /dashboard.v2.DashboardService/UpdateDashboard:
    post:
      operationId: grpc_risUpdateDashboard
      summary: Update dashboard
      description: 'Update dashboard or folder metadata.


        **Protocol:** gRPC


        **Service:** `dashboard.v2.DashboardService`


        **Method:** `UpdateDashboard`


        **Required scope:** `dashboards:write`'
      tags:
      - Dashboard (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `UpdateDashboardRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `UpdateDashboardResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /widget.v2.WidgetService/GetWidgetsByIds:
    post:
      operationId: grpc_risGetWidgetsByIds
      summary: Get widgets
      description: 'Retrieve widget definitions by their IDs.


        **Protocol:** gRPC


        **Service:** `widget.v2.WidgetService`


        **Method:** `GetWidgetsByIds`


        **Required scope:** `dashboards:read`'
      tags:
      - Widget (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetWidgetsByIdsRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetWidgetsByIdsResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /widget.v2.WidgetService/CreateWidget:
    post:
      operationId: grpc_risCreateWidget
      summary: Create widget
      description: 'Add a widget to a dashboard.


        **Protocol:** gRPC


        **Service:** `widget.v2.WidgetService`


        **Method:** `CreateWidget`


        **Required scope:** `dashboards:write`'
      tags:
      - Widget (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `CreateWidgetRequest` message. Refer to
                the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `CreateWidgetResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /widget.v2.WidgetService/UpdateWidget:
    post:
      operationId: grpc_risUpdateWidget
      summary: Update widget
      description: 'Update widget type or configuration.


        **Protocol:** gRPC


        **Service:** `widget.v2.WidgetService`


        **Method:** `UpdateWidget`


        **Required scope:** `dashboards:write`'
      tags:
      - Widget (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `UpdateWidgetRequest` message. Refer to
                the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `UpdateWidgetResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /actuator_command.v2.ActuatorCommandService/CreateActuatorCommand:
    post:
      operationId: grpc_risCreateActuatorCommand
      summary: Create command definition
      description: 'Create an actuator command definition on a device. RIS enforces
        device write access.


        **Protocol:** gRPC


        **Service:** `actuator_command.v2.ActuatorCommandService`


        **Method:** `CreateActuatorCommand`


        **Required scope:** `commands:write`'
      tags:
      - Actuator Command (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `CreateActuatorCommandRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `CreateActuatorCommandResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /actuator_command.v2.ActuatorCommandService/UpdateActuatorCommand:
    post:
      operationId: grpc_risUpdateActuatorCommand
      summary: Update command definition
      description: 'Replace an existing actuator command definition.


        **Protocol:** gRPC


        **Service:** `actuator_command.v2.ActuatorCommandService`


        **Method:** `UpdateActuatorCommand`


        **Required scope:** `commands:write`'
      tags:
      - Actuator Command (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `UpdateActuatorCommandRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `UpdateActuatorCommandResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /actuator_command.v2.ActuatorCommandService/DeleteActuatorCommand:
    post:
      operationId: grpc_risDeleteActuatorCommand
      summary: Delete command definition
      description: 'Delete an actuator command definition.


        **Protocol:** gRPC


        **Service:** `actuator_command.v2.ActuatorCommandService`


        **Method:** `DeleteActuatorCommand`


        **Required scope:** `commands:write`'
      tags:
      - Actuator Command (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `DeleteActuatorCommandRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `DeleteActuatorCommandResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /sensorquery.v1.SensorQueryService/GetHistory:
    post:
      operationId: grpc_sensorqueryGetHistory
      summary: Get telemetry history
      description: 'Retrieve OHLC telemetry history for sensors with configurable
        granularity.


        **Protocol:** gRPC


        **Service:** `sensorquery.v1.SensorQueryService`


        **Method:** `GetHistory`


        **Required scope:** `telemetry:read`'
      tags:
      - Sensor Query (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetHistoryRequest` message. Refer to
                the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetHistoryResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /sensorquery.v1.SensorQueryService/GetLastSeen:
    post:
      operationId: grpc_sensorqueryGetLastSeen
      summary: Get last seen timestamps
      description: 'Retrieve the last-seen timestamps for device sensors.


        **Protocol:** gRPC


        **Service:** `sensorquery.v1.SensorQueryService`


        **Method:** `GetLastSeen`


        **Required scope:** `telemetry:read`'
      tags:
      - Sensor Query (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetLastSeenRequest` message. Refer to
                the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetLastSeenResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /OrganizationsService/GetOrganization:
    post:
      operationId: grpc_orgGet
      summary: Get organization
      description: 'Retrieve organization details (name, owner, creation date).


        **Protocol:** gRPC


        **Service:** `OrganizationsService`


        **Method:** `GetOrganization`


        **Required scope:** `orgs:read`'
      tags:
      - Organizations (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetOrganizationRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetOrganizationResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /OrganizationsService/UpdateOrganization:
    post:
      operationId: grpc_orgUpdate
      summary: Update organization
      description: 'Update organization name or transfer ownership.


        **Protocol:** gRPC


        **Service:** `OrganizationsService`


        **Method:** `UpdateOrganization`


        **Required scope:** `orgs:write`'
      tags:
      - Organizations (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `UpdateOrganizationRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `UpdateOrganizationResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /OrganizationsService/GetOrganizationUsers:
    post:
      operationId: grpc_orgListUsers
      summary: List organization members
      description: 'Retrieve all members of the organization with profile data.


        **Protocol:** gRPC


        **Service:** `OrganizationsService`


        **Method:** `GetOrganizationUsers`


        **Required scope:** `orgs:read`'
      tags:
      - Organizations (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `GetOrganizationUsersRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `GetOrganizationUsersResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /OrganizationsService/CreateUserInvite:
    post:
      operationId: grpc_orgInviteUser
      summary: Invite user
      description: 'Invite a user to the organization by email.


        **Protocol:** gRPC


        **Service:** `OrganizationsService`


        **Method:** `CreateUserInvite`


        **Required scope:** `orgs:write`'
      tags:
      - Organizations (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `CreateUserInviteRequest` message. Refer
                to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `CreateUserInviteResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /organization_access_control.AccessControlService/UpdateUserPermissions:
    post:
      operationId: grpc_orgUpdateUserPermissions
      summary: Assign user role
      description: 'Update a user''s role within the organization (admin, editor,
        viewer).


        **Protocol:** gRPC


        **Service:** `organization_access_control.AccessControlService`


        **Method:** `UpdateUserPermissions`


        **Required scope:** `orgs:write`'
      tags:
      - Access Control (gRPC)
      requestBody:
        required: true
        content:
          application/grpc:
            schema:
              type: object
              description: Protobuf-encoded `UpdateUserPermissionsRequest` message.
                Refer to the service proto definition for field details.
      responses:
        '200':
          description: Successful gRPC response
          content:
            application/grpc:
              schema:
                type: object
                description: Protobuf-encoded `UpdateUserPermissionsResponse` message.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: 'API key for authentication (format: `chirp_<key>`)'
    OrgId:
      type: apiKey
      in: header
      name: X-Organization-Id
      description: Organization UUID that the API key belongs to
  schemas:
    Error:
      type: object
      required:
      - error
      - message
      properties:
        error:
          type: string
        message:
          type: string
    Command:
      type: object
      description: A command definition stored under a digital device.
      properties:
        id:
          type: string
        name:
          type: string
          example: Set temperature
        description:
          type: string
        mode:
          type: string
          enum:
          - direct
          - encoded
        paramsSchema:
          type: object
          description: Per-parameter JSON Schema subset, keyed by parameter name.
          additionalProperties:
            type: object
            properties:
              type:
                type: string
                enum:
                - string
                - integer
                - number
                - boolean
              default: {}
              description:
                type: string
              min:
                type: number
              max:
                type: number
              enum:
                type: array
                items: {}
              pattern:
                type: string
        encodedParamsTemplate:
          type: object
        directPayload:
          type: string
        customEncoder:
          type: string
        fPort:
          type: integer
        mqttTopic:
          type: string
        confirmed:
          type: boolean
        verificationStrategy:
          type: string
          enum:
          - no_verification
          - wait_next_uplink
          - query_after_ack
        queryCommandId:
          type: string
        expectedSensorStates:
          type: array
          items:
            type: object
            properties:
              sensorId:
                type: string
              valueTemplate:
                type: string
        convergenceTimeout:
          type: integer
        suitableAsQuery:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: unauthenticated
            message: missing X-API-Key header
    Forbidden:
      description: Insufficient permissions (missing required scope)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: permission_denied
            message: 'API key lacks required scope: devices:write'
x-tagGroups:
- name: REST API
  tags:
  - Users
  - Devices
  - Sensors
  - Commands
  - Telemetry
  - Connections
  - Connectors
  - Dashboards
  - Orgs
  - Subscriptions
  - Api-Keys
  - Rules
- name: On-Prem / Advanced (gRPC)
  tags:
  - User Profile (gRPC)
  - Digital Device (gRPC)
  - Sensor Template (gRPC)
  - Connector (gRPC)
  - Connection (gRPC)
  - Dashboard (gRPC)
  - Widget (gRPC)
  - Actuator Command (gRPC)
  - Sensor Query (gRPC)
  - Organizations (gRPC)
  - Access Control (gRPC)
