{
  "schema_version": "llms-functions-1.0",
  "nome": "FarMapp API — funções para agents",
  "base_url": "https://farmaperto.onrender.com",
  "openapi": "https://farmapp-2pf.pages.dev/openapi.json",
  "formato_erro": "{\"erro\": true, \"mensagem\": \"<texto>\"} devolvido em todos os 4xx/5xx.",
  "notas": [
    "Nunca inventar IDs (uuid) de farmácia, item de stock ou reserva — obter sempre via GET /api/farmacias. IDs de acesso de farmácia têm 10 dígitos.",
    "Reservas expiram ao fim de 3 horas.",
    "Fora de âmbito: aconselhamento médico, urgências, farmácias fora de Angola."
  ],
  "functions": [
    {
      "type": "function",
      "function": {
        "name": "listarFarmaciasAdmin",
        "description": "GET /api/admin/farmacias — Retorna a lista completa de farmácias registadas, incluindo as congeladas/ desactivadas. O campo `is_ativo` indica o estado. Requer papel `admin`. Para activar/desactivar uma farmácia, usar `PUT /api/farmacias/{id}`.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "obterEstatisticasAdmin",
        "description": "GET /api/admin/stats — Retorna o número total de farmácias (activas, congeladas) e a lista de contas de administração com estado e último login. Requer papel `admin`.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "iniciarSessaoFarmacia",
        "description": "POST /api/auth/farmacia — Autentica uma farmácia usando o seu código de acesso de 10 dígitos (campo `codigo_acesso`). O pedido é registado em `farmacia_acessos` (IP, user-agent, localidade). O token retornou contém `role: 'farmacia'` e `farmacia_id`.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {
            "codigo": {
              "type": "string",
              "description": "ID de 10 dígitos atribuído à farmácia pelo admin. Apenas dígitos são aceites — caracteres não numéricos são ignorados."
            },
            "localidade": {
              "type": [
                "string",
                "null"
              ],
              "description": "Nome da localidade de onde está a aceder (opcional, registado para auditoria)."
            }
          },
          "additionalProperties": false,
          "required": [
            "codigo"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "iniciarSessaoGoogle",
        "description": "POST /api/auth/google — Autentica ou cria uma conta usando o ID token do Google. Se o email ainda não existir, cria automaticamente a conta com `provider: 'google'` e sem password. Se existir (conta de email), faz login directamente. Se o `GOOGLE_CLIENT_ID` não estiver configurado no servidor, retorna 503.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {
            "credential": {
              "type": "string",
              "description": "ID token emitido pelo Google Identity Services (GIS). Gerado no frontend com `google.accounts.id.initialize()`."
            }
          },
          "additionalProperties": false,
          "required": [
            "credential"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "iniciarSessao",
        "description": "POST /api/auth/login — Autentica um utilizador existente pelo email e password. O email é comparado sem distinguir maiúsculas/minúsculas. Se a conta estiver desativada (ex. por um admin), retorna 403. O campo `gestor_admins` é incluído apenas quando `role` é `admin`.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {
            "email": {
              "type": "string",
              "format": "email"
            },
            "password": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": [
            "email",
            "password"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "obterPerfilUtilizador",
        "description": "GET /api/auth/me — Retorna os dados básicos do utilizador cujo token foi usado no pedido. Campos: `id`, `name`, `email`, `role`. Não retorna `telefone` — use `GET /api/perfil/me` para o perfil completo da farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "registarUtilizador",
        "description": "POST /api/auth/register — Regista um novo utilizador no FarMapp. O email tem de ser único — se já estiver registado, retorna 409. A password é hasheada com bcrypt antes de ser guardada. Retorna um token JWT (validade 7 dias) e os dados do utilizador, permitindo fazer login imediatamente.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {
            "nome": {
              "type": "string",
              "minLength": 1,
              "description": "Nome completo do utilizador."
            },
            "email": {
              "type": "string",
              "format": "email",
              "description": "Email único — usado para login."
            },
            "telefone": {
              "type": [
                "string",
                "null"
              ],
              "description": "Número de telefone (opcional, mas recomendado para reservas via SMS)."
            },
            "password": {
              "type": "string",
              "minLength": 6,
              "description": "Palavra-passe (mínimo 6 caracteres)."
            }
          },
          "additionalProperties": false,
          "required": [
            "email",
            "nome",
            "password"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "criarDenuncia",
        "description": "POST /api/denuncias — Regista uma denúncia contra um utilizador que tenha feito reserva nesta farmácia. A denúncia fica com estado `pendente` — os admins avaliam e decidem. A farmácia só pode denunciar utilizadores com reserva associada.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "utilizador_id": {
              "type": "string",
              "format": "uuid",
              "description": "ID do utilizador a denunciar. Tem de ter uma reserva activa ou concluída nesta farmácia."
            },
            "motivo": {
              "type": "string",
              "minLength": 1,
              "description": "Descrição do motivo da denúncia."
            }
          },
          "additionalProperties": false,
          "required": [
            "motivo",
            "utilizador_id"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "listarFarmacias",
        "description": "GET /api/farmacias — Endpoint público — não requer autenticação. Retorna um array de farmácias com dados de contacto, coordenadas GPS, média de avaliações e total. Filtros: `search` + `search_type` (farmacia/medicamento/bairro), `categoria`/`subcategoria` (com medicamento), `latitude`/`longitude` (ordenação por proximidade) e `raio_km` (filtro de raio). Quando `search_type=medicamento`, cada farmácia inclui o array `stock` com os itens correspondentes. Registadores autenticados podem usar `registadas_por_mim=true`.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {
            "search": {
              "type": "string",
              "description": "Texto de pesquisa. Depende de `search_type`: nome/morada/bairro/município da farmácia (default e `farmacia`), item de stock (`medicamento`) ou localidade (`bairro`)."
            },
            "search_type": {
              "type": "string",
              "enum": [
                "farmacia",
                "medicamento",
                "bairro"
              ],
              "default": "farmacia",
              "description": "Tipo de pesquisa: `farmacia` (nome/morada/localidade — default), `medicamento` (itens de stock com o termo) ou `bairro` (arbitro por bairro/município)."
            },
            "categoria": {
              "type": "string",
              "description": "Filtrar por categoria de item de stock (apenas relevante com `search_type=medicamento`)."
            },
            "subcategoria": {
              "type": "string",
              "description": "Filtrar por subcategoria de item de stock (apenas relevante com `search_type=medicamento`)."
            },
            "latitude": {
              "type": "number",
              "format": "double",
              "description": "Latitude do utilizador (decimal). Também aceite como `lat`. Ordena por proximidade quando fornecida com longitude."
            },
            "longitude": {
              "type": "number",
              "format": "double",
              "description": "Longitude do utilizador (decimal). Também aceite como `lng`. Ordena por proximidade quando fornecida com latitude."
            },
            "raio_km": {
              "type": "number",
              "format": "double",
              "minimum": 0,
              "description": "Filtrar por raio máximo em km (requer latitude+longitude)."
            },
            "somente_ativas": {
              "type": "boolean",
              "default": "true",
              "description": "`true` devolve apenas farmácias activas (pagamento regularizado). Utilizadores normais só vêem activas; admins/registadores podem pedir `false`."
            },
            "limite": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50,
              "description": "Número máximo de resultados (padrão: 50)."
            },
            "registadas_por_mim": {
              "type": "boolean",
              "description": "Só para registadores autenticados: `true` devolve apenas farmácias que o próprio registou."
            }
          },
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "criarFarmacia",
        "description": "POST /api/farmacias — Regista uma nova farmácia. Gera automaticamente um código de acesso de 10 dígitos (`codigo_acesso`), envia SMS com o ID à farmácia e notifica todos os admins por email. Requer papel `admin` ou `gestor`. A longitude é guardada internamente em PostGIS (campo `geom`).\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "nome": {
              "type": "string",
              "minLength": 3,
              "description": "Nome da farmácia."
            },
            "telefone": {
              "type": "string",
              "description": "Telefone principal — obrigatório."
            },
            "endereco": {
              "type": [
                "string",
                "null"
              ],
              "description": "Morada / endereço físico."
            },
            "bairro": {
              "type": [
                "string",
                "null"
              ]
            },
            "municipio": {
              "type": [
                "string",
                "null"
              ]
            },
            "latitude": {
              "type": "number",
              "format": "double",
              "description": "Latitude em graus decimais (ex.: -8.8390)."
            },
            "longitude": {
              "type": "number",
              "format": "double",
              "description": "Longitude em graus decimais (ex.: 13.2894)."
            },
            "horario_abertura": {
              "type": [
                "string",
                "null"
              ],
              "description": "Hora de abertura (HH:MM, ex.: '08:00')."
            },
            "horario_fecho": {
              "type": [
                "string",
                "null"
              ]
            },
            "is_24_horas": {
              "type": "boolean",
              "default": false
            },
            "servicos": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Ex.: ['Entrega','Reserva','Atendimento 24h']."
            },
            "notas": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          "additionalProperties": false,
          "required": [
            "latitude",
            "longitude",
            "nome",
            "telefone"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "obterFarmacia",
        "description": "GET /api/farmacias/{id} — Retorna os dados completos de uma farmácia pelo seu UUID — inclui coordenadas, horários, serviços, média e total de avaliações, e o array `stock` com todos os itens disponíveis (quantidade > 0). Não requer autenticação. Retorna 404 se não encontrada.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            }
          },
          "additionalProperties": false,
          "required": [
            "id"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "atualizarFarmacia",
        "description": "PUT /api/farmacias/{id} — Atualiza qualquer campo da farmácia identificada pelo UUID. Requer papel `admin`. A actualização do campo `is_ativo` deve ser feita via `PATCH /api/farmacias/{id}/status`. Retorna os dados actualizados com `latitude` e `longitude` em formato float.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            },
            "nome": {
              "type": "string",
              "minLength": 3
            },
            "telefone": {
              "type": "string"
            },
            "telefone_secundario": {
              "type": [
                "string",
                "null"
              ]
            },
            "endereco": {
              "type": [
                "string",
                "null"
              ]
            },
            "bairro": {
              "type": [
                "string",
                "null"
              ]
            },
            "municipio": {
              "type": [
                "string",
                "null"
              ]
            },
            "latitude": {
              "type": "number",
              "format": "double"
            },
            "longitude": {
              "type": "number",
              "format": "double"
            },
            "horario_abertura": {
              "type": [
                "string",
                "null"
              ]
            },
            "horario_fecho": {
              "type": [
                "string",
                "null"
              ]
            },
            "is_24_horas": {
              "type": "boolean"
            },
            "servicos": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "is_ativo": {
              "type": "boolean"
            },
            "notas": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          "additionalProperties": false,
          "required": [
            "id",
            "latitude",
            "longitude",
            "nome",
            "telefone"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "eliminarFarmacia",
        "description": "DELETE /api/farmacias/{id} — Elimina permanentemente uma farmácia e todos os seus dados associados (stock, avaliações, reservas). Esta operação é irreversível. Requer papel `admin`.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            }
          },
          "additionalProperties": false,
          "required": [
            "id"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "obterAvaliacoesFarmacia",
        "description": "GET /api/farmacias/{id}/avaliacoes — Retorna a média arredondada a 1 casa decimal e o número total de avaliações da farmácia. Não requer autenticação.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            }
          },
          "additionalProperties": false,
          "required": [
            "id"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "avaliarFarmacia",
        "description": "POST /api/farmacias/{id}/avaliacoes — Cria uma avaliação (rating 1–5) para a farmácia. Se o utilizador já tiver avaliado, actualiza a nota existente (upsert). Retorna a avaliação criada/actualizada e as estatísticas actualizadas. Requer autenticação — cada utilizador pode ter apenas uma avaliação por farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            },
            "rating": {
              "type": "integer",
              "enum": [
                1,
                2,
                3,
                4,
                5
              ],
              "description": "Nota de 1 a 5."
            }
          },
          "additionalProperties": false,
          "required": [
            "id",
            "rating"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "getHealth",
        "description": "GET /api/health — Verificação de saúde do backend. Retorna o estado do serviço e a data/hora do servidor. Não requer autenticação. Útil para monitorização e para confirmar que a API está operacional.\nNota: Público, sem autenticação.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "listarMeusAcessos",
        "description": "GET /api/perfil/acessos — Retorna os últimos 20 registos de acesso à conta da farmácia (IP, user-agent, localidade e data). Útil para auditoria de segurança — se detectar acessos estranhos, contacte o suporte.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "actualizarFotoPerfil",
        "description": "POST /api/perfil/foto — Substitui a imagem de perfil da farmácia. Enviar como `multipart/form-data` com o campo `foto` (imagem JPEG/PNG/WebP). Se o R2 estiver activo, a imagem anterior é eliminada do Cloudflare R2. Requer autenticação como farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "foto": {
              "type": "string",
              "format": "binary",
              "description": "Imagem de perfil (JPEG, PNG ou WebP)."
            }
          },
          "additionalProperties": false,
          "required": [
            "foto"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "obterMeuPerfilFarmacia",
        "description": "GET /api/perfil/me — Retorna todos os dados do perfil da farmácia autenticada (nome, telefone, morada, horários, serviços, notas, estado, imagem, cartazes) e o array `stock` completo com todos os itens (incluindo `reservado_ate`). Requer autenticação como farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "actualizarMeuPerfilFarmacia",
        "description": "PUT /api/perfil/me — Actualiza os dados do perfil da farmácia autenticada. O campo `nome` tem de ter pelo menos 3 caracteres e `telefone` é obrigatório. Retorna o perfil e o stock actualizados.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "nome": {
              "type": "string",
              "minLength": 3
            },
            "telefone": {
              "type": "string",
              "description": "Telefone principal — obrigatório para guardar."
            },
            "telefone_secundario": {
              "type": [
                "string",
                "null"
              ]
            },
            "endereco": {
              "type": [
                "string",
                "null"
              ]
            },
            "bairro": {
              "type": [
                "string",
                "null"
              ]
            },
            "municipio": {
              "type": [
                "string",
                "null"
              ]
            },
            "horario_abertura": {
              "type": [
                "string",
                "null"
              ]
            },
            "horario_fecho": {
              "type": [
                "string",
                "null"
              ]
            },
            "is_24_horas": {
              "type": "boolean"
            },
            "servicos": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "notas": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          "additionalProperties": false,
          "required": [
            "nome",
            "telefone"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "listarMeuStock",
        "description": "GET /api/perfil/stock — Retorna todos os itens de stock da farmácia autenticada, ordenados por nome. Inclui `reservado_ate` — se estiver no futuro, o item está reservado. Requer autenticação como farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "criarItemStock",
        "description": "POST /api/perfil/stock — Cria um novo item de stock para a farmácia autenticada. O nome não pode ter mais de 150 caracteres. Requer autenticação como farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "nome": {
              "type": "string",
              "minLength": 1,
              "maxLength": 150,
              "description": "Nome do medicamento ou item."
            },
            "categoria": {
              "type": "string",
              "description": "Categoria (ex.: 'Medicamento', 'Higiene')."
            },
            "subcategoria": {
              "type": "string",
              "description": "Subcategoria (ex.: 'Analgésicos', 'Vitaminas')."
            },
            "quantidade": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "description": "Stock disponível."
            },
            "preco": {
              "type": [
                "number",
                "null"
              ],
              "minimum": 0,
              "description": "Preço em Kz. Null se não definido."
            }
          },
          "additionalProperties": false,
          "required": [
            "categoria",
            "nome",
            "quantidade",
            "subcategoria"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "actualizarItemStock",
        "description": "PUT /api/perfil/stock/{id} — Actualiza todos os campos de um item de stock existente. A validação é idêntica à criação. Requer autenticação como farmácia — o item tem de pertencer à farmácia autenticada.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            },
            "nome": {
              "type": "string",
              "minLength": 1,
              "maxLength": 150,
              "description": "Nome do medicamento ou item."
            },
            "categoria": {
              "type": "string",
              "description": "Categoria (ex.: 'Medicamento', 'Higiene')."
            },
            "subcategoria": {
              "type": "string",
              "description": "Subcategoria (ex.: 'Analgésicos', 'Vitaminas')."
            },
            "quantidade": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "description": "Stock disponível."
            },
            "preco": {
              "type": [
                "number",
                "null"
              ],
              "minimum": 0,
              "description": "Preço em Kz. Null se não definido."
            }
          },
          "additionalProperties": false,
          "required": [
            "categoria",
            "id",
            "nome",
            "quantidade",
            "subcategoria"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "apagarItemStock",
        "description": "DELETE /api/perfil/stock/{id} — Remove permanentemente um item de stock. Requer autenticação como farmácia — o item tem de pertencer à farmácia autenticada.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            }
          },
          "additionalProperties": false,
          "required": [
            "id"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "criarReserva",
        "description": "POST /api/reservas — Reserva um item de stock de uma farmácia durante 3 horas. O stock é automaticamente decrementado e o campo `reservado_ate` é actualizado. A farmácia recebe um SMS de notificação com o nome do utilizador e hora limite. Requer autenticação — o utilizador não pode ser o dono da farmácia (implícito no frontend). Tempo de expiração: 3 horas a partir do momento da reserva.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "stock_item_id": {
              "type": "string",
              "format": "uuid",
              "description": "UUID do item em stock a reservar. O item tem de ter `quantidade > 0` e não pode estar já reservado (campo `reservado_ate` no futuro)."
            },
            "quantidade": {
              "type": "integer",
              "minimum": 1,
              "default": 1,
              "description": "Número de unidades a reservar. Não pode exceder o stock disponível."
            }
          },
          "additionalProperties": false,
          "required": [
            "stock_item_id"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "listarReservasFarmacia",
        "description": "GET /api/reservas — Retorna todas as reservas associadas à farmácia autenticada (token com `role: 'farmacia'`), da mais recente para a mais antiga. Inclui o nome do utilizador, o telefone (para contacto) e o nome do produto. Requer autenticação como farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "listarMinhasReservas",
        "description": "GET /api/reservas/minhas — Retorna todas as reservas feitas pelo utilizador autenticado (token com `role: 'user'`), da mais recente para a mais antiga. Inclui o nome do produto e da farmácia. Requer autenticação.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {},
          "additionalProperties": false
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "aumentarReserva",
        "description": "PATCH /api/reservas/{id}/aumentar — Adiciona unidades a uma reserva existente que esteja no estado `activa`. O stock tem de ser suficiente — caso contrário retorna 409. Requer autenticação e o utilizador tem de ser o dono da reserva.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            },
            "quantidade": {
              "type": "integer",
              "minimum": 1,
              "description": "Número de unidades adicionais a reservar."
            }
          },
          "additionalProperties": false,
          "required": [
            "id",
            "quantidade"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "cancelarReserva",
        "description": "PATCH /api/reservas/{id}/cancelar — Cancela uma reserva activa e repõe automaticamente o stock. Pode ser acionado pelo utilizador dono da reserva ou pela farmácia. Requer autenticação — o utilizador tem de ser o dono da reserva ou a farmácia dona do stock. Retorna erro 409 se a reserva já não estiver activa.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            }
          },
          "additionalProperties": false,
          "required": [
            "id"
          ]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "concluirReserva",
        "description": "PATCH /api/reservas/{id}/concluir — A farmácia confirma que o utilizador recolheu o medicamento. Actualiza o estado da reserva para `concluida` e liberta o campo `reservado_ate` no item de stock. Requer autenticação como farmácia — só pode concluir reservas da própria farmácia.\nNota: REQUER AUTENTICAÇÃO: header 'Authorization: Bearer <token>'. Sem token devolve 401.",
        "parameters": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "description": "UUID do recurso (farmácia, reserva, item, etc.)"
            }
          },
          "additionalProperties": false,
          "required": [
            "id"
          ]
        }
      }
    }
  ]
}