{
  "openapi": "3.1.0",
  "info": {
    "title": "mATRIC API",
    "summary": "REST API for the Multi Access Technology Intelligent Controller",
    "description": "\nmATRIC unifies 5G, WiFi and LiFi under a single management framework. This API is\nthe interface to the platform for three kinds of caller, each authenticating\nthrough the same token endpoint with its own login type.\n\n**Users** manage the platform. Administrators register agents and third party\napplications, and manage user accounts. Anyone may register through the public\nsignup endpoint and receives a standard user role.\n\n**Agents** run on access points. Each agent authenticates, onboards itself with\nits configuration and geolocation, and then posts telemetry on a regular\nschedule.\n\n**Third party applications** consume the platform. They request the details of\nactive agents, retrieve historical data for a chosen agent and time range, and\nsend commands back to the network. Results and subscribed data streams return\nthrough callback endpoints identified by a job number.\n\nEvery call except authentication and public registration requires a bearer\ntoken in the Authorization header.\n",
    "contact": {
      "name": "Smart Internet Lab, University of Bristol",
      "url": "https://www.bristol.ac.uk/engineering/research/smart/"
    },
    "license": {
      "name": "BSD 3 Clause Licence",
      "url": "https://github.com/mATRIC-Platforms/mATRIC-master/blob/master/LICENSE"
    },
    "version": "1.0.0"
  },
  "paths": {
    "/api/v1/token/": {
      "post": {
        "tags": [
          "token"
        ],
        "summary": "Login",
        "operationId": "login_api_v1_token__post",
        "parameters": [
          {
            "name": "login_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Login type: user, agent or third_party_app",
              "title": "Login Type"
            },
            "description": "Login type: user, agent or third_party_app"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/Body_login_api_v1_token__post"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Token"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/public": {
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Create First User",
        "operationId": "create_first_user_api_v1_users_public_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenData"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/signup": {
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Register User",
        "operationId": "register_user_api_v1_users_signup_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserRegister"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenData"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/password-recovery": {
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Recover Password",
        "operationId": "recover_password_api_v1_users_password_recovery_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PasswordRecoveryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "title": "Response Recover Password Api V1 Users Password Recovery Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/reset-password": {
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Reset Password",
        "operationId": "reset_password_api_v1_users_reset_password_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PasswordReset"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "title": "Response Reset Password Api V1 Users Reset Password Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "List Users",
        "operationId": "list_users_api_v1_users__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TokenData"
                  },
                  "type": "array",
                  "title": "Response List Users Api V1 Users  Get"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      },
      "post": {
        "tags": [
          "users"
        ],
        "summary": "Create User",
        "operationId": "create_user_api_v1_users__post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenData"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/users/{username}": {
      "put": {
        "tags": [
          "users"
        ],
        "summary": "Update User",
        "operationId": "update_user_api_v1_users__username__put",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Username"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenData"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "users"
        ],
        "summary": "Delete User",
        "operationId": "delete_user_api_v1_users__username__delete",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Username"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "title": "Response Delete User Api V1 Users  Username  Delete"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "users"
        ],
        "summary": "Get User",
        "operationId": "get_user_api_v1_users__username__get",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Username"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenData"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/users/me": {
      "get": {
        "tags": [
          "users"
        ],
        "summary": "Read Users Me",
        "operationId": "read_users_me_api_v1_users_me_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenData"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/agents/public": {
      "post": {
        "tags": [
          "agents"
        ],
        "summary": "Create First Agent",
        "operationId": "create_first_agent_api_v1_agents_public_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/agents/": {
      "post": {
        "tags": [
          "agents"
        ],
        "summary": "Create Agent",
        "operationId": "create_agent_api_v1_agents__post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/agents/{ap_id}": {
      "get": {
        "tags": [
          "agents"
        ],
        "summary": "Get Agent",
        "operationId": "get_agent_api_v1_agents__ap_id__get",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "ap_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Ap Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "agents"
        ],
        "summary": "Update Agent",
        "operationId": "update_agent_api_v1_agents__ap_id__put",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "ap_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Ap Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Agent"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "agents"
        ],
        "summary": "Delete Agent",
        "operationId": "delete_agent_api_v1_agents__ap_id__delete",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "ap_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Ap Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "title": "Response Delete Agent Api V1 Agents  Ap Id  Delete"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/third_party_apps/": {
      "post": {
        "tags": [
          "third_party_apps"
        ],
        "summary": "Create Third Party App",
        "operationId": "create_third_party_app_api_v1_third_party_apps__post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThirdPartyAppCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThirdPartyApp"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/third_party_apps/{app_name}": {
      "get": {
        "tags": [
          "third_party_apps"
        ],
        "summary": "Get Third Party App",
        "operationId": "get_third_party_app_api_v1_third_party_apps__app_name__get",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "app_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "App Name"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThirdPartyApp"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "third_party_apps"
        ],
        "summary": "Update Third Party App",
        "operationId": "update_third_party_app_api_v1_third_party_apps__app_name__put",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "app_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "App Name"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThirdPartyAppUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThirdPartyApp"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "third_party_apps"
        ],
        "summary": "Delete Third Party App",
        "operationId": "delete_third_party_app_api_v1_third_party_apps__app_name__delete",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "app_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "App Name"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "title": "Response Delete Third Party App Api V1 Third Party Apps  App Name  Delete"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/agent_update/update": {
      "post": {
        "tags": [
          "agent_update"
        ],
        "summary": "Update Agent",
        "description": "Endpoint to handle agent updates.",
        "operationId": "update_agent_api_v1_agent_update_update_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "title": "Data"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "title": "Response Update Agent Api V1 Agent Update Update Post"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/agent_details/request_all_agents_details": {
      "post": {
        "tags": [
          "agent_details"
        ],
        "summary": "Request All Agents Details",
        "description": "Endpoint to request details for all agents.\nOnly authenticated users and third-party apps can access this.",
        "operationId": "request_all_agents_details_api_v1_agent_details_request_all_agents_details_post",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/agent_data/request_agent_data": {
      "post": {
        "tags": [
          "agent_data"
        ],
        "summary": "Request Agent Data",
        "description": "Endpoint to request agent data for a specific period.\nBoth authenticated agents and users can request agent data.",
        "operationId": "request_agent_data_api_v1_agent_data_request_agent_data_post",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "agent_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Agent Id"
            }
          },
          {
            "name": "start_time",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time",
              "title": "Start Time"
            }
          },
          {
            "name": "end_time",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time",
              "title": "End Time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/send_command": {
      "post": {
        "tags": [
          "send_command"
        ],
        "summary": "Send Command To Agent",
        "description": "Endpoint to send a command to a specific agent.",
        "operationId": "send_command_to_agent_api_v1_send_command_post",
        "parameters": [
          {
            "name": "agent_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Agent Id"
            }
          },
          {
            "name": "command",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Command"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/emulator/spinup": {
      "post": {
        "tags": [
          "emulator"
        ],
        "summary": "Spinup Emulators",
        "description": "- Auth required (user or app).\n- Creates emulator agents using DatabaseManager.add_agent with hashed passwords.\n- Normalises locations to lat/lon and stores them ONLY in agent.configuration.geolocation.\n- Publishes a job to RabbitMQ (routing key: emulator_spinup) including agent creds and locations.",
        "operationId": "spinup_emulators_api_v1_emulator_spinup_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmulatorSpinupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/metrics/agent_details": {
      "get": {
        "tags": [
          "metrics"
        ],
        "summary": "Agent Details",
        "description": "Return agents directly from the database with these fields:\nid, ap_id, configuration, onboard.",
        "operationId": "agent_details_api_v1_metrics_agent_details_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/api/v1/metrics/agent_data": {
      "get": {
        "tags": [
          "metrics"
        ],
        "summary": "Get Agent Data",
        "description": "Pull time series for one agent using your exact InfluxDB reader (JWT required).\nWorks only with the agent's ap_id. Returns the key from Influx as 'key'.",
        "operationId": "get_agent_data_api_v1_metrics_agent_data_get",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "agent",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Agent ap_id (exact value used in Influx measurement 'agent/<ap_id>/data')",
              "title": "Agent"
            },
            "description": "Agent ap_id (exact value used in Influx measurement 'agent/<ap_id>/data')"
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ],
              "description": "Window size, for example 1, 5, 10 (minutes) or '1h'",
              "default": 5,
              "title": "Window"
            },
            "description": "Window size, for example 1, 5, 10 (minutes) or '1h'"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/metrics/agent_multi_metric_data": {
      "get": {
        "tags": [
          "metrics"
        ],
        "summary": "Get Agent Multi Metric Data",
        "description": "Return time series for **multiple metrics** for a given agent over the same time window.\n\nThis is the endpoint the real time chart will call once per second.\nThe frontend can select many metrics; we fetch them in a single Influx query and\ngroup by metric (field) server-side.\n\nResponse shape:\n{\n  \"agent_id\": \"<ap_id>\",\n  \"window_minutes\": <int>,\n  \"series\": [\n    { \"metric\": \"throughput\", \"points\": [ { \"ts\": \"...\", \"value\": 123.4 }, ... ] },\n    { \"metric\": \"latency\",    \"points\": [ ... ] },\n    ...\n  ]\n}",
        "operationId": "get_agent_multi_metric_data_api_v1_metrics_agent_multi_metric_data_get",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "agent",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Agent ap_id (same value used in Influx measurement 'agent/<ap_id>/data')",
              "title": "Agent"
            },
            "description": "Agent ap_id (same value used in Influx measurement 'agent/<ap_id>/data')"
          },
          {
            "name": "metrics",
            "in": "query",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Metric names (Influx 'field' values). Can be repeated, e.g. metrics=throughput&metrics=latency, or a single comma separated string.",
              "title": "Metrics"
            },
            "description": "Metric names (Influx 'field' values). Can be repeated, e.g. metrics=throughput&metrics=latency, or a single comma separated string."
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ],
              "description": "Window size, for example 1, 5, 10 (minutes) or '1h'",
              "default": 5,
              "title": "Window"
            },
            "description": "Window size, for example 1, 5, 10 (minutes) or '1h'"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/metrics/agent_metrics": {
      "get": {
        "tags": [
          "metrics"
        ],
        "summary": "List Agent Metrics",
        "description": "Return the list of metric names (Influx 'field' values) available for this agent\nin the given time window. Used by the frontend to populate the checkbox list.\n\nResponse:\n{\n  \"agent_id\": \"<ap_id>\",\n  \"window_minutes\": <int>,\n  \"metrics\": [\n    { \"name\": \"aa\", \"label\": \"aa\" },\n    { \"name\": \"bb\", \"label\": \"bb\" },\n    ...\n  ]\n}",
        "operationId": "list_agent_metrics_api_v1_metrics_agent_metrics_get",
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ],
        "parameters": [
          {
            "name": "agent",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Agent ap_id (same value used in Influx measurement 'agent/<ap_id>/data')",
              "title": "Agent"
            },
            "description": "Agent ap_id (same value used in Influx measurement 'agent/<ap_id>/data')"
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ],
              "description": "Window size for discovering metrics, e.g. 1, 5, 10 (minutes) or '1h'",
              "default": 5,
              "title": "Window"
            },
            "description": "Window size for discovering metrics, e.g. 1, 5, 10 (minutes) or '1h'"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/callback/agent_data": {
      "post": {
        "tags": [
          "agent_data_callback"
        ],
        "summary": "Agent Data Callback",
        "description": "Callback endpoint to receive agent data from the subscriber.\nThe data will be sent to the WebSocket client identified by the job_number.",
        "operationId": "agent_data_callback_api_v1_callback_agent_data_post",
        "parameters": [
          {
            "name": "job_number",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Number"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {},
                "title": "Data"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/callback/agent_details": {
      "post": {
        "tags": [
          "agent_details_callback"
        ],
        "summary": "Agent Details Callback",
        "description": "HTTP callback endpoint to receive agent details from the subscriber.\n\nIf a WebSocket is already connected for this job_number, the data is sent\nimmediately.\n\nIf NOT, we queue the data in pending_messages so it can be sent as soon\nas the WebSocket connects (avoids race conditions).",
        "operationId": "agent_details_callback_api_v1_callback_agent_details_post",
        "parameters": [
          {
            "name": "job_number",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Number"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "title": "Agent Details"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/callback/emulator": {
      "post": {
        "tags": [
          "emulator_callback"
        ],
        "summary": "Agent Details Callback",
        "description": "HTTP callback endpoint to receive agent details from the subscriber.\n\nIf a WebSocket is already connected for this job_number, the data is sent\nimmediately.\n\nIf NOT, we queue the data in pending_messages so it can be sent as soon\nas the WebSocket connects (avoids race conditions).",
        "operationId": "agent_details_callback_api_v1_callback_emulator_post",
        "parameters": [
          {
            "name": "job_number",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Job Number"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object"
                },
                "title": "Agent Details"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Agent": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "ap_id": {
            "type": "string",
            "title": "Ap Id"
          },
          "configuration": {
            "type": "object",
            "title": "Configuration"
          }
        },
        "type": "object",
        "required": [
          "id",
          "ap_id",
          "configuration"
        ],
        "title": "Agent"
      },
      "AgentCreate": {
        "properties": {
          "ap_id": {
            "type": "string",
            "title": "Ap Id"
          },
          "password": {
            "type": "string",
            "title": "Password"
          },
          "configuration": {
            "type": "object",
            "title": "Configuration"
          }
        },
        "type": "object",
        "required": [
          "ap_id",
          "password",
          "configuration"
        ],
        "title": "AgentCreate"
      },
      "AgentUpdate": {
        "properties": {
          "password": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Password"
          },
          "configuration": {
            "anyOf": [
              {
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Configuration"
          }
        },
        "type": "object",
        "title": "AgentUpdate"
      },
      "Body_login_api_v1_token__post": {
        "properties": {
          "grant_type": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "password"
              },
              {
                "type": "null"
              }
            ],
            "title": "Grant Type"
          },
          "username": {
            "type": "string",
            "title": "Username"
          },
          "password": {
            "type": "string",
            "title": "Password"
          },
          "scope": {
            "type": "string",
            "title": "Scope",
            "default": ""
          },
          "client_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Client Id"
          },
          "client_secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Client Secret"
          }
        },
        "type": "object",
        "required": [
          "username",
          "password"
        ],
        "title": "Body_login_api_v1_token__post"
      },
      "EmulatorSpec": {
        "properties": {
          "access_point_type": {
            "type": "string",
            "pattern": "^(5G|WiFi|LiFi)$",
            "title": "Access Point Type"
          },
          "num_access_points": {
            "type": "integer",
            "maximum": 1000,
            "exclusiveMinimum": 0,
            "title": "Num Access Points"
          },
          "locations": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Locations"
          },
          "num_devices": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "title": "Num Devices"
          },
          "duration": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "title": "Duration"
          }
        },
        "type": "object",
        "required": [
          "access_point_type",
          "num_access_points",
          "locations",
          "num_devices",
          "duration"
        ],
        "title": "EmulatorSpec"
      },
      "EmulatorSpinupRequest": {
        "properties": {
          "emulators": {
            "items": {
              "$ref": "#/components/schemas/EmulatorSpec"
            },
            "type": "array",
            "title": "Emulators"
          }
        },
        "type": "object",
        "required": [
          "emulators"
        ],
        "title": "EmulatorSpinupRequest"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "PasswordRecoveryRequest": {
        "properties": {
          "username": {
            "type": "string",
            "format": "email",
            "title": "Username"
          }
        },
        "type": "object",
        "required": [
          "username"
        ],
        "title": "PasswordRecoveryRequest"
      },
      "PasswordReset": {
        "properties": {
          "token": {
            "type": "string",
            "title": "Token"
          },
          "new_password": {
            "type": "string",
            "title": "New Password"
          }
        },
        "type": "object",
        "required": [
          "token",
          "new_password"
        ],
        "title": "PasswordReset"
      },
      "ThirdPartyApp": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "app_name": {
            "type": "string",
            "title": "App Name"
          },
          "api_key": {
            "type": "string",
            "title": "Api Key"
          },
          "permissions": {
            "type": "object",
            "title": "Permissions"
          }
        },
        "type": "object",
        "required": [
          "id",
          "app_name",
          "api_key",
          "permissions"
        ],
        "title": "ThirdPartyApp"
      },
      "ThirdPartyAppCreate": {
        "properties": {
          "app_name": {
            "type": "string",
            "title": "App Name"
          },
          "api_key": {
            "type": "string",
            "title": "Api Key"
          },
          "permissions": {
            "type": "object",
            "title": "Permissions"
          }
        },
        "type": "object",
        "required": [
          "app_name",
          "api_key",
          "permissions"
        ],
        "title": "ThirdPartyAppCreate"
      },
      "ThirdPartyAppUpdate": {
        "properties": {
          "api_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Api Key"
          },
          "permissions": {
            "anyOf": [
              {
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Permissions"
          }
        },
        "type": "object",
        "title": "ThirdPartyAppUpdate"
      },
      "Token": {
        "properties": {
          "access_token": {
            "type": "string",
            "title": "Access Token"
          },
          "token_type": {
            "type": "string",
            "title": "Token Type"
          },
          "expires_in": {
            "type": "integer",
            "title": "Expires In"
          }
        },
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in"
        ],
        "title": "Token"
      },
      "TokenData": {
        "properties": {
          "username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Username"
          },
          "roles": {
            "type": "string",
            "title": "Roles"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes",
            "default": []
          }
        },
        "type": "object",
        "required": [
          "roles"
        ],
        "title": "TokenData"
      },
      "UserCreate": {
        "properties": {
          "username": {
            "type": "string",
            "format": "email",
            "title": "Username"
          },
          "password": {
            "type": "string",
            "title": "Password"
          },
          "roles": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Roles"
          }
        },
        "type": "object",
        "required": [
          "username",
          "password",
          "roles"
        ],
        "title": "UserCreate"
      },
      "UserRegister": {
        "properties": {
          "username": {
            "type": "string",
            "format": "email",
            "title": "Username"
          },
          "password": {
            "type": "string",
            "title": "Password"
          }
        },
        "type": "object",
        "required": [
          "username",
          "password"
        ],
        "title": "UserRegister"
      },
      "UserUpdate": {
        "properties": {
          "password": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Password"
          },
          "roles": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Roles"
          }
        },
        "type": "object",
        "title": "UserUpdate"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    }
  ]
}