{
  "openapi": "3.0.3",
  "info": {
    "title": "sondahub Fleet API",
    "version": "0.6.1",
    "description": "An IoT fleet: sites, devices, telemetry and alerts — the MQTT one.\n\nFive hundred devices of eight kinds across forty sites. The readings table holds the last window of telemetry; the live stream and the MQTT broker publish fresh readings every few seconds and accept commands back. Devices report firmware, signal and battery so there is always something to alert on.\n\nNo keys, no accounts. Writes (POST, PUT, PATCH, DELETE) are validated and answered exactly as a real server would answer them, then forgotten: sondahub stores nothing, and every such answer says so in _note and in the X-Sondahub-Write: simulated header. Every list takes page, limit, sort, q, fields and expand, plus one filter per field with the operators _ne _gt _gte _lt _lte _like _in.",
    "contact": {
      "name": "sondahub",
      "url": "https://api.sondahub.com"
    }
  },
  "servers": [
    {
      "url": "https://api.sondahub.com"
    }
  ],
  "tags": [
    {
      "name": "sites",
      "description": "A place devices are installed."
    },
    {
      "name": "devices",
      "description": "A device on a site. Its MQTT topics are fleet/{serial}/telemetry (published by the broker) and fleet/{serial}/commands (you publish)."
    },
    {
      "name": "readings",
      "description": "Telemetry. metrics is an object whose keys depend on the device type (a thermostat reports temperature, humidity and setpoint; a power meter voltage, current, power_kw and energy_kwh)."
    },
    {
      "name": "alerts",
      "description": "Something a device or a site needs looked at. Acknowledge one with PATCH {\"status\":\"acknowledged\"}."
    },
    {
      "name": "commands",
      "description": "A command sent to a device (reboot, set a config value, request a report). POST one and the answer carries the device’s acknowledgement."
    }
  ],
  "paths": {
    "/v1/fleet/sites": {
      "get": {
        "tags": [
          "sites"
        ],
        "summary": "List sites",
        "operationId": "list_sites",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: devices.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "code",
            "in": "query",
            "required": false,
            "description": "Filter: code equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "example": "MIA-01"
            }
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "Filter: name equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "example": "Miami Warehouse"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Filter: kind equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "warehouse",
                "office",
                "plant",
                "store",
                "datacenter",
                "farm",
                "clinic",
                "depot"
              ],
              "nullable": true,
              "example": "warehouse"
            }
          },
          {
            "name": "timezone",
            "in": "query",
            "required": false,
            "description": "Filter: timezone equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "America/New_York"
            }
          },
          {
            "name": "lat",
            "in": "query",
            "required": false,
            "description": "Filter: lat equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true
            }
          },
          {
            "name": "lon",
            "in": "query",
            "required": false,
            "description": "Filter: lon equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true
            }
          },
          {
            "name": "device_count",
            "in": "query",
            "required": false,
            "description": "Filter: device_count equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "readOnly": true
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "maintenance",
                "decommissioned"
              ],
              "nullable": true,
              "example": "active"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "sites"
        ],
        "summary": "Create a site",
        "operationId": "create_site",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/sites/{id}": {
      "get": {
        "tags": [
          "sites"
        ],
        "summary": "Get a site",
        "operationId": "get_site",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "sites"
        ],
        "summary": "Replace a site",
        "operationId": "replace_site",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "sites"
        ],
        "summary": "Update part of a site",
        "operationId": "update_site",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "sites"
        ],
        "summary": "Delete a site",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_site",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/sites/{id}/devices": {
      "get": {
        "tags": [
          "sites"
        ],
        "summary": "The devices of a site",
        "operationId": "site_devices",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of related records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceList"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/devices": {
      "get": {
        "tags": [
          "devices"
        ],
        "summary": "List devices",
        "operationId": "list_devices",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: site, readings, alerts.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "serial",
            "in": "query",
            "required": false,
            "description": "Filter: serial equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "description": "Unique. Also the device’s MQTT topic segment.",
              "example": "TH200-7K2M4Q"
            }
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "Filter: name equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "Thermostat, floor 2 east"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter: type equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "thermostat",
                "power_meter",
                "air_quality",
                "water_meter",
                "gateway",
                "door_sensor",
                "vibration",
                "gps_tracker"
              ],
              "example": "thermostat"
            }
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "description": "Filter: model equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "TH-200"
            }
          },
          {
            "name": "site_id",
            "in": "query",
            "required": false,
            "description": "Filter: site_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a site."
            }
          },
          {
            "name": "firmware",
            "in": "query",
            "required": false,
            "description": "Filter: firmware equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "2.5.2"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "online",
                "offline",
                "degraded",
                "provisioning",
                "retired"
              ],
              "nullable": true,
              "example": "online"
            }
          },
          {
            "name": "battery_pct",
            "in": "query",
            "required": false,
            "description": "Filter: battery_pct equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "null for mains-powered devices.",
              "minimum": 0,
              "maximum": 100
            }
          },
          {
            "name": "rssi_dbm",
            "in": "query",
            "required": false,
            "description": "Filter: rssi_dbm equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true
            }
          },
          {
            "name": "ip",
            "in": "query",
            "required": false,
            "description": "Filter: ip equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "10.4.12.77"
            }
          },
          {
            "name": "mac",
            "in": "query",
            "required": false,
            "description": "Filter: mac equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "02:8f:1c:4a:9e:31"
            }
          },
          {
            "name": "installed_at",
            "in": "query",
            "required": false,
            "description": "Filter: installed_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          },
          {
            "name": "last_seen_at",
            "in": "query",
            "required": false,
            "description": "Filter: last_seen_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "devices"
        ],
        "summary": "Create a device",
        "operationId": "create_device",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/devices/{id}": {
      "get": {
        "tags": [
          "devices"
        ],
        "summary": "Get a device",
        "operationId": "get_device",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "devices"
        ],
        "summary": "Replace a device",
        "operationId": "replace_device",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "devices"
        ],
        "summary": "Update part of a device",
        "operationId": "update_device",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "devices"
        ],
        "summary": "Delete a device",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_device",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/devices/{id}/site": {
      "get": {
        "tags": [
          "devices"
        ],
        "summary": "The site of a device",
        "operationId": "device_site",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/devices/{id}/readings": {
      "get": {
        "tags": [
          "devices"
        ],
        "summary": "The readings of a device",
        "operationId": "device_readings",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of related records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadingList"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/devices/{id}/alerts": {
      "get": {
        "tags": [
          "devices"
        ],
        "summary": "The alerts of a device",
        "operationId": "device_alerts",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of related records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertList"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/readings": {
      "get": {
        "tags": [
          "readings"
        ],
        "summary": "List readings",
        "operationId": "list_readings",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: -recorded_at.",
            "schema": {
              "type": "string",
              "example": "-recorded_at"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: device.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "description": "Filter: device_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a device."
            }
          },
          {
            "name": "recorded_at",
            "in": "query",
            "required": false,
            "description": "Filter: recorded_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "quality",
            "in": "query",
            "required": false,
            "description": "Filter: quality equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "good",
                "estimated",
                "suspect"
              ],
              "nullable": true,
              "example": "good"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadingList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "readings"
        ],
        "summary": "Create a reading",
        "operationId": "create_reading",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReadingInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reading"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/readings/{id}": {
      "get": {
        "tags": [
          "readings"
        ],
        "summary": "Get a reading",
        "operationId": "get_reading",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reading"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "readings"
        ],
        "summary": "Replace a reading",
        "operationId": "replace_reading",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReadingInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reading"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "readings"
        ],
        "summary": "Update part of a reading",
        "operationId": "update_reading",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReadingInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reading"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "readings"
        ],
        "summary": "Delete a reading",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_reading",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/readings/{id}/device": {
      "get": {
        "tags": [
          "readings"
        ],
        "summary": "The device of a reading",
        "operationId": "reading_device",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/alerts": {
      "get": {
        "tags": [
          "alerts"
        ],
        "summary": "List alerts",
        "operationId": "list_alerts",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: -opened_at.",
            "schema": {
              "type": "string",
              "example": "-opened_at"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: device, site.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "description": "Filter: device_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a device."
            }
          },
          {
            "name": "site_id",
            "in": "query",
            "required": false,
            "description": "Filter: site_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "The id of a site."
            }
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "description": "Filter: severity equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "info",
                "warning",
                "critical"
              ],
              "example": "info"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Filter: kind equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "offline",
                "low_battery",
                "threshold",
                "tamper",
                "firmware",
                "weak_signal"
              ],
              "example": "offline"
            }
          },
          {
            "name": "message",
            "in": "query",
            "required": false,
            "description": "Filter: message equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "acknowledged",
                "resolved",
                "muted"
              ],
              "nullable": true,
              "example": "open"
            }
          },
          {
            "name": "opened_at",
            "in": "query",
            "required": false,
            "description": "Filter: opened_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          },
          {
            "name": "acknowledged_at",
            "in": "query",
            "required": false,
            "description": "Filter: acknowledged_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          },
          {
            "name": "resolved_at",
            "in": "query",
            "required": false,
            "description": "Filter: resolved_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          },
          {
            "name": "acknowledged_by",
            "in": "query",
            "required": false,
            "description": "Filter: acknowledged_by equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "alerts"
        ],
        "summary": "Create a alert",
        "operationId": "create_alert",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/alerts/{id}": {
      "get": {
        "tags": [
          "alerts"
        ],
        "summary": "Get a alert",
        "operationId": "get_alert",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "alerts"
        ],
        "summary": "Replace a alert",
        "operationId": "replace_alert",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "alerts"
        ],
        "summary": "Update part of a alert",
        "operationId": "update_alert",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "alerts"
        ],
        "summary": "Delete a alert",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_alert",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/alerts/{id}/device": {
      "get": {
        "tags": [
          "alerts"
        ],
        "summary": "The device of a alert",
        "operationId": "alert_device",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/alerts/{id}/site": {
      "get": {
        "tags": [
          "alerts"
        ],
        "summary": "The site of a alert",
        "operationId": "alert_site",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/commands": {
      "get": {
        "tags": [
          "commands"
        ],
        "summary": "List commands",
        "operationId": "list_commands",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: -created_at.",
            "schema": {
              "type": "string",
              "example": "-created_at"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: device.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "device_id",
            "in": "query",
            "required": false,
            "description": "Filter: device_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a device."
            }
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "description": "Filter: action equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "reboot",
                "set_config",
                "report_now",
                "update_firmware",
                "identify"
              ],
              "example": "reboot"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "queued",
                "sent",
                "acked",
                "failed",
                "expired"
              ],
              "nullable": true,
              "example": "queued"
            }
          },
          {
            "name": "issued_by",
            "in": "query",
            "required": false,
            "description": "Filter: issued_by equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "sent_at",
            "in": "query",
            "required": false,
            "description": "Filter: sent_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          },
          {
            "name": "acked_at",
            "in": "query",
            "required": false,
            "description": "Filter: acked_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommandList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "commands"
        ],
        "summary": "Create a command",
        "operationId": "create_command",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommandInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Command"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/commands/{id}": {
      "get": {
        "tags": [
          "commands"
        ],
        "summary": "Get a command",
        "operationId": "get_command",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Command"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "commands"
        ],
        "summary": "Replace a command",
        "operationId": "replace_command",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommandInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Command"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "commands"
        ],
        "summary": "Update part of a command",
        "operationId": "update_command",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommandInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Command"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "commands"
        ],
        "summary": "Delete a command",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_command",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fleet/commands/{id}/device": {
      "get": {
        "tags": [
          "commands"
        ],
        "summary": "The device of a command",
        "operationId": "command_device",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "example": "validation_failed"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        }
      },
      "ListMeta": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          }
        }
      },
      "Site": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "code": {
            "type": "string",
            "example": "MIA-01"
          },
          "name": {
            "type": "string",
            "example": "Miami Warehouse"
          },
          "kind": {
            "type": "string",
            "enum": [
              "warehouse",
              "office",
              "plant",
              "store",
              "datacenter",
              "farm",
              "clinic",
              "depot"
            ],
            "nullable": true,
            "example": "warehouse"
          },
          "address": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { line1, city, region, postal_code, country }"
          },
          "timezone": {
            "type": "string",
            "nullable": true,
            "example": "America/New_York"
          },
          "lat": {
            "type": "number",
            "nullable": true
          },
          "lon": {
            "type": "number",
            "nullable": true
          },
          "device_count": {
            "type": "integer",
            "nullable": true,
            "readOnly": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "maintenance",
              "decommissioned"
            ],
            "nullable": true,
            "example": "active"
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "code",
          "name",
          "device_count"
        ]
      },
      "SiteInput": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "MIA-01"
          },
          "name": {
            "type": "string",
            "example": "Miami Warehouse"
          },
          "kind": {
            "type": "string",
            "enum": [
              "warehouse",
              "office",
              "plant",
              "store",
              "datacenter",
              "farm",
              "clinic",
              "depot"
            ],
            "nullable": true,
            "example": "warehouse"
          },
          "address": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { line1, city, region, postal_code, country }"
          },
          "timezone": {
            "type": "string",
            "nullable": true,
            "example": "America/New_York"
          },
          "lat": {
            "type": "number",
            "nullable": true
          },
          "lon": {
            "type": "number",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "maintenance",
              "decommissioned"
            ],
            "nullable": true,
            "example": "active"
          }
        },
        "required": [
          "code",
          "name"
        ],
        "example": {
          "code": "MIA-01",
          "name": "Miami Warehouse",
          "kind": "warehouse",
          "timezone": "America/New_York",
          "status": "active"
        }
      },
      "SiteList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Site"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Device": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "serial": {
            "type": "string",
            "description": "Unique. Also the device’s MQTT topic segment.",
            "example": "TH200-7K2M4Q"
          },
          "name": {
            "type": "string",
            "nullable": true,
            "example": "Thermostat, floor 2 east"
          },
          "type": {
            "type": "string",
            "enum": [
              "thermostat",
              "power_meter",
              "air_quality",
              "water_meter",
              "gateway",
              "door_sensor",
              "vibration",
              "gps_tracker"
            ],
            "example": "thermostat"
          },
          "model": {
            "type": "string",
            "nullable": true,
            "example": "TH-200"
          },
          "site_id": {
            "type": "integer",
            "description": "The id of a site."
          },
          "firmware": {
            "type": "string",
            "nullable": true,
            "example": "2.5.2"
          },
          "status": {
            "type": "string",
            "enum": [
              "online",
              "offline",
              "degraded",
              "provisioning",
              "retired"
            ],
            "nullable": true,
            "example": "online"
          },
          "battery_pct": {
            "type": "integer",
            "nullable": true,
            "description": "null for mains-powered devices.",
            "minimum": 0,
            "maximum": 100
          },
          "rssi_dbm": {
            "type": "integer",
            "nullable": true
          },
          "ip": {
            "type": "string",
            "nullable": true,
            "example": "10.4.12.77"
          },
          "mac": {
            "type": "string",
            "nullable": true,
            "example": "02:8f:1c:4a:9e:31"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Shape: string[]"
          },
          "config": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { report_interval_s, thresholds? }"
          },
          "installed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "serial",
          "type",
          "site_id"
        ]
      },
      "DeviceInput": {
        "type": "object",
        "properties": {
          "serial": {
            "type": "string",
            "description": "Unique. Also the device’s MQTT topic segment.",
            "example": "TH200-7K2M4Q"
          },
          "name": {
            "type": "string",
            "nullable": true,
            "example": "Thermostat, floor 2 east"
          },
          "type": {
            "type": "string",
            "enum": [
              "thermostat",
              "power_meter",
              "air_quality",
              "water_meter",
              "gateway",
              "door_sensor",
              "vibration",
              "gps_tracker"
            ],
            "example": "thermostat"
          },
          "model": {
            "type": "string",
            "nullable": true,
            "example": "TH-200"
          },
          "site_id": {
            "type": "integer",
            "description": "The id of a site."
          },
          "firmware": {
            "type": "string",
            "nullable": true,
            "example": "2.5.2"
          },
          "status": {
            "type": "string",
            "enum": [
              "online",
              "offline",
              "degraded",
              "provisioning",
              "retired"
            ],
            "nullable": true,
            "example": "online"
          },
          "battery_pct": {
            "type": "integer",
            "nullable": true,
            "description": "null for mains-powered devices.",
            "minimum": 0,
            "maximum": 100
          },
          "rssi_dbm": {
            "type": "integer",
            "nullable": true
          },
          "ip": {
            "type": "string",
            "nullable": true,
            "example": "10.4.12.77"
          },
          "mac": {
            "type": "string",
            "nullable": true,
            "example": "02:8f:1c:4a:9e:31"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Shape: string[]"
          },
          "config": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { report_interval_s, thresholds? }"
          },
          "installed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_seen_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "serial",
          "type",
          "site_id"
        ],
        "example": {
          "serial": "TH200-7K2M4Q",
          "name": "Thermostat, floor 2 east",
          "type": "thermostat",
          "model": "TH-200",
          "site_id": 1,
          "firmware": "2.5.2",
          "status": "online",
          "ip": "10.4.12.77",
          "mac": "02:8f:1c:4a:9e:31"
        }
      },
      "DeviceList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Device"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Reading": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "device_id": {
            "type": "integer",
            "description": "The id of a device."
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time"
          },
          "metrics": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { [metric]: number | boolean }"
          },
          "quality": {
            "type": "string",
            "enum": [
              "good",
              "estimated",
              "suspect"
            ],
            "nullable": true,
            "example": "good"
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "device_id",
          "recorded_at",
          "metrics"
        ]
      },
      "ReadingInput": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "integer",
            "description": "The id of a device."
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time"
          },
          "metrics": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { [metric]: number | boolean }"
          },
          "quality": {
            "type": "string",
            "enum": [
              "good",
              "estimated",
              "suspect"
            ],
            "nullable": true,
            "example": "good"
          }
        },
        "required": [
          "device_id",
          "recorded_at",
          "metrics"
        ],
        "example": {
          "device_id": 1,
          "recorded_at": "2026-09-30T12:00:00Z",
          "metrics": {},
          "quality": "good"
        }
      },
      "ReadingList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Reading"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Alert": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "device_id": {
            "type": "integer",
            "description": "The id of a device."
          },
          "site_id": {
            "type": "integer",
            "nullable": true,
            "description": "The id of a site."
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warning",
              "critical"
            ],
            "example": "info"
          },
          "kind": {
            "type": "string",
            "enum": [
              "offline",
              "low_battery",
              "threshold",
              "tamper",
              "firmware",
              "weak_signal"
            ],
            "example": "offline"
          },
          "message": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "acknowledged",
              "resolved",
              "muted"
            ],
            "nullable": true,
            "example": "open"
          },
          "opened_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acknowledged_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acknowledged_by": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "device_id",
          "severity",
          "kind"
        ]
      },
      "AlertInput": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "integer",
            "description": "The id of a device."
          },
          "site_id": {
            "type": "integer",
            "nullable": true,
            "description": "The id of a site."
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warning",
              "critical"
            ],
            "example": "info"
          },
          "kind": {
            "type": "string",
            "enum": [
              "offline",
              "low_battery",
              "threshold",
              "tamper",
              "firmware",
              "weak_signal"
            ],
            "example": "offline"
          },
          "message": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "acknowledged",
              "resolved",
              "muted"
            ],
            "nullable": true,
            "example": "open"
          },
          "opened_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acknowledged_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "resolved_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acknowledged_by": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "device_id",
          "severity",
          "kind"
        ],
        "example": {
          "device_id": 1,
          "severity": "info",
          "kind": "offline",
          "status": "open"
        }
      },
      "AlertList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Alert"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Command": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "device_id": {
            "type": "integer",
            "description": "The id of a device."
          },
          "action": {
            "type": "string",
            "enum": [
              "reboot",
              "set_config",
              "report_now",
              "update_firmware",
              "identify"
            ],
            "example": "reboot"
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: object"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sent",
              "acked",
              "failed",
              "expired"
            ],
            "nullable": true,
            "example": "queued"
          },
          "issued_by": {
            "type": "string",
            "nullable": true
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "result": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: object"
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "device_id",
          "action"
        ]
      },
      "CommandInput": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "integer",
            "description": "The id of a device."
          },
          "action": {
            "type": "string",
            "enum": [
              "reboot",
              "set_config",
              "report_now",
              "update_firmware",
              "identify"
            ],
            "example": "reboot"
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: object"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sent",
              "acked",
              "failed",
              "expired"
            ],
            "nullable": true,
            "example": "queued"
          },
          "issued_by": {
            "type": "string",
            "nullable": true
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "result": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: object"
          }
        },
        "required": [
          "device_id",
          "action"
        ],
        "example": {
          "device_id": 1,
          "action": "reboot",
          "status": "queued"
        }
      },
      "CommandList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Command"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      }
    }
  }
}