{
  "openapi": "3.1.0",
  "info": {
    "title": "API pública do evobits",
    "version": "1",
    "description": "Leitura de dispositivos, sensores, medidas, eventos e alertas da empresa, reconhecimento de alertas e agendamento de manutenções. Autenticação por chave `evk_` no cabeçalho `Authorization: Bearer`; limite de requisições por minuto por chave, definido pelo plano."
  },
  "components": {
    "securitySchemes": {
      "chaveApi": {
        "type": "http",
        "scheme": "bearer",
        "description": "Chave `evk_...` criada em Integrações > API."
      }
    },
    "schemas": {}
  },
  "paths": {
    "/api/v1/dispositivos": {
      "get": {
        "summary": "Lista os dispositivos",
        "tags": [
          "Dispositivos"
        ],
        "description": "Em ordem de nome. Uma chave com recorte só vê os dispositivos dos grupos que o grupo de usuários dela lê.\n\nEscopo exigido: `dispositivos.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "grupo",
            "required": false,
            "description": "só os dispositivos deste grupo"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "in": "query",
            "name": "limite",
            "required": false,
            "description": "itens por página (1 a 200)"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "in": "query",
            "name": "cursor",
            "required": false,
            "description": "o `proximo` da página anterior"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "dispositivos.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "endereco": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "tipo": {
                            "type": "string",
                            "enum": [
                              "servidor",
                              "rede",
                              "servico",
                              "outro"
                            ]
                          },
                          "grupo": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "description": "grupo do dispositivo; nulo em \"Não agrupados\"",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "ativo": {
                            "type": "boolean"
                          },
                          "estado": {
                            "type": "string",
                            "enum": [
                              "ok",
                              "atencao",
                              "ruim",
                              "sem_dado"
                            ],
                            "description": "pior estado entre os sensores ativos"
                          },
                          "em_manutencao": {
                            "type": "boolean"
                          },
                          "evento_aberto": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "estado_pior": {
                                "type": "string"
                              },
                              "inicio": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        }
                      }
                    },
                    "proximo": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "description": "cursor da próxima página; nulo na última"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Cria um dispositivo",
        "tags": [
          "Dispositivos"
        ],
        "description": "Uma chave com recorte precisa escolher um grupo gravável. Este primeiro corte não configura SNMP, sonda remota nem VPN.\n\nEscopo exigido: `dispositivos.criar`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "nome"
                ],
                "additionalProperties": false,
                "properties": {
                  "nome": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "endereco": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 253
                  },
                  "grupo_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid"
                  },
                  "tipo": {
                    "type": "string",
                    "enum": [
                      "servidor",
                      "rede",
                      "servico",
                      "outro"
                    ]
                  },
                  "intervalo_padrao_s": {
                    "type": "integer",
                    "minimum": 30,
                    "maximum": 86400
                  },
                  "ativo": {
                    "type": "boolean"
                  },
                  "latitude": {
                    "type": [
                      "number",
                      "null"
                    ],
                    "minimum": -90,
                    "maximum": 90
                  },
                  "longitude": {
                    "type": [
                      "number",
                      "null"
                    ],
                    "minimum": -180,
                    "maximum": 180
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "dispositivos.criar",
        "responses": {
          "201": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "grupo_id": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "uuid"
                    },
                    "sensores_criados": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/dispositivos/{id}": {
      "get": {
        "summary": "Detalhe de um dispositivo",
        "tags": [
          "Dispositivos"
        ],
        "description": "Com os sensores, a disponibilidade do sensor ping por janela e a manutenção vigente.\n\nEscopo exigido: `dispositivos.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "dispositivos.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "endereco": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "tipo": {
                      "type": "string",
                      "enum": [
                        "servidor",
                        "rede",
                        "servico",
                        "outro"
                      ]
                    },
                    "grupo": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "grupo do dispositivo; nulo em \"Não agrupados\"",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "ativo": {
                      "type": "boolean"
                    },
                    "estado": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "atencao",
                        "ruim",
                        "sem_dado"
                      ],
                      "description": "pior estado entre os sensores ativos"
                    },
                    "em_manutencao": {
                      "type": "boolean"
                    },
                    "evento_aberto": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "estado_pior": {
                          "type": "string"
                        },
                        "inicio": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "manutencao_vigente": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "inicio": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "fim": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "motivo": {
                          "type": [
                            "null",
                            "string"
                          ]
                        }
                      }
                    },
                    "pai": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "dispositivo de que este depende",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "intervalo_padrao_s": {
                      "type": [
                        "null",
                        "integer"
                      ]
                    },
                    "uptime_s": {
                      "type": [
                        "null",
                        "number"
                      ]
                    },
                    "ultima_coleta_em": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "disponibilidade": {
                      "type": "object",
                      "description": "percentual do sensor de referência (o primeiro ping ativo) em ok ou atenção sobre o tempo considerado, por janela: manutenção descontada, tempo sem dado fora da conta",
                      "properties": {
                        "24h": {
                          "type": [
                            "null",
                            "number"
                          ]
                        },
                        "7d": {
                          "type": [
                            "null",
                            "number"
                          ]
                        },
                        "30d": {
                          "type": [
                            "null",
                            "number"
                          ]
                        },
                        "1a": {
                          "type": [
                            "null",
                            "number"
                          ]
                        }
                      }
                    },
                    "sensores": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "tipo": {
                            "type": "string"
                          },
                          "chave": {
                            "type": "string"
                          },
                          "ativo": {
                            "type": "boolean"
                          },
                          "intervalo_s": {
                            "type": [
                              "null",
                              "integer"
                            ]
                          },
                          "dispositivo": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "estado": {
                            "type": "string",
                            "enum": [
                              "ok",
                              "atencao",
                              "ruim",
                              "sem_dado",
                              "pausado"
                            ]
                          },
                          "valor": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "valor2": {
                            "type": [
                              "null",
                              "number"
                            ],
                            "description": "segundo canal (saída de porta, perda do ping, usado do disco)"
                          },
                          "unidade": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "desde": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "coletado_em": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/grupos": {
      "get": {
        "summary": "Lista os grupos de dispositivos",
        "tags": [
          "Dispositivos"
        ],
        "description": "A árvore vem pelo `pai_id`. Com recorte, os grupos lidos e os ancestrais deles (só o nome).\n\nEscopo exigido: `dispositivos.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "in": "query",
            "name": "limite",
            "required": false,
            "description": "itens por página (1 a 200)"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "in": "query",
            "name": "cursor",
            "required": false,
            "description": "o `proximo` da página anterior"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "dispositivos.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "pai_id": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "uuid"
                          }
                        }
                      }
                    },
                    "proximo": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "description": "cursor da próxima página; nulo na última"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Cria um grupo de dispositivos",
        "tags": [
          "Dispositivos"
        ],
        "description": "Uma chave com recorte precisa criar o grupo dentro de um grupo pai que possa gravar. Sem recorte, `pai_id` nulo cria um grupo raiz.\n\nEscopo exigido: `dispositivos.criar`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "nome"
                ],
                "additionalProperties": false,
                "properties": {
                  "nome": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "pai_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid"
                  },
                  "ordem": {
                    "type": "integer",
                    "minimum": 0
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "dispositivos.criar",
        "responses": {
          "201": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "pai_id": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "grupo duplicado",
            "content": {
              "application/json": {
                "schema": {
                  "description": "grupo duplicado",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/dispositivos/{id}/sensores": {
      "post": {
        "summary": "Cria um sensor no dispositivo",
        "tags": [
          "Sensores"
        ],
        "description": "Escopo exigido: `dispositivos.criar`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tipo",
                  "config"
                ],
                "additionalProperties": false,
                "properties": {
                  "tipo": {
                    "type": "string"
                  },
                  "nome": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "chave": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "intervalo_s": {
                    "type": "integer",
                    "minimum": 30,
                    "maximum": 86400
                  },
                  "config": {
                    "type": "object"
                  },
                  "limiares": {
                    "type": "object"
                  },
                  "ativo": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "dispositivos.criar",
        "responses": {
          "201": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "dispositivo_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "tipo": {
                      "type": "string"
                    },
                    "chave": {
                      "type": "string"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "ativo": {
                      "type": "boolean"
                    },
                    "intervalo_s": {
                      "type": "integer"
                    },
                    "token": {
                      "type": "string",
                      "description": "presente apenas uma vez na criação de heartbeat; guarde este valor"
                    },
                    "url": {
                      "type": "string",
                      "description": "presente apenas uma vez na criação de heartbeat; guarde este valor"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "sensor já existe",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sensor já existe",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sensores": {
      "get": {
        "summary": "Lista os sensores com o estado atual",
        "tags": [
          "Sensores e medidas"
        ],
        "description": "Em ordem de dispositivo e nome. Sem a configuração do sensor (que pode ter credenciais).\n\nEscopo exigido: `sensores.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "dispositivo",
            "required": false,
            "description": "só os sensores deste dispositivo"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "in": "query",
            "name": "tipo",
            "required": false,
            "description": "tipo do sensor (ex.: ping, snmp_porta)"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "ok",
                "atencao",
                "ruim",
                "sem_dado",
                "pausado"
              ]
            },
            "in": "query",
            "name": "estado",
            "required": false
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "in": "query",
            "name": "limite",
            "required": false,
            "description": "itens por página (1 a 200)"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "in": "query",
            "name": "cursor",
            "required": false,
            "description": "o `proximo` da página anterior"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "sensores.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "tipo": {
                            "type": "string"
                          },
                          "chave": {
                            "type": "string"
                          },
                          "ativo": {
                            "type": "boolean"
                          },
                          "intervalo_s": {
                            "type": [
                              "null",
                              "integer"
                            ]
                          },
                          "dispositivo": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "estado": {
                            "type": "string",
                            "enum": [
                              "ok",
                              "atencao",
                              "ruim",
                              "sem_dado",
                              "pausado"
                            ]
                          },
                          "valor": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "valor2": {
                            "type": [
                              "null",
                              "number"
                            ],
                            "description": "segundo canal (saída de porta, perda do ping, usado do disco)"
                          },
                          "unidade": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "desde": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "coletado_em": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "proximo": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "description": "cursor da próxima página; nulo na última"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sensores/{id}": {
      "get": {
        "summary": "Detalhe de um sensor",
        "tags": [
          "Sensores e medidas"
        ],
        "description": "Escopo exigido: `sensores.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "sensores.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "tipo": {
                      "type": "string"
                    },
                    "chave": {
                      "type": "string"
                    },
                    "ativo": {
                      "type": "boolean"
                    },
                    "intervalo_s": {
                      "type": [
                        "null",
                        "integer"
                      ]
                    },
                    "dispositivo": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "estado": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "atencao",
                        "ruim",
                        "sem_dado",
                        "pausado"
                      ]
                    },
                    "valor": {
                      "type": [
                        "null",
                        "number"
                      ]
                    },
                    "valor2": {
                      "type": [
                        "null",
                        "number"
                      ],
                      "description": "segundo canal (saída de porta, perda do ping, usado do disco)"
                    },
                    "unidade": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "desde": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "coletado_em": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/estado": {
      "get": {
        "summary": "Resumo do estado atual",
        "tags": [
          "Sensores e medidas"
        ],
        "description": "Quantos dispositivos e sensores estão em cada estado agora.\n\nEscopo exigido: `sensores.ler`.",
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "sensores.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "dispositivos": {
                      "type": "object",
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "ok": {
                          "type": "integer"
                        },
                        "atencao": {
                          "type": "integer"
                        },
                        "ruim": {
                          "type": "integer"
                        },
                        "sem_dado": {
                          "type": "integer"
                        }
                      }
                    },
                    "sensores": {
                      "type": "object",
                      "properties": {
                        "total": {
                          "type": "integer"
                        },
                        "ok": {
                          "type": "integer"
                        },
                        "atencao": {
                          "type": "integer"
                        },
                        "ruim": {
                          "type": "integer"
                        },
                        "sem_dado": {
                          "type": "integer"
                        },
                        "pausado": {
                          "type": "integer"
                        }
                      }
                    },
                    "gerado_em": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sensores/{id}/medidas": {
      "get": {
        "summary": "Medidas de um sensor num período",
        "tags": [
          "Sensores e medidas"
        ],
        "description": "`bruto` traz cada leitura (guardadas por 7 dias); `5m`, `1h` e `1d` trazem média, mínimo e máximo do balde. Sem `de` e `ate`, as últimas 24 horas. O histórico respeita o limite do plano. Até 1000 pontos por página.\n\nEscopo exigido: `medidas.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "de",
            "required": false,
            "description": "início, ISO 8601"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "ate",
            "required": false,
            "description": "fim (exclusivo), ISO 8601"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "bruto",
                "5m",
                "1h",
                "1d"
              ],
              "default": "5m"
            },
            "in": "query",
            "name": "agregacao",
            "required": false
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 500
            },
            "in": "query",
            "name": "limite",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "in": "query",
            "name": "cursor",
            "required": false,
            "description": "o `proximo` da página anterior"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "medidas.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "sensor_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "agregacao": {
                      "type": "string",
                      "enum": [
                        "bruto",
                        "5m",
                        "1h",
                        "1d"
                      ]
                    },
                    "de": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "ate": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "unidade": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "tempo": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "valor": {
                            "type": [
                              "null",
                              "number"
                            ],
                            "description": "a leitura (bruto) ou a média do balde"
                          },
                          "valor2": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "min": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "max": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "min2": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "max2": {
                            "type": [
                              "null",
                              "number"
                            ]
                          }
                        }
                      }
                    },
                    "proximo": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "description": "cursor da próxima página; nulo na última"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/eventos": {
      "get": {
        "summary": "Lista os eventos (mudanças de estado)",
        "tags": [
          "Eventos"
        ],
        "description": "Mais recentes primeiro. `desde` e `ate` filtram por sobreposição: um evento ainda aberto aparece.\n\nEscopo exigido: `eventos.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "desde",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "ate",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "dispositivo",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "atencao",
                "ruim"
              ]
            },
            "in": "query",
            "name": "estado",
            "required": false
          },
          {
            "schema": {
              "type": "boolean"
            },
            "in": "query",
            "name": "em_curso",
            "required": false,
            "description": "false exclui os ainda abertos"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "in": "query",
            "name": "limite",
            "required": false,
            "description": "itens por página (1 a 200)"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "in": "query",
            "name": "cursor",
            "required": false,
            "description": "o `proximo` da página anterior"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "eventos.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "dispositivo": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "description": "dispositivo do evento",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "item": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "description": "item da página de status, quando o evento é de um item",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "inicio": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "fim": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "duracao_s": {
                            "type": [
                              "null",
                              "integer"
                            ]
                          },
                          "estado_pior": {
                            "type": "string",
                            "enum": [
                              "atencao",
                              "ruim"
                            ]
                          },
                          "origem": {
                            "type": "string"
                          },
                          "em_curso": {
                            "type": "boolean"
                          },
                          "sensores_gatilho": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "proximo": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "description": "cursor da próxima página; nulo na última"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/eventos/{id}": {
      "get": {
        "summary": "Detalhe de um evento",
        "tags": [
          "Eventos"
        ],
        "description": "Escopo exigido: `eventos.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{1,18}$"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "eventos.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "dispositivo": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "dispositivo do evento",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "item": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "item da página de status, quando o evento é de um item",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "inicio": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "fim": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "duracao_s": {
                      "type": [
                        "null",
                        "integer"
                      ]
                    },
                    "estado_pior": {
                      "type": "string",
                      "enum": [
                        "atencao",
                        "ruim"
                      ]
                    },
                    "origem": {
                      "type": "string"
                    },
                    "em_curso": {
                      "type": "boolean"
                    },
                    "sensores_gatilho": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "estado_anterior": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "gatilho": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "sensor_id": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "nome": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "tipo": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "estado": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "valor": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "unidade": {
                            "type": [
                              "null",
                              "string"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/alertas": {
      "get": {
        "summary": "Lista os alertas",
        "tags": [
          "Alertas"
        ],
        "description": "Ativos: o mais grave e mais antigo primeiro. Resolvidos e todos: o mais recente primeiro.\n\nEscopo exigido: `alertas.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "ativo",
                "resolvido",
                "todos"
              ],
              "default": "ativo"
            },
            "in": "query",
            "name": "estado",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "desde",
            "required": false,
            "description": "abertos a partir de"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "dispositivo",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "atencao",
                "ruim"
              ]
            },
            "in": "query",
            "name": "severidade",
            "required": false
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "in": "query",
            "name": "limite",
            "required": false,
            "description": "itens por página (1 a 200)"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "in": "query",
            "name": "cursor",
            "required": false,
            "description": "o `proximo` da página anterior"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "alertas.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "severidade": {
                            "type": "string",
                            "enum": [
                              "atencao",
                              "ruim"
                            ]
                          },
                          "estado": {
                            "type": "string",
                            "enum": [
                              "aberto",
                              "reconhecido",
                              "fechado"
                            ]
                          },
                          "mensagem": {
                            "type": "string"
                          },
                          "regra": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "description": "regra que abriu o alerta",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "dispositivo": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "description": "dispositivo do alerta",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "sensor": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "description": "sensor do alerta",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "aberto_em": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "reconhecido": {
                            "type": "boolean"
                          },
                          "reconhecido_em": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "reconhecido_origem": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "enum": [
                              "painel",
                              "link",
                              "api",
                              null
                            ]
                          },
                          "silenciado_ate": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "fechado_em": {
                            "type": [
                              "null",
                              "string"
                            ],
                            "format": "date-time"
                          },
                          "fechamento": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "duracao_s": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "proximo": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "description": "cursor da próxima página; nulo na última"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/alertas/{id}": {
      "get": {
        "summary": "Detalhe de um alerta",
        "tags": [
          "Alertas"
        ],
        "description": "Escopo exigido: `alertas.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{1,18}$"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "alertas.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "severidade": {
                      "type": "string",
                      "enum": [
                        "atencao",
                        "ruim"
                      ]
                    },
                    "estado": {
                      "type": "string",
                      "enum": [
                        "aberto",
                        "reconhecido",
                        "fechado"
                      ]
                    },
                    "mensagem": {
                      "type": "string"
                    },
                    "regra": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "regra que abriu o alerta",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "dispositivo": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "dispositivo do alerta",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "sensor": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "sensor do alerta",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "aberto_em": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "reconhecido": {
                      "type": "boolean"
                    },
                    "reconhecido_em": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "reconhecido_origem": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "enum": [
                        "painel",
                        "link",
                        "api",
                        null
                      ]
                    },
                    "silenciado_ate": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "fechado_em": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "fechamento": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "duracao_s": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/alertas/{id}/reconhecer": {
      "post": {
        "summary": "Reconhece um alerta",
        "tags": [
          "Alertas"
        ],
        "description": "Para o escalonamento do alerta. Idempotente: reconhecer de novo devolve o mesmo alerta. Fica na Auditoria da empresa como feito pela chave. Uma chave com recorte só reconhece alerta de dispositivo em grupo com acesso de escrita.\n\nEscopo exigido: `alertas.operar`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "properties": {
                  "comentario": {
                    "type": "string",
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{1,18}$"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "alertas.operar",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "severidade": {
                      "type": "string",
                      "enum": [
                        "atencao",
                        "ruim"
                      ]
                    },
                    "estado": {
                      "type": "string",
                      "enum": [
                        "aberto",
                        "reconhecido",
                        "fechado"
                      ]
                    },
                    "mensagem": {
                      "type": "string"
                    },
                    "regra": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "regra que abriu o alerta",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "dispositivo": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "dispositivo do alerta",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "sensor": {
                      "type": [
                        "null",
                        "object"
                      ],
                      "description": "sensor do alerta",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "nome": {
                          "type": "string"
                        }
                      }
                    },
                    "aberto_em": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "reconhecido": {
                      "type": "boolean"
                    },
                    "reconhecido_em": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "reconhecido_origem": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "enum": [
                        "painel",
                        "link",
                        "api",
                        null
                      ]
                    },
                    "silenciado_ate": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "fechado_em": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "date-time"
                    },
                    "fechamento": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "duracao_s": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "o alerta já está fechado",
            "content": {
              "application/json": {
                "schema": {
                  "description": "o alerta já está fechado",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/manutencoes": {
      "get": {
        "summary": "Lista as janelas de manutenção",
        "tags": [
          "Manutenções"
        ],
        "description": "Mais recentes primeiro (pelo início). `vigentes=true` só as que valem agora; `futuras=true` as vigentes e as que ainda vão começar.\n\nEscopo exigido: `manutencoes.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "grupo",
                "dispositivo",
                "sensor",
                "item"
              ]
            },
            "in": "query",
            "name": "escopo_tipo",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "escopo_id",
            "required": false
          },
          {
            "schema": {
              "type": "boolean"
            },
            "in": "query",
            "name": "vigentes",
            "required": false
          },
          {
            "schema": {
              "type": "boolean"
            },
            "in": "query",
            "name": "futuras",
            "required": false
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "in": "query",
            "name": "limite",
            "required": false,
            "description": "itens por página (1 a 200)"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "in": "query",
            "name": "cursor",
            "required": false,
            "description": "o `proximo` da página anterior"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "manutencoes.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "escopo_tipo": {
                            "type": "string",
                            "enum": [
                              "grupo",
                              "dispositivo",
                              "sensor",
                              "item"
                            ]
                          },
                          "escopo_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "escopo_nome": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "inicio": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "fim": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "motivo": {
                            "type": [
                              "null",
                              "string"
                            ]
                          },
                          "vigente": {
                            "type": "boolean"
                          },
                          "criado_em": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "proximo": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "description": "cursor da próxima página; nulo na última"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Agenda uma janela de manutenção",
        "tags": [
          "Manutenções"
        ],
        "description": "Durante a janela, o alvo continua medido mas não abre evento nem alerta. Uma chave com recorte só agenda em alvo de grupo com acesso de escrita.\n\nEscopo exigido: `manutencoes.escrever`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "escopo_tipo",
                  "escopo_id",
                  "inicio",
                  "fim"
                ],
                "additionalProperties": false,
                "properties": {
                  "escopo_tipo": {
                    "type": "string",
                    "enum": [
                      "grupo",
                      "dispositivo",
                      "sensor",
                      "item"
                    ]
                  },
                  "escopo_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "inicio": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "fim": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "motivo": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "manutencoes.escrever",
        "responses": {
          "201": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "escopo_tipo": {
                      "type": "string",
                      "enum": [
                        "grupo",
                        "dispositivo",
                        "sensor",
                        "item"
                      ]
                    },
                    "escopo_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "escopo_nome": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "inicio": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "fim": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "motivo": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "vigente": {
                      "type": "boolean"
                    },
                    "criado_em": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/manutencoes/{id}": {
      "patch": {
        "summary": "Altera início, fim ou motivo de uma janela",
        "tags": [
          "Manutenções"
        ],
        "description": "O alvo não muda: para outro alvo, apague e crie de novo.\n\nEscopo exigido: `manutencoes.escrever`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "minProperties": 1,
                "additionalProperties": false,
                "properties": {
                  "inicio": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "fim": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "motivo": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "manutencoes.escrever",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "escopo_tipo": {
                      "type": "string",
                      "enum": [
                        "grupo",
                        "dispositivo",
                        "sensor",
                        "item"
                      ]
                    },
                    "escopo_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "escopo_nome": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "inicio": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "fim": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "motivo": {
                      "type": [
                        "null",
                        "string"
                      ]
                    },
                    "vigente": {
                      "type": "boolean"
                    },
                    "criado_em": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Apaga uma janela de manutenção",
        "tags": [
          "Manutenções"
        ],
        "description": "Escopo exigido: `manutencoes.escrever`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "path",
            "name": "id",
            "required": true
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "manutencoes.escrever",
        "responses": {
          "204": {
            "description": "apagada"
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/disponibilidade": {
      "get": {
        "summary": "Disponibilidade de um escopo num período",
        "tags": [
          "Disponibilidade"
        ],
        "description": "A mesma conta dos relatórios do painel: tempo em ok ou atenção do sensor de referência (o primeiro ping ativo do dispositivo) sobre o tempo considerado. Manutenção sempre sai da conta; o tempo sem dado fica fora do denominador e aparece como cobertura (ou conta como fora com `sem_dado_conta_fora=true`); antes do primeiro histórico do sensor não conta. Grupo e empresa são a média ponderada pelo tempo dos dispositivos ativos da subárvore. Período por `mes` (AAAA-MM) ou por `de` e `ate` (dias, até 400 dias), no fuso America/Fortaleza, dentro do histórico do plano.\n\nEscopo exigido: `relatorios.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "empresa",
                "grupo",
                "dispositivo",
                "sensor"
              ],
              "default": "empresa"
            },
            "in": "query",
            "name": "escopo",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "id",
            "required": false,
            "description": "grupo, dispositivo ou sensor (obrigatório fora de `empresa`)"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^\\d{4}-(0[1-9]|1[0-2])$"
            },
            "in": "query",
            "name": "mes",
            "required": false,
            "description": "AAAA-MM"
          },
          {
            "schema": {
              "type": "string",
              "format": "date"
            },
            "in": "query",
            "name": "de",
            "required": false,
            "description": "primeiro dia (AAAA-MM-DD)"
          },
          {
            "schema": {
              "type": "string",
              "format": "date"
            },
            "in": "query",
            "name": "ate",
            "required": false,
            "description": "último dia, inclusive (AAAA-MM-DD)"
          },
          {
            "schema": {
              "type": "boolean",
              "default": false
            },
            "in": "query",
            "name": "sem_dado_conta_fora",
            "required": false
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "relatorios.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "application/json": {
                "schema": {
                  "description": "sucesso",
                  "type": "object",
                  "properties": {
                    "escopo": {
                      "type": "object",
                      "properties": {
                        "tipo": {
                          "type": "string",
                          "enum": [
                            "empresa",
                            "grupo",
                            "dispositivo",
                            "sensor"
                          ]
                        },
                        "id": {
                          "type": [
                            "null",
                            "string"
                          ]
                        },
                        "nome": {
                          "type": [
                            "null",
                            "string"
                          ]
                        }
                      }
                    },
                    "periodo": {
                      "type": "object",
                      "properties": {
                        "inicio": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "fim": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "inicio_efetivo": {
                          "type": "string",
                          "format": "date-time",
                          "description": "o início depois do corte de histórico do plano"
                        },
                        "fim_efetivo": {
                          "type": "string",
                          "format": "date-time",
                          "description": "o fim, cortado em agora no período em andamento"
                        },
                        "parcial": {
                          "type": "boolean"
                        },
                        "fuso": {
                          "type": "string"
                        }
                      }
                    },
                    "sem_dado_conta_fora": {
                      "type": "boolean"
                    },
                    "agregado": {
                      "type": "object",
                      "description": "média ponderada pelo tempo considerado dos dispositivos",
                      "properties": {
                        "disponibilidade_pct": {
                          "type": [
                            "null",
                            "number"
                          ],
                          "description": "ok e atenção sobre o tempo considerado; nulo sem tempo considerado"
                        },
                        "cobertura_pct": {
                          "type": [
                            "null",
                            "number"
                          ],
                          "description": "tempo medido sobre o tempo fora de manutenção"
                        },
                        "considerado_s": {
                          "type": "integer",
                          "description": "denominador: período menos manutenção (e menos sem dado, no padrão)"
                        },
                        "ok_s": {
                          "type": "integer"
                        },
                        "fora_s": {
                          "type": "integer",
                          "description": "tempo em ruim fora de manutenção"
                        },
                        "sem_dado_s": {
                          "type": "integer"
                        },
                        "manutencao_s": {
                          "type": "integer",
                          "description": "tempo em manutenção, descontado da conta"
                        },
                        "dispositivos": {
                          "type": "integer"
                        },
                        "dispositivos_na_conta": {
                          "type": "integer"
                        },
                        "quedas": {
                          "type": "integer"
                        }
                      }
                    },
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "dispositivo": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "sensor": {
                            "type": [
                              "null",
                              "object"
                            ],
                            "description": "sensor de referência; nulo quando o dispositivo não tem ping ativo",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "nome": {
                                "type": "string"
                              }
                            }
                          },
                          "sem_referencia": {
                            "type": "boolean",
                            "description": "sem ping ativo: fora da conta"
                          },
                          "sem_historico": {
                            "type": "boolean",
                            "description": "sem histórico no período: fora da conta"
                          },
                          "disponibilidade_pct": {
                            "type": [
                              "null",
                              "number"
                            ],
                            "description": "ok e atenção sobre o tempo considerado; nulo sem tempo considerado"
                          },
                          "cobertura_pct": {
                            "type": [
                              "null",
                              "number"
                            ],
                            "description": "tempo medido sobre o tempo fora de manutenção"
                          },
                          "considerado_s": {
                            "type": "integer",
                            "description": "denominador: período menos manutenção (e menos sem dado, no padrão)"
                          },
                          "ok_s": {
                            "type": "integer"
                          },
                          "fora_s": {
                            "type": "integer",
                            "description": "tempo em ruim fora de manutenção"
                          },
                          "sem_dado_s": {
                            "type": "integer"
                          },
                          "manutencao_s": {
                            "type": "integer",
                            "description": "tempo em manutenção, descontado da conta"
                          },
                          "quedas": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "dias": {
                      "type": "array",
                      "description": "dia a dia, no fuso America/Fortaleza",
                      "items": {
                        "type": "object",
                        "properties": {
                          "dia": {
                            "type": "string",
                            "format": "date"
                          },
                          "disponibilidade_pct": {
                            "type": [
                              "null",
                              "number"
                            ]
                          },
                          "considerado_s": {
                            "type": "integer"
                          },
                          "fora_s": {
                            "type": "integer"
                          },
                          "sem_dado_s": {
                            "type": "integer"
                          },
                          "manutencao_s": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/medidas.csv": {
      "get": {
        "summary": "Exporta medidas em CSV",
        "tags": [
          "Exportação"
        ],
        "description": "Medidas de um sensor, de um dispositivo, de um grupo ou da empresa inteira (sem `sensor`, `dispositivo` nem `grupo`), no período e na agregação pedidos. Uma linha por canal: `horario` (ISO 8601 no `fuso`), `dispositivo`, `grupo`, `sensor`, `tipo`, `canal`, `unidade`, `minimo`, `media`, `maximo` (mínimo e máximo ficam vazios em `bruto`). Sem `de` e `ate`, as últimas 24 horas; `ate` é exclusivo. Até 200 mil linhas, em streaming; acima disso a resposta é 422 `muitas_linhas`: reduza o período, o escopo, ou use uma agregação maior. O histórico respeita o limite do plano e o recorte da chave; `bruto` existe só dos últimos 7 dias. Em `1d`, o dia é o do `fuso` pedido (UTC sem ele).\n\nEscopo exigido: `medidas.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "sensor",
            "required": false,
            "description": "só as medidas deste sensor"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "dispositivo",
            "required": false,
            "description": "só os sensores deste dispositivo"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "grupo",
            "required": false,
            "description": "só os dispositivos deste grupo e dos subgrupos"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "de",
            "required": false,
            "description": "início, ISO 8601"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "ate",
            "required": false,
            "description": "fim (exclusivo), ISO 8601"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "bruto",
                "5m",
                "1h",
                "1d"
              ],
              "default": "5m"
            },
            "in": "query",
            "name": "agregacao",
            "required": false
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "in": "query",
            "name": "fuso",
            "required": false,
            "description": "nome IANA do fuso dos horários do arquivo (ex.: America/Fortaleza); padrão UTC"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "medidas.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "description": "CSV em UTF-8, vírgula, com cabeçalho"
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "recorte com mais de 200 mil linhas: reduza o período ou o escopo",
            "content": {
              "application/json": {
                "schema": {
                  "description": "recorte com mais de 200 mil linhas: reduza o período ou o escopo",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/eventos.csv": {
      "get": {
        "summary": "Exporta eventos em CSV",
        "tags": [
          "Exportação"
        ],
        "description": "Eventos (mudanças de estado) de um dispositivo, de um grupo, que citam um sensor, ou da empresa inteira, que se sobrepõem ao período. Colunas: `inicio`, `fim` (vazio se em curso), `duracao_s`, `dispositivo`, `grupo`, `item`, `estado`, `origem`, `em_curso`, `sensores`; horários no `fuso`. Sem `de` e `ate`, as últimas 24 horas. Até 200 mil linhas; acima disso, 422 `muitas_linhas`.\n\nEscopo exigido: `eventos.ler`.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "sensor",
            "required": false,
            "description": "só os eventos cujo gatilho cita este sensor"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "dispositivo",
            "required": false,
            "description": "só os sensores deste dispositivo"
          },
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "in": "query",
            "name": "grupo",
            "required": false,
            "description": "só os dispositivos deste grupo e dos subgrupos"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "de",
            "required": false,
            "description": "início, ISO 8601"
          },
          {
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "in": "query",
            "name": "ate",
            "required": false,
            "description": "fim (exclusivo), ISO 8601"
          },
          {
            "schema": {
              "type": "string",
              "maxLength": 100
            },
            "in": "query",
            "name": "fuso",
            "required": false,
            "description": "nome IANA do fuso dos horários do arquivo (ex.: America/Fortaleza); padrão UTC"
          }
        ],
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "eventos.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "description": "CSV em UTF-8, vírgula, com cabeçalho"
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "recorte com mais de 200 mil linhas: reduza o período ou o escopo",
            "content": {
              "application/json": {
                "schema": {
                  "description": "recorte com mais de 200 mil linhas: reduza o período ou o escopo",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/metrics": {
      "get": {
        "summary": "Métricas no formato do Prometheus",
        "tags": [
          "Métricas"
        ],
        "description": "O estado atual da empresa no formato de exposição do Prometheus (`text/plain; version=0.0.4`), para o `scrape_config` com `authorization` do tipo Bearer. Séries: `evobits_sensor_valor`, `evobits_sensor_valor2`, `evobits_sensor_estado` (0 ok, 1 atenção, 2 ruim, 3 sem dado), `evobits_sensor_coletado_timestamp_seconds`, `evobits_dispositivo_estado` e `evobits_alertas_abertos`, com os rótulos `dispositivo`, `grupo`, `sensor`, `tipo` e `unidade`. Nunca sai endereço, IP nem configuração. Uma chave com recorte exporta só os dispositivos do recorte. Raspar a cada 60 s basta.\n\nEscopo exigido: `metricas.ler`.",
        "security": [
          {
            "chaveApi": []
          }
        ],
        "x-escopo": "metricas.ler",
        "responses": {
          "200": {
            "description": "sucesso",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "description": "texto de exposição do Prometheus"
                }
              }
            }
          },
          "400": {
            "description": "parâmetro inválido",
            "content": {
              "application/json": {
                "schema": {
                  "description": "parâmetro inválido",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "chave ausente, inválida, revogada ou vencida",
            "content": {
              "application/json": {
                "schema": {
                  "description": "chave ausente, inválida, revogada ou vencida",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "cadastro bloqueado ou limite do plano",
            "content": {
              "application/json": {
                "schema": {
                  "description": "cadastro bloqueado ou limite do plano",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "escopo insuficiente ou empresa suspensa",
            "content": {
              "application/json": {
                "schema": {
                  "description": "escopo insuficiente ou empresa suspensa",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "não existe ou está fora do recorte da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "não existe ou está fora do recorte da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "limite de requisições por minuto da chave",
            "content": {
              "application/json": {
                "schema": {
                  "description": "limite de requisições por minuto da chave",
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "description": "código do erro"
                    },
                    "message": {
                      "type": "string",
                      "description": "texto em português para quem lê"
                    },
                    "escopo": {
                      "type": "string",
                      "description": "em 403 escopo_insuficiente: o escopo que faltou"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://app.evobits.com.br"
    }
  ],
  "tags": [
    {
      "name": "Dispositivos",
      "description": "Dispositivos e grupos da empresa."
    },
    {
      "name": "Sensores e medidas",
      "description": "Sensores, estado atual e séries de medidas."
    },
    {
      "name": "Eventos",
      "description": "Mudanças de estado dos dispositivos e dos itens da página de status."
    },
    {
      "name": "Alertas",
      "description": "Alertas abertos pelas regras da empresa."
    },
    {
      "name": "Manutenções",
      "description": "Janelas de manutenção planejada."
    },
    {
      "name": "Disponibilidade",
      "description": "Disponibilidade por período, na mesma conta dos relatórios do painel."
    },
    {
      "name": "Exportação",
      "description": "Medidas e eventos em CSV, por escopo e período."
    },
    {
      "name": "Métricas",
      "description": "Exportador no formato de exposição do Prometheus."
    }
  ]
}
