openapi: 3.0.4
info:
  title: Fotokite API
  description: Allows access to all Fotokite Sigma functionality from a single entry
    point.
  version: 1.1.2
servers:
- url: http://192.168.2.100:3128/api
  description: API service running on the system
- url: http://{hostname_or_ip}/api
  description: Unencrypted API anywhere, for development use
  variables:
    hostname_or_ip:
      default: localhost:3128
- url: https://{hostname_or_ip}/api
  description: Encrypted API accessible from outside the Sigma network
  variables:
    hostname_or_ip:
      default: fotokite-sigma.local
- url: https://{gsname}.sigma.fotokite-system.com/api
  description: Hostname used for TLS certificates. The API is not reachable there,
    unless a local DNS override is set.
  variables:
    gsname:
      default: G2628RH
security:
- TokenAuth: []
paths:
  /health:
    get:
      tags:
      - Health
      security:
      - {}
      summary: Get health status
      description: Returns the health status and the version of the Fotokite API.
      responses:
        200:
          description: API is healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
        500:
          description: API is not healthy
          content:
            application/json:
              schema:
                type: string
                example: Service Unavailable
  /v1/health:
    get:
      tags:
      - Health
      security:
      - {}
      summary: Get health status
      description: Returns the health status and the version of the Fotokite API.
      responses:
        200:
          description: API is healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
        500:
          description: API is not healthy
          content:
            application/json:
              schema:
                type: string
                example: Service Unavailable
  /v1/auth/token/request:
    post:
      tags:
      - Authentication
      security:
      - ApiKeyAuth: []
      - {}
      summary: Request a token
      description: 'Initiate a request to obtain an authentication token for accessing
        protected API endpoints. In order to perform authenticated operations, you
        must first obtain a token by calling this endpoint. If the request is denied,
        Fotokite Live may prompt the operator for authorization, depending on system
        configuration. The Fotokite API key can be provided via basic auth or in the
        request body.

        '
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TokenRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/TokenRequest'
      responses:
        200:
          description: Token issued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'
        401:
          description: Unauthorized - Invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        403:
          description: Forbidden - API key valid but insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/auth/token/invalidate:
    post:
      tags:
      - Authentication
      security:
      - TokenAuth: []
      summary: Invalidate a token
      description: 'Invalidate the token used for calling the endpoint.

        '
      responses:
        200:
          description: Token invalidated
        401:
          description: Unauthorized - Invalid or missing API Token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        403:
          description: Forbidden - Token valid but insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        404:
          description: Not found - Specified session does not exist
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/auth/tokens:
    get:
      tags:
      - Authentication
      security:
      - TokenAuth:
        - read
      summary: Get active tokens
      description: 'Returns a list of active tokens

        '
      responses:
        200:
          description: List of sessions
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Session'
        401:
          description: Unauthorized - Invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        403:
          description: Forbidden - API key valid but insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        500:
          $ref: '#/components/responses/InternalError'
  /v1/auth/plugin/update:
    post:
      tags:
      - Authentication
      security:
      - TokenAuth:
        - control
      summary: 'Update plugin state

        '
      description: 'Update the state of a plugin

        '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PluginSelfUpdatableFields'
      responses:
        204:
          description: Updated
        404:
          description: Not found - Specified plugin does not exist
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        401:
          description: Unauthorized - Invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        403:
          description: Forbidden - API key valid but insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        500:
          $ref: '#/components/responses/InternalError'
        422:
          description: Invalid parameters - Request body or parameters are malformed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /v1/{category}/{endpoint}/subscribe:
    get:
      tags:
      - Subscription
      summary: Connect to web socket
      description: This endpoint will allow a connection upgrade to a websocket
      parameters:
      - in: path
        name: category
        description: Category of the endpoint to subscribe to
        required: true
        schema:
          type: string
      - in: path
        name: endpoint
        description: Which endpoint to subscribe to
        required: true
        schema:
          type: string
      responses:
        101:
          description: Websocket connection established.
          headers:
            Set-Cookie:
              schema:
                type: string
                example: connection=websocket:2373d2d1-d22d-4b5a-8fef-67bffdd85aef;
                  Path=/;
        404:
          description: Endpoint does not exist
        405:
          description: Endpoint does not support subscription
    post:
      tags:
      - Subscription
      summary: Subscribe for updates
      parameters:
      - in: path
        name: category
        description: Category of the endpoint to subscribe to
        required: true
        schema:
          type: string
      - in: path
        name: endpoint
        description: Which endpoint to subscribe to
        required: true
        schema:
          type: string
      - in: cookie
        name: connection
        description: Which connection to use
        required: true
        schema:
          type: string
        example: websocket:2373d2d1-d22d-4b5a-8fef-67bffdd85aef
      responses:
        201:
          description: Subscribed
        400:
          description: No such connection
        404:
          description: Endpoint does not exist
        405:
          description: Endpoint does not support subscription
  /v1/notifications/state:
    get:
      tags:
      - Notifications
      security:
      - TokenAuth:
        - read
      summary: Get system notifications
      description: 'Returns all current active notifications. Can be subscribed via
        a WebSocket connection.

        '
      responses:
        200:
          description: Success response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationsObject'
  /v1/notifications/history:
    get:
      tags:
      - Notifications
      security:
      - TokenAuth:
        - read
      summary: Get system notifications
      description: 'Returns system notifications. A notification is a temporary or
        permanent event that reflects the current system state. This could be an error
        state, an alert or a simple message. If the request parameter is empty, all
        currently active notifications will be returned. Every response contains `to_time`
        time point. Up to this time point notifications are fetched. An event gets
        into the response, if the `end_time` is not set or greater or equal to the
        `to_time`. It is recommended to use this point for the next request to not
        miss any notification and to not request the same notifications multiple times.

        '
      parameters:
      - name: from_time
        in: query
        required: false
        description: 'The time from which notifications will be sent (including the
          time point itself). In RFC3339 (section 5.6) format. If this parameter is
          not set then only currently active notifications will be returned.

          '
        schema:
          type: string
          format: date-time
          example: 2025-05-05 13:10:00+00:00
      responses:
        200:
          description: Success response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotificationsObject'
  /v1/notifications/dictionary:
    get:
      tags:
      - Notifications
      security:
      - TokenAuth:
        - read
      summary: Get notifications dictionary
      description: 'Returns the notifications dictionary. The dictionary contains
        all possible notifications that can be sent by the Fotokite system. It is
        recommended to use this endpoint to get the list of all possible notifications
        and their texts to display them to the user.

        '
      responses:
        200:
          description: Success response
          content:
            application/json:
              schema:
                type: array
                description: Notifications dictionary
                items:
                  $ref: '#/components/schemas/NotificationDictionaryItem'
  /v1/handoff/state:
    get:
      tags:
      - Handoff
      security:
      - TokenAuth:
        - read
      summary: Get handoff control state
      description: 'Returns the current handoff control state, including which client
        (Fotokite Live, Fotokite API, or Plugin) currently controls the system and
        which clients have requested control. Subscribing to this endpoint is recommended
        to receive real-time updates.

        '
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HandoffState'
  /v1/handoff/control/request:
    post:
      tags:
      - Handoff
      security:
      - TokenAuth:
        - control
      summary: Request control
      description: 'Requests control of the Fotokite system. If no other client (Fotokite
        Live, Fotokite API, Plugin) is controlling, control is granted. If another
        client is controlling, the request is added to the waiting list (`requesting_clients`)
        in `handoff/state`. A request remains valid for 1 minute; clients should periodically
        re-request control. The result of the request must be monitored using the
        `handoff/state` endpoint.

        '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestHandoffControl'
      responses:
        201:
          description: 'Request to take control was accepted. This means that either
            the system is not controlled right now or the requestor already has control.
            Control will be revoked after 10 seconds. To prevent this, the requestor
            should periodically call `handoff/control/request`.

            '
        202:
          description: 'Request was queued. This means that there is another entity
            controlling the system right now. The requestor should subscribe to the
            `handoff/state` endpoint or poll it to see the result of the request.
            It is also important to note that the request will be cleared after 1
            minute if not taken.

            '
        400:
          $ref: '#/components/responses/WrongInput'
        500:
          $ref: '#/components/responses/InternalError'
  /v1/handoff/control/release:
    post:
      tags:
      - Handoff
      security:
      - TokenAuth:
        - control
      summary: Release control
      description: 'Releases control of the Fotokite system, allowing other clients
        (Fotokite Live, Fotokite API, or Plugin) to take control.

        '
      responses:
        204:
          description: 'Command was released successfully or requesting client successfully
            removed from the waiting queue or no one was controlling.

            '
        500:
          $ref: '#/components/responses/InternalError'
  /v1/handoff/control/override:
    post:
      tags:
      - Handoff
      security:
      - TokenAuth:
        - control
        - can_override
      summary: Override control
      description: 'Immediately enforces control of the Fotokite system, overriding
        other clients (Fotokite Live, Fotokite API, or Plugin) that may be blocking
        access. This endpoint is intended for use mainly by Fotokite Live.

        '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RequestHandoffControl'
      responses:
        201:
          description: 'Success, command taken.

            '
        403:
          description: Failure, current session can't command the system right now.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        500:
          $ref: '#/components/responses/InternalError'
  /v1/system/info:
    get:
      tags:
      - System
      security:
      - TokenAuth:
        - read
      summary: Get system information
      description: Returns system information.
      responses:
        200:
          description: Success execution
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SystemInfo'
  /v1/system/state:
    get:
      tags:
      - System
      security:
      - TokenAuth:
        - read
      summary: Get system state
      description: 'Returns frequently changing system information.

        '
      responses:
        200:
          description: Success execution
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SystemState'
  /v1/system/control/open_rtb_lids:
    post:
      tags:
      - System
      security:
      - TokenAuth:
        - control
      summary: Open Rooftop Box lids
      description: 'Opens the Rooftop Box (RTB) lids. It is not necessary to call
        this endpoint before takeoff, as the system will automatically open the lids
        when needed. This endpoint is intended for maintenance purposes.

        '
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongSystemSetup'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/system/control/close_rtb_lids:
    post:
      tags:
      - System
      security:
      - TokenAuth:
        - control
      summary: Close Rooftop Box lids
      description: 'Closes the Rooftop Box (RTB) lids. It is not necessary to call
        this endpoint after landing, as the system will automatically close the lids
        when needed. This endpoint is intended for maintenance purposes.

        '
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongSystemSetup'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/flight/info:
    get:
      tags:
      - Flight
      security:
      - TokenAuth:
        - read
      summary: Get flight information
      description: 'Returns flight information. Flight information contains properties
        that either do not change (ex. physical limitations) or change rarely (ex.
        legal restrictions).

        '
      responses:
        200:
          description: Success execution
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FlightInfo'
  /v1/flight/state:
    get:
      tags:
      - Flight
      security:
      - TokenAuth:
        - read
      summary: Get flight state
      description: 'Returns frequently changing flight information.

        '
      responses:
        200:
          description: Success execution
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FlightState'
  /v1/flight/control/take_off:
    post:
      tags:
      - Flight
      security:
      - TokenAuth:
        - control
      summary: Take off
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
  /v1/flight/control/land:
    post:
      tags:
      - Flight
      security:
      - TokenAuth:
        - control
      summary: Land
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
  /v1/flight/control/abort:
    post:
      tags:
      - Flight
      security:
      - TokenAuth:
        - control
      summary: Abort take off, landing, or rotation command
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
  /v1/flight/control/altitude:
    post:
      tags:
      - Flight
      security:
      - TokenAuth:
        - control
      summary: Set target altitude
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ControlAltitudeRequest'
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/flight/control/altitude_soft_max:
    post:
      tags:
      - Flight
      security:
      - TokenAuth:
        - control
      summary: Set flight max altitude (soft limit)
      description: 'Sets or updates the Kite flight max altitude (soft limit). If
        the Kite is airborne at an altitude above the new soft limit, it will automatically
        descend to comply with the new limit. Note: this value resets on system reboot.

        '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ControlSoftAltitudeMaxRequest'
      responses:
        204:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/camera/info:
    get:
      tags:
      - Camera
      security:
      - TokenAuth:
        - read
      summary: Get camera information
      description: Returns camera information.
      responses:
        200:
          description: Camera information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CameraInfo'
        404:
          $ref: '#/components/responses/CameraNotFound'
  /v1/camera/state:
    get:
      tags:
      - Camera
      security:
      - TokenAuth:
        - read
      summary: Get camera state
      description: 'Returns camera frequently changing information.

        '
      responses:
        200:
          description: Camera information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CameraState'
        404:
          $ref: '#/components/responses/CameraNotFound'
  /v1/camera/control/rotate_by_angle:
    post:
      tags:
      - Camera
      security:
      - TokenAuth:
        - control
      summary: Rotate by angle
      description: 'Rotates the camera by a given angle. Optionally sets the tilt
        (applies only to the gimbal). For Fotokite Sigma, rotation is achieved through
        a combination of camera gimbal and kite movement.

        '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RotateCameraByAngle'
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        404:
          $ref: '#/components/responses/CameraNotFound'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/camera/control/rotate_to_angle:
    post:
      tags:
      - Camera
      security:
      - TokenAuth:
        - control
      summary: Rotate to angle
      description: 'Rotates the camera to a given angle. Optionally sets the tilt
        (applies only to the gimbal). For Fotokite Sigma, rotation is achieved through
        a combination of camera gimbal and kite movement.

        '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RotateCameraToAngle'
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        404:
          $ref: '#/components/responses/CameraNotFound'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/camera/control/rotate_with_speed:
    post:
      tags:
      - Camera
      security:
      - TokenAuth:
        - control
      summary: Rotate with speed
      description: 'Rotates the camera at a given speed over a duration. To stop rotation
        immediately, set speed to 0. **The Fotokite Sigma is not designed for constant
        unidirectional rotation, as this may twist and damage the tether cable. We
        recommend counteracting rotations (e.g., perform 10 rotations in one direction,
        then 10 in the opposite).**

        '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RotateCameraWithSpeed'
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        404:
          $ref: '#/components/responses/CameraNotFound'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/videostreams:
    get:
      tags:
      - Video streams
      security:
      - TokenAuth:
        - read
      summary: Get video streams information
      description: 'Returns video stream information. URLs for the video streams are
        generated dynamically based on client and network context, which prevents
        this endpoint from supporting subscriptions.

        '
      responses:
        200:
          description: Video stream settings
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/VideoStreamInfo'
              example:
              - stream_id: zoom
                type: Color
                frame_width: 1920
                frame_height: 1080
                sensor_width: 5.952
                sensor_height: 3.348
                lens_focal_length: 2.7
                zoom_min: 1.0
                zoom_max: 32.0
                codec: H.264
                rtsp_url: rtsp://192.168.2.100:554/zoom
                rtsps_url: rtsps://192.168.2.100:322/zoom
                can_do_snapshot: true
              - stream_id: overview
                type: Color
                frame_width: 1920
                frame_height: 1080
                sensor_width: 5.952
                sensor_height: 3.348
                lens_focal_length: 2.7
                zoom_min: 1.0
                zoom_max: 1.0
                codec: H.264
                rtsp_url: rtsp://192.168.2.100:554/wide
                rtsps_url: rtsps://192.168.2.100:322/wide
                can_do_snapshot: true
              - stream_id: thermal
                type: Thermal
                frame_width: 320
                frame_height: 240
                sensor_width: 3.84
                sensor_height: 2.88
                lens_focal_length: 9.1
                zoom_min: 1.0
                zoom_max: 1.0
                codec: H.264
                rtsp_url: rtsp://192.168.2.100:554/thermal
                rtsps_url: rtsps://192.168.2.100:322/thermal
                can_do_snapshot: true
  /v1/videostreams/{stream_id}/state:
    get:
      tags:
      - Video streams
      security:
      - TokenAuth:
        - read
      summary: Get video stream state
      description: Returns frequently changing video stream information for the specified
        video stream.
      parameters:
      - in: path
        name: stream_id
        description: Unique stream identifier.
        required: true
        schema:
          type: string
          example: Zoom
      responses:
        200:
          description: Video stream frequently changing information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoStreamState'
              examples:
                Zoom:
                  value:
                    stream_id: zoom
                    is_streaming: true
                    timestamp: 123456789
                    fov_horizontal: 47.785
                    fov_vertical: 31.8
                    zoom_level: 2.0
                Overview:
                  value:
                    stream_id: overview
                    is_streaming: true
                    timestamp: 583096709
                    fov_horizontal: 95.57
                    fov_vertical: 63.6
                    zoom_level: 1.0
                Thermal:
                  value:
                    stream_id: thermal
                    is_streaming: true
                    timestamp: 2338114
                    fov_horizontal: 23.83
                    fov_vertical: 17.984
                    zoom_level: 1.0
                    thermal_color_palette: Ironbow
        404:
          $ref: '#/components/responses/VideostreamOrCameraNotFound'
  /v1/videostreams/{stream_id}/control/zoom:
    post:
      tags:
      - Video streams
      security:
      - TokenAuth:
        - control
      summary: Set zoom
      description: Sets the zoom level for the specified video stream.
      parameters:
      - in: path
        name: stream_id
        description: Unique stream identifier.
        required: true
        schema:
          type: string
          example: Zoom
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ControlZoomRequest'
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        404:
          $ref: '#/components/responses/VideostreamOrCameraNotFound'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        502:
          $ref: '#/components/responses/BadGateway'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
  /v1/videostreams/{stream_id}/control/palette:
    post:
      tags:
      - Video streams
      security:
      - TokenAuth:
        - control
      summary: Set thermal color palette
      description: Sets the thermal color palette for the specified video stream.
      parameters:
      - in: path
        name: stream_id
        description: Unique stream identifier.
        required: true
        schema:
          type: string
          example: Thermal
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ControlThermalPaletteRequest'
      responses:
        202:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        404:
          $ref: '#/components/responses/VideostreamOrCameraNotFound'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        502:
          $ref: '#/components/responses/BadGateway'
  /v1/videostreams/{stream_id}/snapshot:
    get:
      tags:
      - Video streams
      security:
      - TokenAuth:
        - read
      summary: Get snapshot
      description: Returns a snapshot from the specified video stream.
      parameters:
      - in: path
        name: stream_id
        description: Unique stream identifier.
        required: true
        schema:
          type: string
          example: Zoom
      responses:
        200:
          description: Snapshot image
          content:
            image/jpeg:
              schema:
                type: string
                format: binary
        400:
          $ref: '#/components/responses/WrongInput'
        404:
          $ref: '#/components/responses/VideostreamOrCameraNotFound'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        502:
          $ref: '#/components/responses/BadGateway'
  /v1/recordings:
    get:
      summary: Get video recordings
      description: A recording is a collection of video files (color and thermal)
        and metadata files.
      tags:
      - Recordings
      security:
      - TokenAuth:
        - read
      responses:
        200:
          description: List of video recordings
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Recording'
                example:
                - recording_id: 20260616_132946_+0200
                  is_being_recorded: false
                  videos:
                  - type: color
                    recording_id: 20260616_132946_+0200
                    file_id: main.mp4
                    size: 104857600
                    is_recording: false
                  - type: thermal
                    recording_id: 20260616_132946_+0200
                    file_id: sub.mp4
                    size: 52428800
                    is_recording: false
                - recording_id: 20260617_140000_+0200
                  is_being_recorded: true
                  videos:
                  - type: color
                    recording_id: 20260617_140000_+0200
                    file_id: main.mp4
                    size: 20480000
                    is_recording: true
  /v1/recordings/state:
    get:
      summary: Get video recorder state
      description: Returns the current video recorder state.
      tags:
      - Recordings
      security:
      - TokenAuth:
        - read
      responses:
        200:
          description: Current recorder state
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RecordingsState'
  /v1/recordings/{recording_id}:
    parameters:
    - name: recording_id
      in: path
      required: true
      description: ID of the video recording
      schema:
        type: string
      example: 20260616_132946_+0200
    get:
      summary: Get video recording
      description: Returns a video recording. A video recording is a collection of
        video files (color and thermal) and metadata.
      tags:
      - Recordings
      security:
      - TokenAuth:
        - read
      responses:
        200:
          description: Details of the video recording
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Recording'
        404:
          $ref: '#/components/responses/NotFound'
    delete:
      summary: Delete video recording
      description: Deletes a video recording. A video recording is a collection of
        video files (color and thermal) and metadata.
      tags:
      - Recordings
      security:
      - TokenAuth:
        - control
      responses:
        200:
          $ref: '#/components/responses/CommandSuccess'
        404:
          $ref: '#/components/responses/NotFound'
        502:
          $ref: '#/components/responses/BadGateway'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
        400:
          $ref: '#/components/responses/WrongInput'
  /v1/recordings/{recording_id}/{file_id}:
    parameters:
    - name: recording_id
      in: path
      required: true
      description: ID of the video recording, URL-encoded.
      schema:
        type: string
      example: 20260616_132946_+0200
    - name: file_id
      in: path
      required: true
      description: Identifier of the video file to download, URL-encoded.
      schema:
        type: string
      example: color.mp4
    - name: Range
      in: header
      required: false
      description: Specifies byte range for partial downloads, enabling efficient
        buffering or browser playback.
      schema:
        type: string
      example: bytes=0-1048575
    get:
      summary: Download video
      description: Returns a specific video of a recording.
      tags:
      - Recordings
      security:
      - TokenAuth:
        - read
      responses:
        200:
          description: Full file content
          content:
            video/mp4:
              schema:
                type: string
                format: binary
            image/jpeg:
              schema:
                type: string
                format: binary
        206:
          description: Partial file content
          headers:
            Accept-Ranges:
              description: The range unit supported by the server.
              schema:
                type: string
            Content-Length:
              description: Length of the response body in bytes.
              schema:
                type: integer
                format: int64
            Content-Range:
              description: Content byte range in the response.
              schema:
                type: string
                pattern: ^bytes \d+-\d+/\d+$
              example: bytes 0-1048575/10485760
          content:
            video/mp4:
              schema:
                type: string
                format: binary
        400:
          $ref: '#/components/responses/WrongInput'
        404:
          $ref: '#/components/responses/NotFound'
        502:
          $ref: '#/components/responses/BadGateway'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
        416:
          $ref: '#/components/responses/RangeNotSatisfiable'
  /v1/recordings/control/start:
    post:
      summary: Start video recording
      description: Starts a video recording. A video recording is a collection of
        video files (color and thermal) and metadata.
      tags:
      - Recordings
      security:
      - TokenAuth:
        - control
      responses:
        201:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        502:
          $ref: '#/components/responses/BadGateway'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
        507:
          $ref: '#/components/responses/InsufficientStorage'
  /v1/recordings/control/stop:
    post:
      summary: Stop video recording
      description: Stops the current video recording.
      tags:
      - Recordings
      security:
      - TokenAuth:
        - control
      responses:
        201:
          $ref: '#/components/responses/CommandSuccess'
        400:
          $ref: '#/components/responses/WrongInput'
        403:
          $ref: '#/components/responses/ControlCommandBlocked'
        409:
          $ref: '#/components/responses/NotAllowedInCurrentState'
        502:
          $ref: '#/components/responses/BadGateway'
        503:
          $ref: '#/components/responses/ServiceUnavailable'
        507:
          $ref: '#/components/responses/InsufficientStorage'
components:
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: basic
      description: 'Provide a Fotokite API key as a HTTP basic auth password (user
        name is ignored).

        '
    TokenAuth:
      description: 'Plugin authentication using Bearer token. For more details, see
        [Fotokite API Documentation](https://developer.fotokite.com/~/changes/46/getting-started#authentication).

        '
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: http://192.168.2.100:3128/api/v1/auth/token/request
          scopes:
            read: Grants access to retrieve system data and information.
            control: Allows sending commands to control the system.
            can_override: Allows to make `handoff/control/override` call to override
              current controlling client.
            experimental: Enables access to experimental API features.
            internal: Fotokite-internal functions. Not for third-party use.
  responses:
    BadRequest:
      description: Bad request. This can be a completely malformed request (e.g. request
        body not JSON) or specific parameter values that are outside the acceptable
        limits.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: File Not Found. Endpoint does not exist at all or the object referred
        to is not known.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RangeNotSatisfiable:
      description: Requested Range Not Satisfiable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Internal error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InsufficientStorage:
      description: Insufficient Storage
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    CommandSuccess:
      description: The command was sent successfully
    WrongInput:
      description: Request parameter doesn't meet criteria
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServiceUnavailable:
      description: 'The service is not ready yet. Usually this means that service
        didn''t gather all the necessary information from subsystems.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    VideostreamOrCameraNotFound:
      description: 'The operation requires a camera payload, but either a different
        type of payload is currently installed, or the requested video stream does
        not exist for the installed camera.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    CameraNotFound:
      description: 'The operation requires a camera payload, but a different type
        of payload is currently installed. Please install a compatible camera payload
        to proceed.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotAllowedInCurrentState:
      description: 'The operation is not allowed in current state. Example: Rotation
        is not allowed during landing.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ControlCommandBlocked:
      description: Control is not allowed because somebody else is controlling the
        System.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    BadGateway:
      description: Bad Gateway. The service is not able to communicate with an upstream
        service it depends on.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    WrongSystemSetup:
      description: 'The system is not set up to work as Rooftop Box, so the operation
        cannot be performed.

        '
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    HealthResponse:
      type: object
      description: Health response
      required:
      - status
      - api_version
      properties:
        status:
          description: Health status
          type: string
          example: OK
        api_version:
          description: SemVer version of the Fotokite API.
          type: string
          example: 1.0.1
          x-oapi-codegen-extra-tags:
            fk-default: 1.1.2
    Error:
      type: object
      description: A generic error object.
      required:
      - code
      - message
      properties:
        code:
          description: Unique error code.
          type: string
          example: SOMETHING_WENT_WRONG
        message:
          description: User readable message of the error
          type: string
          example: Something went wrong, please try again later.
    OnlineState:
      type: string
      description: "Online state of the payload.\n  * `Online` - payload is on and\
        \ available to the system.\n  * `Offline` - payload is not available for some\
        \ reason.\n"
      enum:
      - Online
      - Offline
    Scopes:
      type: string
      description: "Available OAuth2 scopes:\n  * `read` - Grants access to retrieve\
        \ system data and information.\n  * `control` - Allows sending commands to\
        \ control the system.\n  * `can_override` - Allows to make `handoff/control/override`\
        \ call to override current controlling client.\n  * `experimental` - Enables\
        \ access to experimental API features.\n  * `internal` - Fotokite-internal\
        \ functions. Not for third-party use.\n"
    TokenRequest:
      type: object
      description: Request to obtain a session token. Compatible with OAuth2 `client_credentials`
        flow.
      required:
      - client_secret
      properties:
        grant_type:
          type: string
          description: 'OAuth2 flow type, only "client_credentials" is supported.

            '
          example: client_credentials
        client_id:
          type: string
          description: 'Ignored (For OAuth compatibility)

            '
          example: ''
        client_secret:
          type: string
          description: 'Fotokite API key. Contact Fotokite support to get an API key
            assigned and activated for your systems.

            '
          example: 1234567890qwertyuiop
        scope:
          type: string
          description: 'Which scopes to request access for. This must be a subset
            of the scopes enabled for the plugin. If more scopes are requested, the
            request will fail. Space separated list.

            '
          example: read control
          allOf:
          - $ref: '#/components/schemas/Scopes'
        token_name:
          type: string
          description: 'Name of the token for display to the operator if there can
            be multiple sessions per plugin.

            '
          example: Flight Controller
    Session:
      type: object
      description: OAuth2 compatible access token response.
      required:
      - id
      - plugin_id
      - scopes
      - access_token
      - created_at
      properties:
        id:
          type: string
          description: 'Unique ID of the session, used to identify the session in
            the system.

            '
          example: 234
        plugin_id:
          type: string
          description: 'Unique ID of the plugin (API) key used to create this session.

            '
          example: pluginAB
        plugin_name:
          type: string
          description: 'Name of the plugin (API) key used to create this session.

            '
          example: Plugin AB
        scopes:
          type: array
          items:
            type: string
          description: 'Scopes granted to this session token.

            '
          example:
          - read
          - control
        name:
          type: string
          description: 'Name of the session for display to the operator.

            '
          example: Flight Controller
        valid_until:
          type: string
          format: date-time
          description: 'Timestamp when this token expires and will no longer be valid.

            '
        created_at:
          type: string
          format: date-time
          description: 'Timestamp when this token was created.

            '
        access_token:
          type: string
          description: 'Token to use for future requests.

            '
          example: ABCD-WXYZ-1234-5678-PQRS
    PluginSelfUpdatableFields:
      type: object
      description: Updatable fields of the plugin to report self status.
      properties:
        plugin_id:
          description: '**DEPRECATED: This field is still accepted for backward compatibility
            but will be removed in the future.**

            '
          deprecated: true
          type: string
          example: pluginAB
        state:
          description: "**DEPRECATED: Use `self_status` instead. This field is still\
            \ accepted for backward compatibility but will be removed in the future.**\
            \ Possible values:\n  * `Disabled` - Operator has not enabled this plugin\
            \ yet.\n  * `Enabled` - Operator has enabled the plugin, but there is\
            \ no active session\n  * `Active` - There is at least one session using\
            \ the plugin key.\n  * `Connected` - The plugin has reported that it is\
            \ operational on any session.\n  * `Error` - The plugin has reported an\
            \ error on any session.\n"
          deprecated: true
          type: string
          example: Disabled
        self_status:
          $ref: '#/components/schemas/PluginSelfStatus'
        self_status_text:
          $ref: '#/components/schemas/PluginStatusText'
    PluginSupervisoryUpdatableFields:
      type: object
      description: 'Updatable fields of a plugin. Can be used by other internal plugins
        to report status of a plugin. If you don''t want to change a plugin aspect
        - just don''t include the corresponding field in the request.

        '
      properties:
        is_enabled:
          type: boolean
          description: 'Request to enable or disable the plugin. This is used by Fotokite
            Live.

            '
          example: true
        state:
          description: "**DEPRECATED: Use `supervisory_status` instead. This field\
            \ is still accepted for backward compatibility but will be removed in\
            \ the future.** Possible values:\n  * `Disabled` - Operator has not enabled\
            \ this plugin yet.\n  * `Enabled` - Operator has enabled the plugin, but\
            \ there is no active session\n  * `Active` - There is at least one session\
            \ using the plugin key.\n  * `Connected` - The plugin has reported that\
            \ it is operational on any session.\n  * `Error` - The plugin has reported\
            \ an error on any session.\n"
          deprecated: true
          type: string
          example: Disabled
        supervisory_status:
          $ref: '#/components/schemas/PluginSupervisoryStatus'
        supervisory_status_text:
          $ref: '#/components/schemas/PluginStatusText'
    ApiKey:
      type: object
      description: Hashed Fotokite API key used by this plugin
      required:
      - key
      properties:
        key:
          type: string
          description: 'Hashed key

            '
        valid_from:
          type: string
    PluginSelfStatus:
      type: string
      description: "Status reported by the plugin code about itself.\n  * `None` or\
        \ `<empty string>` - no additional information about the plugin status is\
        \ available. This is the default status.\n  * `Connected` - the plugin is\
        \ operational and connected to all required backend services.\n  * `Warning`\
        \ - a situation that requires operator attention but is not critical occurred.\n\
        \  * `Error` - an error occurred and must be addressed by the operator.\n"
      example: Connected
    PluginSupervisoryStatus:
      type: string
      description: "Status reported by an internal plugin about another plugin.\n\
        \  * `None` or `<empty string>` - no additional information about the plugin\
        \ status is available. This is the default status.\n  * `Downloading` - plugin\
        \ loader is downloading the plugin (if applicable).\n  * `Warning` - a situation\
        \ that requires operator attention but is not critical occurred.\n  * `Error`\
        \ - an error occurred and must be addressed by the operator.\n"
      example: Downloading
    PluginStatusText:
      type: string
      description: 'Free-form status text reported by the plugin itself or by internal
        plugins. This is shown to the operator in the UI together with the state.
        There is no hard limit on the content of this field, but it is recommended
        to keep it concise and operator-friendly. Recommended max length is 160 characters.
        To reset the status text, send an empty string.

        '
      example: Couldn't connect to back-end service. Please check your Internet connection.
    NotificationDictionaryItem:
      type: object
      description: Notification dictionary item object
      required:
      - code
      - severity
      - message
      properties:
        code:
          description: Notification code
          type: integer
          example: 10032
        severity:
          $ref: '#/components/schemas/NotificationSeverity'
          description: Notification severity
          example: Warning
        message:
          description: Description message
          type: string
          example: Ground Station battery temperature problem.
        system_reaction:
          description: 'System reaction message

            '
          type: string
          example: The temperature is too high to fly.
        instructions:
          description: 'User instructions message

            '
          type: string
          example: Please unplug the system and wait until it cools down.
    NotificationsObject:
      type: object
      description: Notifications object
      required:
      - notifications
      properties:
        from_time:
          description: 'The time from which notifications are sent (including the
            time point itself). In RFC3339 (section 5.6) format. This value typically
            comes from request query parameter. If request parameter is missed then
            only currently active notifications returned and `from_time` is missed.
            If too many notifications were requested then the value is set to the
            `end_time` of the first returned notification.

            '
          type: string
          format: date-time
          example: 2025-05-05 13:10:00+00:00
        to_time:
          description: Current system time up to which notifications were fetched
            (excluding the time point itself). In RFC3339 (section 5.6) format.
          type: string
          format: date-time
          example: 2025-05-05 13:11:02.582000+00:00
        notifications:
          description: Notifications array. If no notifications are registered in
            the time interval from `from_time` to `to_time` then the array is empty.
          type: array
          items:
            $ref: '#/components/schemas/Notification'
    Notification:
      type: object
      description: One notification item
      required:
      - severity
      - code
      - message
      - begin_time
      properties:
        severity:
          $ref: '#/components/schemas/NotificationSeverity'
          description: Notification severity
          example: Warning
        code:
          description: Notification code. See the dictionary for all possible codes.
          type: integer
          example: 10032
        message:
          description: Notification message. This is a human-readable message of the
            notification. It may contain parameters that are used in the notification
            texts.
          type: string
          example: Kite backup battery temperature is too high
        begin_time:
          description: Notification begin time. This is the time point when the notification
            was initially detected. In RFC3339 (section 5.6) format.
          type: string
          format: date-time
          example: 2025-05-05 13:10:00.231000+00:00
        end_time:
          description: Notification end time. This is the time point when the notification
            was gone. In RFC3339 (section 5.6) format. If notification is still not
            gone then the property is absent.
          type: string
          format: date-time
          example: 2025-05-05 13:10:30.853000+00:00
        parameters:
          description: 'Notification parameters. This is a dictionary of key-value
            pairs that are used in the notification texts. The keys are defined in
            the notification code dictionary.

            '
          type: object
          additionalProperties: true
    NotificationSeverity:
      type: string
      description: "Notification severity enumeration.\n  * `Info` - Something happened\
        \ that is not an issue, but may be of interest\n  * `Warning` - Something\
        \ bad happened, but functionality is not affected\n  * `Critical` - Something\
        \ bad happened, some functionality is broken\n  * `Fatal` - Something bad\
        \ happened, system is not functional\n"
      enum:
      - Info
      - Warning
      - Critical
      - Fatal
    HandoffState:
      type: object
      description: Information about connected and controlling entities.
      required:
      - controlling_client
      - requesting_clients
      properties:
        controlling_client:
          $ref: '#/components/schemas/ControllingClient'
          description: 'Information about the entity currently controlling the system.
            If no entity is controlling the system, this field will be null.

            '
        requesting_clients:
          type: array
          items:
            $ref: '#/components/schemas/RequestingClient'
          example:
          - plugin_id: Fotokite Live
            plugin_name: Fotokite Live
            session_id: '3'
            session_name: Fotokite-D
            operator_name: Fotokite-D
            last_change: '2025-08-25T18:48:01.111Z'
          - plugin_id: My cool plugin Id
            plugin_name: My cool plugin
            session_id: '7'
            session_name: Main session
            operator_name: Mr. Handoff
            last_change: '2025-08-25T18:53:11.839Z'
    ControllingClient:
      nullable: true
      type: object
      description: Information about controlling entity.
      required:
      - session_id
      - operator_name
      properties:
        plugin_id:
          type: string
          description: 'Unique ID assigned by Fotokite assigned to this plugin.

            '
        plugin_name:
          type: string
          description: 'Human readable name of the plugin. Has value of `Fotokite
            Live` for Fotokite Live application.

            '
        session_id:
          type: string
          description: 'Unique ID of the session controlling control.

            '
        session_name:
          type: string
          description: 'Name of the session for display to the operator if there can
            be multiple sessions per plugin.

            '
        operator_name:
          type: string
          description: 'Operator name provided to `take_command` or `request_command`
            endpoint.

            '
        last_change:
          type: string
          format: date-time
          description: 'Time when control was taken.

            '
      example:
        plugin_id: My controlling plugin id
        plugin_name: My controlling plugin
        session_id: '5'
        session_name: Only session
        operator_name: Quick brown fox
        last_change: '2025-08-25T18:47:21.191Z'
    RequestingClient:
      type: object
      description: Information about requested control client.
      required:
      - session_id
      - operator_name
      properties:
        plugin_id:
          type: string
          description: 'Unique ID assigned by Fotokite assigned to this plugin.

            '
        plugin_name:
          type: string
          description: 'Human readable name of the plugin. Has value of `Fotokite
            Live` for Fotokite Live application.

            '
        session_id:
          type: string
          description: 'Unique ID of the session requested control.

            '
        session_name:
          type: string
          description: 'Name of the session for display to the operator if there can
            be multiple sessions per plugin.

            '
        operator_name:
          type: string
          description: 'Operator name provided to `take_command` or `request_command`
            endpoint.

            '
        last_change:
          type: string
          format: date-time
          description: 'Time when the entity was added to the waiting queue.

            '
    RequestHandoffControl:
      type: object
      description: Request to take control
      required:
      - operator_name
      properties:
        operator_name:
          type: string
          description: 'Name of the operator taking control for display in UI.

            '
        regulatory_mode:
          $ref: '#/components/schemas/OperatorRegulatoryMode'
        operator_gps_lat:
          description: Latitude of the operator reported by GPS [-90..+90] (degrees)
          type: number
          minimum: -90
          exclusiveMinimum: true
          maximum: 90
        operator_gps_lon:
          description: Longitude of the operator reported by GPS (-180..+180] (degrees)
          type: number
          minimum: -180
          exclusiveMinimum: true
          maximum: 180
        operator_gps_elevation:
          description: Elevation of the operator reported by GPS (meters)
          type: number
        operator_gps_accuracy:
          description: Operator GPS accuracy in meters
          type: number
          minimum: 0
      example:
        operator_name: Mr. Handoff
    OperatorRegulatoryMode:
      type: string
      description: "DroneID regulation variant that the UI provided to the operator\
        \ complies with. DroneID broadcasts such as those required for FAA RemoteID\
        \ contain information about the UAS operator. This endpoint can be used to\
        \ provide such information. An update must be provided regularly according\
        \ to the applicable regulation to prevent entering a DroneID error state (this\
        \ may require sending handoff requests more frequently than it is required\
        \ normally). By setting this value, you declare compliance with the relevant\
        \ regulation. For the US:\n  * An operator location of sufficient accuracy\
        \ is required. A GPS\n    receiver with SBAS augmentation is sufficient.\n\
        \  * Any DroneID error reported by the `/system/state` endpoint must cause\n\
        \    an audiovisual indicator to signal a Remote ID failure to the operator.\n\
        \nPlease refer to FAA 14 CFR Part 89, ASTM F3411 and ASTM F3586 for details.\
        \ **Possible values:**\n  * `US_REMOTE_ID_STANDARD`\n  * `unset`\nIf unset,\
        \ this operator is not considered as a UAS operator, and a RemoteID error\
        \ might occur if regulation requires an operator but no other operator is\
        \ present. If no location information is provided, it is assumed that the\
        \ operator is in direct vicinity of the Ground Station and the Ground Station\
        \ location is used as the operator location.\n"
      example: US_REMOTE_ID_STANDARD
    SystemInfo:
      type: object
      description: Represents system information
      required:
      - gs_name
      - gs_mac
      - installation
      - model
      - timezone
      - timezone_name_short
      - timezone_offset
      - boards
      - software_channel
      - software_version
      properties:
        gs_name:
          description: Identity of the Ground Station
          type: string
          example: G001ZH
        gs_mac:
          description: The MAC address of the router WAN port
          type: string
          example: 00:11:22:33:44:55
        kite_name:
          description: Name of the Kite
          type: string
          example: K2020MF
        rtb_name:
          description: Name of the Rooftop Box (RTB)
          type: string
          example: R001ND
        installation:
          description: "Type of installation. Possible values:\n  * `Transport Case`\n\
            \  * `Tray Mount`\n  * `Rooftop Box`\n  * `Dev Kit`\n  * `Bare Ground\
            \ Station`\n"
          type: string
          example: Rooftop Box
        model:
          description: Model/generation of the Fotokite system
          type: string
          example: Sigma
        propeller_model:
          description: "Model of the propellers used in the system. Possible values:\n\
            \  * `Propeller 1st Generation`\n  * `Propeller 2nd Generation`\n"
          type: string
          example: Propeller 1st Generation
        timezone:
          description: Timezone of the Fotokite system
          type: string
          example: Europe/Zurich
        timezone_name_short:
          description: Short name of the timezone
          type: string
          example: CEST
        timezone_offset:
          description: Offset of the timezone
          type: string
          example: +02:00
        boards:
          type: array
          description: List of system boards
          items:
            $ref: '#/components/schemas/SystemBoard'
        software_channel:
          type: string
          description: System software channel
          example: production
        software_version:
          type: string
          description: System software release version number
          example: '59'
        drone_id:
          $ref: '#/components/schemas/DroneIdInfo'
    SystemBoard:
      type: object
      description: Represents a system board
      required:
      - board
      - id
      properties:
        board:
          type: string
          description: Available system board names
          example: GMC
        id:
          description: 'Unique identifier of a system board (e.g. "001111211136511134311FFF")

            '
          type: string
          example: 001111211136511134311FFF
    SystemState:
      type: object
      description: 'Represents frequently changing system information

        '
      properties:
        kite_battery_level:
          description: Kite backup battery charge level in percents [0..+100]
          type: number
          minimum: 0
          maximum: 100
        gs_battery_level:
          description: Ground Station backup battery charge level in percents [0..+100]
          type: number
          minimum: 0
          maximum: 100
        gs_input_voltage:
          description: Ground Station input voltage (volts)
          type: number
        gs_gps_has_fix:
          description: Whether the data reported by the Ground Station GPS is useable
          type: boolean
        gs_gps_lat:
          description: Latitude reported by Ground Station GPS [-90..+90] (degrees)
          type: number
          minimum: -90
          exclusiveMinimum: true
          maximum: 90
        gs_gps_lon:
          description: Longitude reported by Ground Station GPS (-180..+180] (degrees)
          type: number
          minimum: -180
          exclusiveMinimum: true
          maximum: 180
        gs_gps_elevation:
          description: Elevation reported by Ground Station GPS (meters)
          type: number
        gs_gps_accuracy:
          description: Ground Station GPS accuracy in meters
          type: number
          minimum: 0
        drone_id:
          $ref: '#/components/schemas/DroneIdStatus'
        rtb_lids_state:
          $ref: '#/components/schemas/RTBLidsState'
        rtb_external_safety_land_button_state:
          description: State of the external safety land button connected to the Rooftop
            Box
          type: string
          enum:
          - Pressed
          - NotPressed
        rtb_parking_brake_state:
          description: State of the parking brake on the Rooftop Box. When the parking
            brake is engaged, the system will not take off.
          type: string
          enum:
          - Engaged
          - Disengaged
      example:
        kite_battery_level: 100
        gs_battery_level: 98
        gs_input_voltage: 112
        gs_gps_has_fix: true
        gs_gps_lat: 47.3883959
        gs_gps_lon: 8.5229581
        gs_gps_elevation: 403
        gs_gps_accuracy: 0.31
        drone_id:
          status:
            status: OK
          error_codes: []
        rtb_lids_state: Opened
        rtb_external_safety_land_button_state: NotPressed
        rtb_parking_brake_state: Disengaged
    RTBLidsState:
      type: string
      description: 'Rooftop Box (RTB) lids state

        '
      enum:
      - Closed
      - Opening
      - Opened
      - Closing
    DroneIdInfo:
      type: object
      description: 'Static, system-level DroneID information.

        '
      required:
      - regulatory_mode
      - serial
      properties:
        regulatory_mode:
          $ref: '#/components/schemas/RegulatoryMode'
        serial:
          type: string
          description: ANSI/CTA-2063-A compliant serial number used for DroneID purposes
          example: 1898B0020G9132PH
    DroneIdStatus:
      type: object
      description: The current status of the system
      required:
      - status
      - error_codes
      properties:
        status:
          $ref: '#/components/schemas/DroneIdCheckStatus'
        error_codes:
          type: array
          items:
            $ref: '#/components/schemas/CurrentDroneIDErrorCode'
          description: List of error codes that are currently applicable.
    RegulatoryMode:
      type: string
      description: "DroneID regulation variant that the system needs to comply with.\
        \ The possible values are:\n  * `DISABLED` - DroneID is disabled, no compliance\
        \ provided.\n  * `US_REMOTE_ID_STANDARD` - The system is compliant with the\
        \ US Remote ID Standard.\n  * `UNKNOWN` - Regulatory mode is unknown.\n"
      example: US_REMOTE_ID_STANDARD
    CurrentDroneIDErrorCode:
      description: "Code that describes what is wrong with DroneID. Values prefixed\
        \ with `ERROR_` are hard errors that prevent the preflight check and cause\
        \ DroneID to be non-compliant, while values prefixed with `WARNING_` indicate\
        \ potential issues (data stale, no gps fix).\nThe non-compliant state should\
        \ be indicated in the monitoring application.\nThe possible values are:\n\
        \  * `ERROR_UNKNOWN_REGULATORY_MODE` - Unknown regulatory mode (needs\n  \
        \  config change or software update to fix).\n  * `ERROR_HARDWARE_VARIANT_UNSUITABLE`\
        \ - Hardware variant and regulatory\n    mode configured are incompatible\
        \ (needs hardware changes to fix).\n  * `ERROR_TX_FAILED` - Tx reports failure,\
        \ maybe HW/SW defect (restart might fix it).\n  * `ERROR_TX_WRONG_WIFI_REGION`\
        \ - Transmission is happening, but with the\n    wrong region settings (fix\
        \ by changing wifi region).\n  * `ERROR_TX_WRONG_TRANSMISSION_POWER` - Transmission\
        \ is happening, but\n    with higher or lower power than allowed (fix by changing\
        \ wifi settings/region).\n  * `ERROR_TX_NOT_TRANSMITTING` - Tx(s) that should\
        \ be transmitting, are\n    not (probably hardware malfunction if this persists).\n\
        \  * `ERROR_TX_TRANSMITTING` - At least one Tx is transmitting even though\n\
        \    it should not be (bug in tx software, try restarting).\n  * `ERROR_TX_STALE`\
        \ - Tx is transmitting old data (might be intermittent).\n  * `ERROR_FW_INCOMPATIBLE`\
        \ - The installed firmware doesn't support the\n    DroneID preflight check.\n\
        \  * `ERROR_NO_OPERATOR` - No operator connected that is compatible with DroneID.\n\
        \  * `ERROR_DATA_STALE` - We recently didn't receive required data (from\n\
        \    the kite, or, in the future, tablet). In this case we pretend that the\n\
        \    data is recent but put this alert here.\n  * `WARNING_DATA_INACCURATE`\
        \ - No GPS fix, this is not a failure condition.\n"
      type: string
    DroneIdCheckStatus:
      type: string
      description: "Status of the DroneID check.\n  * `CHECKING` - The check is currently\
        \ running.\n  * `OK` - The check completed successfully.\n  * `FAILED` - The\
        \ check failed.\n  * `EMERGENCY` - The system is in an emergency state.\n"
      example: CHECKING
    FlightInfo:
      type: object
      description: Flight information
      required:
      - altitude_hard_max
      - altitude_soft_max
      properties:
        altitude_takeoff:
          description: 'Kite takeoff altitude (meters). The takeoff altitude is the
            altitude to which the Kite rises after takeoff. **Important: The Kite
            cannot fly lower than the takeoff altitude.**

            '
          type: number
        altitude_hard_max:
          description: 'Maximum altitude (hard limit) of the Fotokite system (meters).
            Hard limit dictated by system capabilities or legal restrictions. The
            Kite cannot fly higher than this altitude.

            '
          type: number
        altitude_soft_max:
          description: 'Maximum altitude (soft limit) of the Fotokite system (meters).
            This value can be set by an operator or API client to limit the maximum
            altitude of the Kite (ex. for safety reasons). This value resets on system
            reboot. The Kite cannot fly higher than this altitude.

            '
          type: number
        total_kite_flight_hours:
          description: 'Total Kite flight time (hours). This value can be used for
            maintenance purposes. Note: initial value can be greater than 0 due to
            pre-delivery testing.

            '
          type: number
          minimum: 0
      example:
        altitude_takeoff: 1.0
        altitude_hard_max: 45.0
        altitude_soft_max: 10.0
        total_kite_flight_hours: 15.3
    FlightState:
      type: object
      description: 'Represents frequently changing flight information. A property
        is not presented if it could not be gathered (for example due to a magnetometer
        or a GPS issue). Note: there is always a margin of error between the `altitude_target`
        and the altitude the Kite will take. And this error is not a constant.

        '
      required:
      - flight_state
      properties:
        flight_state:
          $ref: '#/components/schemas/FlightStateEnum'
        altitude:
          description: Current Kite altitude above the Ground Station (meters)
          type: number
          minimum: 0
        altitude_target:
          description: Target Kite altitude set by the user (meters)
          type: number
          minimum: 0
        kite_heading:
          description: Kite heading [0..+360) (degrees)
          type: number
          minimum: 0
          maximum: 360
          exclusiveMaximum: true
        is_rotating:
          description: 'Whether Kite is rotating (changing heading) (ex. as a result
            of the rotation command). True - Kite is rotating

            '
          type: boolean
        is_changing_altitude:
          description: 'Whether Kite is changing altitude (ex. as a result of the
            set altitude command). True - Kite is changing altitude

            '
          type: boolean
        kite_gps_has_fix:
          description: Whether the data reported by the Kite GPS is useable
          type: boolean
        kite_gps_lat:
          description: Latitude reported by Kite GPS [-90..+90] (degrees)
          type: number
          minimum: -90
          maximum: 90
        kite_gps_lon:
          description: Longitude reported by Kite GPS (-180..+180] (degrees)
          type: number
          minimum: -180
          exclusiveMinimum: true
          maximum: 180
        kite_gps_elevation:
          description: Elevation reported by Kite GPS (meters)
          type: number
        kite_gps_accuracy:
          description: Kite GPS accuracy in meters
          type: number
          minimum: 0
      example:
        flight_state: Flying
        altitude: 40
        altitude_target: 11
        kite_heading: 98
        is_rotating: false
        is_changing_altitude: true
        kite_gps_has_fix: true
        kite_gps_lat: 47.3883959
        kite_gps_lon: 8.5229581
        kite_gps_elevation: 443
        kite_gps_accuracy: 0.23
    FlightStateEnum:
      type: string
      description: "Flight state enumeration\n  * `Unknown` - We couldn't get required\
        \ data to conclude flight sate. This may happen due to numerous reasons:\n\
        \    Kite detached, Kite power is off, etc. More information can be found\
        \ in notifications.\n  * `StandBy` - Kite is on the Ground Station\n  * `TakingOff`\
        \ - Kite is doing preflight checks or taking off\n  * `Flying` - Kite is flying\n\
        \  * `Landing` - Kite is landing\n  * `SafetyLanding` - Kite is landing due\
        \ to a critical issue happened during the flight.\n    More information can\
        \ be found in notifications.\n  * `SafetyDescending` - Kite is descending\
        \ for safety reasons (due to strong wind or weak GPS signal).\n    More information\
        \ can be found in notifications.\n"
      enum:
      - Unknown
      - StandBy
      - TakingOff
      - Flying
      - Landing
      - SafetyLanding
      - SafetyDescending
    ControlAltitudeRequest:
      type: object
      description: Control altitude request data
      required:
      - altitude
      properties:
        altitude:
          description: 'Sets target Kite altitude above the Ground Station (meters).
            Must not be lower than Kite takeoff altitude + 1 meter. But lower than
            both `altitude_hard_limit` and `altitude_soft_limit`. Note: there is always
            a margin of error between the `altitude_target` and the altitude the Kite
            will take. And this error is not a constant.

            '
          type: number
          example: 20
    ControlSoftAltitudeMaxRequest:
      type: object
      description: Control altitude soft limit request data
      required:
      - altitude
      properties:
        altitude:
          description: 'Maximum altitude (soft limit)

            '
          type: number
          example: 20
    CameraInfo:
      type: object
      description: Camera information
      properties:
        model:
          description: "Camera model. Allows to identify the camera type. Possible\
            \ values:\n  * `Camera 1st Generation`. It has one color and one thermal\
            \ module.\n  * `Camera 2nd Generation`. It has two color and one thermal\
            \ module.\n    One color video stream has 32x zoom capabilities. Thermal\
            \ module has resolution of 320x240.\n  * `Camera 2nd Generation IR Plus`.\
            \ It has two color and one thermal module.\n    Thermal module is upgraded\
            \ to a resolution of 640x512.\n"
          type: string
        pan_speed_min:
          description: Minimum absolute pan speed of the camera (degrees/sec)
          type: number
        pan_speed_max:
          description: Maximum absolute pan speed of the camera (degrees/sec)
          type: number
        tilt_speed_min:
          description: Minimum absolute tilt speed of the camera (degrees/sec)
          type: number
        tilt_speed_max:
          description: Maximum absolute tilt speed of the camera (degrees/sec)
          type: number
        tilt_min:
          description: Minimum tilt angle of the camera relative to the kite (degrees)
          type: number
          minimum: -90.0
          maximum: 0.0
        tilt_max:
          description: Maximum tilt angle of the camera relative to the kite (degrees)
          type: number
          minimum: 0.0
          maximum: 90.0
        roll_min:
          description: Minimum roll angle of the camera relative to the kite (degrees)
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 0.0
        roll_max:
          description: Maximum roll angle of the camera relative to the kite (degrees)
          type: number
          minimum: 0.0
          maximum: 180.0
      example:
        model: SigCam2
        pan_speed_min: 2.0
        pan_speed_max: 25.0
        tilt_speed_min: 2.0
        tilt_speed_max: 25.0
        tilt_min: -11.0
        tilt_max: 80.0
        roll_min: 0.0
        roll_max: 0.0
    CameraState:
      type: object
      description: Camera state
      required:
      - online_state
      properties:
        online_state:
          description: 'If `Online` then the camera is powered on and can be used.
            This also means that the data about camera is up-to-date. If `Offline`
            then the camera is powered off or not connected to the system. In this
            case the data about the last online camera is provided. And this information
            may be inaccurate due to payload swap.

            '
          $ref: '#/components/schemas/OnlineState'
          example: Online
        pan_ned:
          description: "Camera pan angle in degrees in NED coordinates.\n  * 0 - The\
            \ camera is looking North.\n  * +90 - The camera is looking East.\n  *\
            \ +180 - The camera is looking South.\n  * -90 - The camera is looking\
            \ West.\n"
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 10.0
        tilt_ned:
          description: "Camera tilt angle in degrees in NED coordinates.\n  * 0 -\
            \ The camera is level, looking straight ahead.\n  * -90 - The camera is\
            \ looking straight up.\n  * +90 - The camera is looking straight down\
            \ towards gravity vector.\n"
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 32.0
        roll_ned:
          description: "Camera roll angle in degrees in NED coordinates.\n  * 0 -\
            \ The camera is level, with the top facing upward.\n  * +90 - The top\
            \ of the camera is rotated to the right.\n  * +180 - The top of the camera\
            \ is facing downward (the same direction as gravity vector).\n  * -90\
            \ - The top of the camera is rotated to the left.\n"
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 0.0
    RotateCameraByAngle:
      type: object
      description: 'Pan Kite and tilt camera by angle command arguments. If a property
        is missed then the Kite or camera will not be rotated in this direction.

        '
      properties:
        pan:
          description: 'Change camera pan by this angle in degrees. Positive value
            means that the camera is rotated to the right.

            '
          type: number
          minimum: -180.0
          maximum: 180.0
          example: 10.0
        tilt:
          description: 'Change camera tilt by this angle in degrees. Positive value
            means that the camera is rotated down.

            '
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 14.0
    RotateCameraToAngle:
      type: object
      description: 'Pan Kite and tilt camera to angle command arguments. If a property
        is missed then the Kite or camera will not be rotated in this direction.

        '
      properties:
        pan_ned:
          description: 'Rotate the camera to the pan specified (in NED coordinates)
            [0..+360) (degrees). 0 - North, 90 - East, 180 - South, 270 - West.

            '
          type: number
          minimum: 0
          maximum: 360
          exclusiveMaximum: true
          example: 90
        tilt_ned:
          description: "Tilt (in NED coordinates) to rotate to in degrees.\n  * 0\
            \ - means that the camera is looking straight forward.\n  * -90 - means\
            \ that the camera is looking straight up.\n  * +90 - means that the camera\
            \ is looking straight down.\n  * +180 - means that the camera is looking\
            \ backward and upside down.\n"
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 10.0
    RotateCameraWithSpeed:
      type: object
      description: Rotate camera with speed command data
      required:
      - duration
      properties:
        pan_speed:
          description: 'Change the camera pan with the angle speed specified. Positive
            value - rotate clockwise (degrees/sec). Negative value - rotate counter-clockwise
            (degrees/sec). 0 - stop any previously commanded pan movement. If parameter
            missed then pan speed is considered to be 0 (no pan). Minimum absolute
            speed is `camera_pan_speed_min` (degrees/sec). Maximum absolute speed
            is `camera_pan_speed_max` (degrees/sec).

            '
          type: number
          example: 11
        tilt_speed:
          description: 'Change the camera tilt with the angle speed specified. Positive
            value - rotate down (degrees/sec). Negative value - rotate up (degrees/sec).
            0 - stop any previously commanded tilt movement. If parameter missed then
            tilt speed is considered to be 0 (no tilt). Minimum absolute speed is
            `camera_tilt_speed_min` (degrees/sec). Maximum absolute speed is `camera_tilt_speed_max`
            (degrees/sec).

            '
          type: number
          example: 20
        duration:
          description: 'Duration of the command in seconds. The camera will rotate
            with the speed specified for the time specified.

            '
          type: number
          minimum: 0.1
          maximum: 10
          example: 5
    VideoStreamInfo:
      type: object
      description: Information about video stream. This information is mostly static
        but may change based on a user request.
      required:
      - stream_id
      - type
      - codec
      - sensor_width
      - sensor_height
      - lens_focal_length
      - zoom_min
      - zoom_max
      - can_do_snapshot
      properties:
        stream_id:
          description: Unique video stream identifier.
          type: string
          example: Zoom
        type:
          $ref: '#/components/schemas/VideoStreamType'
        frame_width:
          description: Video frames width. Presented for fixed resolution encoders.
          type: integer
          example: 1920
        frame_height:
          description: Video frames height. Presented for fixed resolution encoders.
          type: integer
          example: 1080
        sensor_width:
          description: Sensor width in mm.
          type: number
          example: 5.952
        sensor_height:
          description: Sensor height in mm.
          type: number
          example: 3.348
        lens_focal_length:
          description: 'Lens focal length in mm. This value is constant and is not
            affected by zoom. This value corresponds to the `zoom_min` value.

            '
          type: number
          example: 2.7
        zoom_min:
          description: Minimum zoom level.
          type: number
          example: 1.0
        zoom_max:
          description: Maximum zoom level.
          type: number
          example: 32.0
        codec:
          description: "Video codec. Possible values:\n  * `H.264`\n"
          type: string
          example: H.264
        rtsp_url:
          description: RTSP video stream url.
          type: string
          example: rtsp://192.168.2.100:554/thermal
        rtsps_url:
          description: RTSPS encoded video stream url.
          type: string
          example: rtsps://192.168.2.100:322/thermal
        can_do_snapshot:
          description: 'If true then the video stream supports snapshot functionality.
            This means that the video stream can provide a snapshot image.

            '
          type: boolean
          example: true
    VideoStreamType:
      type: string
      description: "Video stream type. Possible values:\n  * `Color` - regular color\
        \ video stream.\n  * `Thermal` - thermal video stream.\n"
    VideoStreamState:
      type: object
      description: Frequently changing information about video stream
      required:
      - stream_id
      - is_streaming
      properties:
        stream_id:
          description: Unique video stream identifier.
          type: string
          example: Zoom
        is_streaming:
          description: 'If true then the video stream is currently streaming.

            '
          type: boolean
          example: true
        timestamp:
          description: 'Video timestamp of the last video frame. For RTP video streams
            this is the RTP timestamp.

            '
          type: number
          example: 123456789
        fov_horizontal:
          description: Horizontal field of view in degrees.
          type: number
          example: 95.57
        fov_vertical:
          description: Vertical field of view in degrees.
          type: number
          example: 63.6
        pan_ned:
          description: "Camera pan angle in degrees in NED coordinates.\n  * 0 - The\
            \ camera is looking North.\n  * +90 - The camera is looking East.\n  *\
            \ +180 - The camera is looking South.\n  * -90 - The camera is looking\
            \ West.\n"
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 10.0
        tilt_ned:
          description: "Camera tilt angle in degrees in NED coordinates.\n  * 0 -\
            \ The camera is level, looking straight ahead.\n  * -90 - The camera is\
            \ looking straight up.\n  * +90 - The camera is looking straight down\
            \ towards gravity vector.\n"
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 32.0
        roll_ned:
          description: "Camera roll angle in degrees in NED coordinates.\n  * 0 -\
            \ The camera is level, with the top facing upward.\n  * +90 - The top\
            \ of the camera is rotated to the right.\n  * +180 - The top of the camera\
            \ is facing downward (the same direction as gravity vector).\n  * -90\
            \ - The top of the camera is rotated to the left.\n"
          type: number
          minimum: -180.0
          exclusiveMinimum: true
          maximum: 180.0
          example: 0.0
        zoom_level:
          description: Current zoom level.
          type: number
          example: 1.0
        thermal_color_palette:
          description: 'Thermal color palette. This property is present only for thermal
            video streams. If the video stream is not thermal then this property is
            absent.

            '
          $ref: '#/components/schemas/ThermalColorPalette'
          example: Ironbow
    ThermalColorPalette:
      type: string
      description: "Thermal color palette. Possible values:\n  * `WhiteHot`\n  * `BlackHot`\n\
        \  * `Rainbow`\n  * `RainbowHighContrast`\n  * `Ironbow`\n  * `Lava`\n  *\
        \ `Arctic`\n  * `Glowbow`\n  * `GradedFire`\n  * `Hottest`\n"
    ControlZoomRequest:
      type: object
      description: Request to set zoom level.
      required:
      - zoom_level
      properties:
        zoom_level:
          description: New zoom level to set. Must be in the range from `zoom_min`
            to `zoom_max`.
          type: number
          example: 2.0
    ControlThermalPaletteRequest:
      type: object
      description: Request to set thermal color palette.
      required:
      - thermal_color_palette
      properties:
        thermal_color_palette:
          description: New thermal color palette to set.
          allOf:
          - $ref: '#/components/schemas/ThermalColorPalette'
          example: Ironbow
    RecordingsState:
      type: object
      description: Current state of the video recorder.
      required:
      - available_space
      - total_space
      - is_recording
      properties:
        recording_id:
          type: string
          description: ID of the recording.
          example: 20260616_132946_+0200
        started_recording_timestamp:
          type: string
          format: date-time
          description: Last time a recording was started since boot, or zero otherwise.
          example: '2023-10-01T12:00:00Z'
        stopped_recording_timestamp:
          type: string
          format: date-time
          description: Last time a recording was stopped, or current time if recording.
          example: '2023-10-01T12:00:00Z'
        is_recording:
          type: boolean
          description: Whether the recorder is currently running.
          example: true
        recording_seconds:
          type: integer
          format: int32
          description: Number of seconds the current recording has been running.
          example: 120
        available_space:
          type: integer
          description: Bytes available to store video recordings
          format: int64
          minimum: 0
        occupied_space:
          type: integer
          description: Bytes currently occupied by video recordings
          format: int64
          minimum: 0
        total_space:
          type: integer
          description: Total bytes available for video recordings
          format: int64
          minimum: 0
    Recording:
      type: object
      description: Represents a video recording, including video files and metadata.
      required:
      - recording_id
      - is_being_recorded
      - videos
      properties:
        recording_id:
          type: string
          description: Identifier of the recording.
          example: 20260616_132946_+0200
        is_being_recorded:
          type: boolean
          description: Whether this recording is currently being recorded.
          example: true
        videos:
          type: array
          items:
            $ref: '#/components/schemas/VideoFile'
    VideoFile:
      description: Represents a video file in a recording, including metadata.
      type: object
      required:
      - type
      - recording_id
      - file_id
      - size
      - is_recording
      properties:
        type:
          $ref: '#/components/schemas/VideoStreamType'
        recording_id:
          type: string
          description: ID of the video recording
          example: 20211126_165209_+0100
        file_id:
          type: string
          description: Identifier of the video file. Used for downloading.
        size:
          type: integer
          format: int64
        is_recording:
          type: boolean
