{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "HotSpotVU IoT Connectivity API",
    "version": "1.0.0-candidate",
    "description": "Software implementation candidate; physical router/device qualification pending. Network features default off. Self-service sandbox defaults to ten devices/one explicitly authorized site. Production activation reviewed. Managed-site connectivity only; no certified/global federation availability implied. Partner APIs use scoped credentials; human-only actions use dashboard session. INTERNAL tags mark separate AAA, gateway, runtime and service-administration surfaces. Database timestamps may be UTC SQL strings. JSON columns are decoded in authenticated API responses. No production secrets are embedded. Recognized partner/device tokens have independent 120/minute buckets; trusted AAA has 6000/minute. Unrecognized, browser and gateway callers use 120/minute per source IP; the aggregate source-IP ceiling is 6000/minute. Rate-limit headers and Retry-After on 429 support bounded backoff."
  },
  "servers": [
    {
      "url": "/api/iot/v1",
      "description": "Same-origin service at assigned deployment; IoT workspace must be enabled."
    }
  ],
  "tags": [
    {
      "name": "Partner",
      "description": "Partner integrations and explicitly authorized company dashboard actions."
    },
    {
      "name": "Internal AAA",
      "description": "Private certificate authentication/accounting."
    },
    {
      "name": "Internal gateway",
      "description": "Private gateway configuration/acknowledgement."
    },
    {
      "name": "Device runtime",
      "description": "Device-specific reporting/configuration."
    },
    {
      "name": "Internal administration",
      "description": "Service-user reviews and manual qualification."
    },
    {
      "name": "Webhook receiver",
      "description": "Outbound event receiver."
    }
  ],
  "paths": {
    "/account": {
      "get": {
        "operationId": "getAccount",
        "tags": [
          "Partner"
        ],
        "summary": "Read active company IoT account",
        "description": "Returns account=null before registration. Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountState"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "x-required-partner-scope": "read"
      },
      "post": {
        "operationId": "registerAccount",
        "tags": [
          "Partner"
        ],
        "summary": "Create or return self-service sandbox",
        "description": "Register active company once. Existing registration is returned without changing capabilities. Defaults: ten devices, one sandbox site. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterAccount"
              }
            }
          }
        },
        "x-human-session-required": true
      }
    },
    "/products": {
      "get": {
        "operationId": "listProducts",
        "tags": [
          "Partner"
        ],
        "summary": "List own and delegated products",
        "description": "Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductsPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-required-partner-scope": "read"
      },
      "post": {
        "operationId": "createProduct",
        "tags": [
          "Partner"
        ],
        "summary": "Create product",
        "description": "Partner token with write scope, or a company administrator session. Writes affect the own account; delegated access is read-only.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProduct"
              },
              "example": {
                "name": "Reference sensor",
                "platform": "Linux/OpenWrt",
                "category": "environmental-sensor"
              }
            }
          }
        },
        "x-required-partner-scope": "write"
      }
    },
    "/batches": {
      "get": {
        "operationId": "listBatches",
        "tags": [
          "Partner"
        ],
        "summary": "List own and delegated batches",
        "description": "Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchesPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-required-partner-scope": "read"
      },
      "post": {
        "operationId": "createBatch",
        "tags": [
          "Partner"
        ],
        "summary": "Create manufacturing batch",
        "description": "Product must belong to own account. Partner token with write scope, or a company administrator session. Writes affect the own account; delegated access is read-only.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBatch"
              }
            }
          }
        },
        "x-required-partner-scope": "write"
      }
    },
    "/devices": {
      "get": {
        "operationId": "listDevices",
        "tags": [
          "Partner"
        ],
        "summary": "List own and delegated devices",
        "description": "Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DevicesPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-required-partner-scope": "read"
      },
      "post": {
        "operationId": "enrollDevice",
        "tags": [
          "Partner"
        ],
        "summary": "Enroll individual device",
        "description": "external_id is the own-account idempotency key. Same external_id/product_id/batch_id returns the existing row; conflicting product/batch returns 409. Generic Idempotency-Key header is not implemented. Satellite role additionally requires infrastructure_issuer approval. Partner token with enroll scope, or a company administrator session. Only the own account may provision devices; delegation is read-only.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDevice"
              },
              "example": {
                "product_id": "69bddffa-9915-4783-b2f8-43ed901bb3d5",
                "external_id": "demo-sensor-001",
                "name": "Reference sensor 001",
                "role": "endpoint"
              }
            }
          }
        },
        "x-required-partner-scope": "enroll"
      }
    },
    "/devices/{device}/credentials": {
      "post": {
        "operationId": "issueDeviceCredentials",
        "tags": [
          "Partner"
        ],
        "summary": "Issue or renew device credentials",
        "description": "CSR CN must equal the device UUID. Never submit private keys. Reporting tokens are returned only by issuance/renewal and expire with their associated certificate; earlier valid tokens and certificates continue until expiry or revocation. Response private, no-store. Partner token with enroll scope, or own-company administrator session required.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssuedCredentials"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "Credential material is not cacheable.",
                "schema": {
                  "type": "string",
                  "const": "private, no-store"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          },
          "502": {
            "description": "Issuing CA returned invalid/unexpected certificate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueCredentials"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "device",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Stable enrolled device UUID."
          }
        ],
        "x-required-partner-scope": "enroll"
      }
    },
    "/devices/{device}/revoke": {
      "post": {
        "operationId": "revokeDevice",
        "tags": [
          "Partner"
        ],
        "summary": "Revoke device credentials and site permissions",
        "description": "Revokes all device certificates/reporting token and marks every permission revoked, enforcement pending. Gateway acknowledgement is separate. Partner token with write scope, or a company administrator session. Writes affect the own account; delegated access is read-only.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevokedDevice"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "parameters": [
          {
            "name": "device",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Stable enrolled device UUID."
          }
        ],
        "x-required-partner-scope": "write"
      }
    },
    "/requests": {
      "get": {
        "operationId": "listConnectionRequests",
        "tags": [
          "Partner"
        ],
        "summary": "List own and delegated requests",
        "description": "Includes computed freshness-aware status (reference freshness 90 seconds). Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RequestsPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-required-partner-scope": "read"
      }
    },
    "/requests/{connection}/decision": {
      "post": {
        "operationId": "decideConnectionRequest",
        "tags": [
          "Partner"
        ],
        "summary": "Allow, deny or revoke device at site",
        "description": "Active company must own the request location. Repeating same decision does not advance revision. Changed decisions mark enforcement pending and advance site revision. No ownership transfer. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectionRequest"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecideRequest"
              },
              "example": {
                "decision": "allowed"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "connection",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Connection-request UUID."
          }
        ],
        "x-human-session-required": true
      }
    },
    "/sites": {
      "get": {
        "operationId": "listSites",
        "tags": [
          "Partner"
        ],
        "summary": "List company locations and IoT state",
        "description": "Any active-company member can read; unconfigured locations have null IoT fields. Partner bearer tokens not accepted.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LocationSite"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "x-human-session-required": true
      }
    },
    "/sites/{location}": {
      "put": {
        "operationId": "configureSite",
        "tags": [
          "Partner"
        ],
        "summary": "Configure local IoT policy",
        "description": "Requires location ownership. Enabling requires global network flag and manual hardware qualification. sandbox_account_id counts toward its account site limit. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfigureSite"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "location",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Location UUID, not the IoT site UUID."
          }
        ],
        "x-human-session-required": true
      }
    },
    "/sites/{location}/requests": {
      "get": {
        "operationId": "listSiteRequests",
        "tags": [
          "Partner"
        ],
        "summary": "List requests at owned location",
        "description": "Requires existing IoT site at owned location. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RequestsPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "location",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Location UUID, not the IoT site UUID."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-human-session-required": true
      }
    },
    "/tokens": {
      "get": {
        "operationId": "listPartnerTokens",
        "tags": [
          "Partner"
        ],
        "summary": "List own token metadata",
        "description": "Secrets/hashes not returned. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiToken"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "x-human-session-required": true
      },
      "post": {
        "operationId": "createPartnerToken",
        "tags": [
          "Partner"
        ],
        "summary": "Create scoped expiring partner token",
        "description": "Scopes read/write/enroll are independent. Lifetime 1-90 days, default 30. Secret returned once; response private, no-store. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedToken"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "Credential material is not cacheable.",
                "schema": {
                  "type": "string",
                  "const": "private, no-store"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateToken"
              }
            }
          }
        },
        "x-human-session-required": true
      }
    },
    "/tokens/{token}": {
      "delete": {
        "operationId": "revokePartnerToken",
        "tags": [
          "Partner"
        ],
        "summary": "Revoke own partner token",
        "description": "Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "204": {
            "description": "No content."
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "API token record UUID, never the secret."
          }
        ],
        "x-human-session-required": true
      }
    },
    "/delegations": {
      "get": {
        "operationId": "listDelegations",
        "tags": [
          "Partner"
        ],
        "summary": "List grants made by own account",
        "description": "Includes revoked grants. Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Delegation"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "x-required-partner-scope": "read"
      },
      "post": {
        "operationId": "setDelegation",
        "tags": [
          "Partner"
        ],
        "summary": "Grant or revoke provider read delegation",
        "description": "Recipient must be a different non-suspended account with provider capability. Repeating pair updates grant; revoke=true removes future delegated reads. No ownership transfer or local network permission. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedDelegation"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DelegateProvider"
              }
            }
          }
        },
        "x-human-session-required": true
      }
    },
    "/sessions": {
      "get": {
        "operationId": "listSessions",
        "tags": [
          "Partner"
        ],
        "summary": "List own and delegated usage sessions",
        "description": "Operational cumulative AAA counters, not invoice-grade billing or proof of Internet/application reachability. Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.",
        "security": [
          {
            "PartnerToken": []
          },
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionsPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-required-partner-scope": "read"
      }
    },
    "/production-application": {
      "post": {
        "operationId": "applyForProduction",
        "tags": [
          "Partner"
        ],
        "summary": "Submit production application",
        "description": "Stores latest application and timestamp; sandbox remains available while reviewed. Does not automatically activate production or networking. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmittedApplication"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductionApplication"
              }
            }
          }
        },
        "x-human-session-required": true
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "tags": [
          "Partner"
        ],
        "summary": "List own subscriptions",
        "description": "Verification secrets not returned. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Webhook"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "x-human-session-required": true
      },
      "post": {
        "operationId": "createWebhook",
        "tags": [
          "Partner"
        ],
        "summary": "Create approved HTTPS subscription",
        "description": "Host must be operator-allowlisted and resolve only to public addresses, HTTPS port443. Secret returned once; private,no-store. All account audit events; no event-filter field. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedWebhook"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "Credential material is not cacheable.",
                "schema": {
                  "type": "string",
                  "const": "private, no-store"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhook"
              }
            }
          }
        },
        "x-human-session-required": true
      }
    },
    "/webhooks/{webhook}": {
      "delete": {
        "operationId": "disableWebhook",
        "tags": [
          "Partner"
        ],
        "summary": "Disable own subscription",
        "description": "Sets enabled=false; retains record and history. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "204": {
            "description": "No content."
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "parameters": [
          {
            "name": "webhook",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Webhook record UUID."
          }
        ],
        "x-human-session-required": true
      }
    },
    "/webhook-deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": [
          "Partner"
        ],
        "summary": "List own webhook delivery attempts",
        "description": "At most eight attempts. Retry backoff 30 seconds up to one hour; actual timing depends on worker scheduling. Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.",
        "security": [
          {
            "BrowserSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeliveriesPage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-human-session-required": true
      }
    },
    "/infrastructure/authorize": {
      "post": {
        "operationId": "authorizeInfrastructureDevice",
        "tags": [
          "Internal AAA"
        ],
        "summary": "Internal: authorize EAP-TLS identity",
        "description": "INTERNAL AAA integration, not a manufacturer API. Requires separate deployment-managed AAA bearer secret and both IoT feature flags enabled. Never embed this secret in endpoints, SDKs, browser code or public examples. Caller must first validate EAP-TLS and establish trusted gateway/NAS context; a fingerprint alone is not identity proof. Pending decisions return allow=false and no ordinary Internet access.",
        "security": [
          {
            "AaaToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuthorizeDevice"
              }
            }
          }
        },
        "x-internal": true
      }
    },
    "/infrastructure/accounting": {
      "post": {
        "operationId": "recordInfrastructureAccounting",
        "tags": [
          "Internal AAA"
        ],
        "summary": "Internal: ingest AAA accounting",
        "description": "INTERNAL AAA integration, not a manufacturer API. Requires separate deployment-managed AAA bearer secret and both IoT feature flags enabled. Never embed this secret in endpoints, SDKs, browser code or public examples. event_id is idempotent per gateway. Identical validated content succeeds; changed content with same ID returns 409. Cumulative counters never decrease. A new session requires an allowed request at gateway site. Accounting confirms association, not Internet/application reachability.",
        "security": [
          {
            "AaaToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommittedEvent"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountingEvent"
              }
            }
          }
        },
        "x-internal": true
      }
    },
    "/gateway/config": {
      "get": {
        "operationId": "getGatewayConfig",
        "tags": [
          "Internal gateway"
        ],
        "summary": "Internal: retrieve site enforcement policy",
        "description": "INTERNAL gateway management. X-Device-Id and X-API-Key must identify an active non-deleted gateway. These deployment secrets do not belong in manufacturer devices or browsers. Enabled only when global flag, site enablement and manual qualification all hold. No site returns minimal disabled configuration. An unqualified site can be enabled only in a bounded service-admin sandbox test window; permissions are limited to that assigned account and expire automatically.",
        "security": [
          {
            "GatewayDeviceId": [],
            "GatewayApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayConfig"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "x-internal": true
      }
    },
    "/gateway/acknowledge": {
      "post": {
        "operationId": "acknowledgeGatewayConfig",
        "tags": [
          "Internal gateway"
        ],
        "summary": "Internal: acknowledge applied revision",
        "description": "INTERNAL gateway management. X-Device-Id and X-API-Key must identify an active non-deleted gateway. These deployment secrets do not belong in manufacturer devices or browsers. Acknowledge only after applying revision. Stale revision returns409; fetch again. Success marks site request enforcement applied.",
        "security": [
          {
            "GatewayDeviceId": [],
            "GatewayApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppliedRevision"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AcknowledgeConfig"
              }
            }
          }
        },
        "x-internal": true
      }
    },
    "/device/config": {
      "get": {
        "operationId": "getDeviceConfig",
        "tags": [
          "Device runtime"
        ],
        "summary": "Device runtime: retrieve allowed site references",
        "description": "DEVICE RUNTIME, separate from partner automation. An unexpired, unrevoked hsv_device_ reporting token tied to an unexpired, unrevoked certificate is required for an active device in a non-suspended account. Overlapping valid tokens remain usable across renewal. Lists allowed requests at enabled qualified sites. Not first-connect credential bootstrap; does not grant Internet before approval. An unqualified site appears only for its explicitly assigned account during an active service-admin qualification window.",
        "security": [
          {
            "DeviceReportToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceConfig"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "x-internal": true
      }
    },
    "/device/health": {
      "post": {
        "operationId": "reportDeviceHealth",
        "tags": [
          "Device runtime"
        ],
        "summary": "Device runtime: report observed connectivity",
        "description": "DEVICE RUNTIME, separate from partner automation. An unexpired, unrevoked hsv_device_ reporting token tied to an unexpired, unrevoked certificate is required for an active device in a non-suspended account. Overlapping valid tokens remain usable across renewal. Request must belong to endpoint and remain allowed. event_id idempotent per device; conflicting content409. Over30seconds future422. Older health does not replace newer health.",
        "security": [
          {
            "DeviceReportToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommittedEvent"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HealthEvent"
              }
            }
          }
        },
        "x-internal": true
      }
    },
    "/administration": {
      "get": {
        "operationId": "listAdministration",
        "tags": [
          "Internal administration"
        ],
        "summary": "Internal: inspect accounts and sites",
        "description": "INTERNAL service administration. Requires auth:sanctum and service-user permission hotspotvu.infrastructure.manage. Partner tokens and ordinary company-admin status do not satisfy this permission. Accounts paginated50; sites at most100 most recent rows.",
        "security": [
          {
            "ServiceSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdministrationIndex"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Page number; server fixes per_page to 50."
          }
        ],
        "x-internal": true,
        "x-required-service-permission": "hotspotvu.infrastructure.manage"
      }
    },
    "/administration/accounts/{account}/review": {
      "post": {
        "operationId": "reviewAccount",
        "tags": [
          "Internal administration"
        ],
        "summary": "Internal: review account access and limits",
        "description": "INTERNAL service administration. Requires auth:sanctum and service-user permission hotspotvu.infrastructure.manage. Partner tokens and ordinary company-admin status do not satisfy this permission. Suspension revokes partner tokens and site permissions with enforcement pending. Records reviewer and audit. Does not bypass local permission or enable global flags.",
        "security": [
          {
            "ServiceSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReviewedAccount"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReviewAccount"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "account",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "IoT account UUID."
          }
        ],
        "x-internal": true,
        "x-required-service-permission": "hotspotvu.infrastructure.manage"
      }
    },
    "/administration/sites/{site}/qualification": {
      "post": {
        "operationId": "recordSiteQualification",
        "tags": [
          "Internal administration"
        ],
        "summary": "Internal: record manual qualification",
        "description": "INTERNAL service administration. Requires auth:sanctum and service-user permission hotspotvu.infrastructure.manage. Partner tokens and ordinary company-admin status do not satisfy this permission. Records manual pass/fail with evidence reference and increments revision. Passing does not itself enable site or global network.",
        "security": [
          {
            "ServiceSession": [],
            "CsrfHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QualifiedSite"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "419": {
            "$ref": "#/components/responses/419"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QualifySite"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "site",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "IoT site UUID, not the location UUID."
          }
        ],
        "x-internal": true,
        "x-required-service-permission": "hotspotvu.infrastructure.manage"
      }
    },
    "/device/renew": {
      "post": {
        "operationId": "renewDeviceCredentials",
        "tags": [
          "Device runtime"
        ],
        "summary": "Device runtime: renew credentials with private-key proof",
        "description": "Use a valid certificate-bound reporting bearer token. For a fresh request, timestamp must be within 300 seconds of server time. Compute lowercase hex SHA-256 of the exact UTF-8 csr string, then sign event_id + \"\\n\" + device_id + \"\\n\" + decimal timestamp + \"\\n\" + csr_sha256 with actual LF (U+000A) separators and no trailing LF, using SHA-256 and the private key of the certificate associated with that reporting token. Send the signature as standard base64. The enrolled device UUID is the authenticated device identity. Never transmit its private key. A successful response has the same bundle as partner issuance. Previous unexpired/unrevoked certificates and reporting tokens remain valid; install the new bundle safely. Repeating the identical event_id and payload while authenticating with a valid token returns the originally issued bundle, including its reporting token, without issuing again. The response is stored encrypted at rest. Reusing an event_id with different content returns 409. Exact replays use the saved receipt before checking original timestamp age; new events require fresh timestamps. The reference daemon attempts renewal seven days before expiry. Expired credentials require authorized recovery rather than bypassing authentication.",
        "security": [
          {
            "DeviceReportToken": []
          }
        ],
        "x-internal": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenewDeviceCredentials"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New credential bundle, or the same saved bundle for an identical renewal replay.",
            "headers": {
              "Cache-Control": {
                "description": "Credential material must not be cached.",
                "schema": {
                  "type": "string",
                  "const": "private, no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssuedCredentials"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          },
          "502": {
            "description": "Issuing CA returned an unexpected or invalid certificate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/infrastructure/nas-map": {
      "get": {
        "operationId": "getInfrastructureNasMap",
        "tags": [
          "Internal AAA"
        ],
        "summary": "Internal AAA: active mutually authenticated NAS registry",
        "description": "AAA service only; both feature flags required. Includes qualified active gateways and explicitly approved infrastructure satellites. Used by the operator-installed 30-second NAS reconciler; contains no private keys or partner tokens.",
        "security": [
          {
            "AaaToken": []
          }
        ],
        "x-internal": true,
        "responses": {
          "200": {
            "description": "Active NAS UUID to parent gateway UUID map.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NasMap"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        }
      }
    },
    "/administration/sites/{site}/qualification-window": {
      "post": {
        "operationId": "setQualificationWindow",
        "tags": [
          "Internal administration"
        ],
        "summary": "Internal: open or close bounded sandbox hardware test window",
        "description": "Service infrastructure permission required. Only an unqualified site explicitly bound to a sandbox account can receive a new window. 1-8 hours; zero closes the window and disables the site. Never records hardware qualification. Global enablement, site enablement and factory firmware preflight remain required. Only the assigned account may authenticate at an unqualified test site.",
        "x-internal": true,
        "security": [
          {
            "ServiceSession": [],
            "CsrfHeader": []
          }
        ],
        "parameters": [
          {
            "name": "site",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "hours",
                  "evidence_reference"
                ],
                "properties": {
                  "hours": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 8
                  },
                  "evidence_reference": {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Window expiry and actual hardware-qualified state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "qualification_expires_at",
                    "hardware_qualified"
                  ],
                  "properties": {
                    "qualification_expires_at": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "hardware_qualified": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/401"
          },
          "403": {
            "$ref": "#/components/responses/403"
          },
          "404": {
            "$ref": "#/components/responses/404"
          },
          "409": {
            "$ref": "#/components/responses/409"
          },
          "422": {
            "$ref": "#/components/responses/422"
          },
          "429": {
            "$ref": "#/components/responses/429"
          },
          "503": {
            "$ref": "#/components/responses/503"
          }
        }
      }
    }
  },
  "webhooks": {
    "iotEvent": {
      "post": {
        "description": "Outbound request to subscriber URL. Verify X-HotSpotVU-Signature as t=<Unix-seconds>,v1=<hex-HMAC-SHA256> over timestamp + \".\" + raw UTF-8 body using subscription secret. Apply receiver-defined bounded timestamp tolerance, deduplicate event IDs and durably accept before a 2xx. Maximum eight delivery attempts. Events contain no private keys or bearer credentials. device.connection_changed includes connected/disconnected health transitions and not_reporting from the minute-scheduled presence expiry job after the 90-second freshness interval; scheduling and delivery can delay that notification. Current API status evaluates freshness directly. Event payloads use opaque request IDs without exposing site/location identity.",
        "operationId": "receiveIotEvent",
        "tags": [
          "Webhook receiver"
        ],
        "parameters": [
          {
            "name": "X-HotSpotVU-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "X-HotSpotVU-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^t=[0-9]+,v1=[a-f0-9]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              },
              "examples": {
                "approvalRequest": {
                  "summary": "Enrolled device requests site access",
                  "value": {
                    "id": "e2c0fa93-7bac-423b-aa93-f4bc91ea74e0",
                    "type": "connection.requested",
                    "occurred_at": "2026-10-28T14:00:00Z",
                    "data": {
                      "device_id": "ca2ca362-24d2-4f56-abab-91939ff85fc0",
                      "request_id": "31dd045a-6471-4374-a9ee-19bf866db968"
                    }
                  }
                },
                "connectionChange": {
                  "summary": "Connection changed without venue identity",
                  "value": {
                    "id": "10e12dfa-4c87-4dc3-a730-c238060b24ec",
                    "type": "device.connection_changed",
                    "occurred_at": "2026-10-28T14:00:00Z",
                    "data": {
                      "device_id": "ca2ca362-24d2-4f56-abab-91939ff85fc0",
                      "request_id": "31dd045a-6471-4374-a9ee-19bf866db968",
                      "connection": "not_reporting"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Receiver accepted; any2xx accepted, other statuses/transport errors retry."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "PartnerToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "hsv_iot_ opaque token",
        "description": "Independent read/write/enroll scopes. Cannot perform human-only company or local-approval actions."
      },
      "BrowserSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "hotspotvu_session",
        "description": "Cognito/Sanctum browser session with active company and verified membership. Cookie name deployment-configurable via SESSION_COOKIE. Stateful writes require X-XSRF-TOKEN. Sign in through normal dashboard."
      },
      "CsrfHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-XSRF-TOKEN",
        "description": "URL-decoded XSRF-TOKEN cookie value for stateful browser mutation. Not partner/device/AAA credential."
      },
      "AaaToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "deployment-managed AAA secret",
        "description": "INTERNAL dedicated AAA credential configured outside this document. Never distribute to endpoints."
      },
      "GatewayDeviceId": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Device-Id",
        "description": "INTERNAL active gateway UUID; must accompany GatewayApiKey."
      },
      "GatewayApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "INTERNAL identified gateway secret; must accompany GatewayDeviceId."
      },
      "DeviceReportToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "hsv_device_ opaque token",
        "description": "Certificate-bound hsv_device_ reporting/configuration/renewal credential. Expires with its associated certificate; prior valid tokens survive renewal until expiry or revocation. Device must remain active and account not suspended. This credential cannot enroll devices, approve access, or call AAA."
      },
      "ServiceSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "hotspotvu_session",
        "description": "INTERNAL Sanctum session with hotspotvu.infrastructure.manage permission; deployment-configurable cookie. Stateful writes require CSRF."
      }
    },
    "responses": {
      "401": {
        "description": "Missing, invalid, expired or revoked credentials.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "403": {
        "description": "Actor, token scope, company/site permission or infrastructure authority is insufficient.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "404": {
        "description": "Resource absent or outside the caller's authorized scope.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "409": {
        "description": "Missing account/company context, deployment/quota gate, stale configuration or idempotency/state conflict.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "419": {
        "description": "Missing or invalid CSRF token on a stateful browser request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "422": {
        "description": "Validation failed. Inspect message and optional field errors.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "429": {
        "description": "Rate limit exceeded; routes share the configured 120 requests/minute limiter.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "503": {
        "description": "IoT workspace or required provisioning service disabled/unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string"
          },
          "errors": {
            "type": "object",
            "properties": {},
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        "required": [
          "message"
        ],
        "additionalProperties": true
      },
      "PaginationLink": {
        "type": "object",
        "properties": {
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "label": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          }
        },
        "required": [
          "url",
          "label",
          "active"
        ]
      },
      "PaginationMetadata": {
        "type": "object",
        "properties": {
          "current_page": {
            "type": "integer",
            "minimum": 1
          },
          "first_page_url": {
            "type": "string",
            "format": "uri"
          },
          "from": {
            "type": [
              "integer",
              "null"
            ]
          },
          "last_page": {
            "type": "integer",
            "minimum": 1
          },
          "last_page_url": {
            "type": "string",
            "format": "uri"
          },
          "links": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaginationLink"
            }
          },
          "next_page_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "path": {
            "type": "string",
            "format": "uri"
          },
          "per_page": {
            "type": "integer",
            "const": 50
          },
          "prev_page_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "to": {
            "type": [
              "integer",
              "null"
            ]
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "current_page",
          "first_page_url",
          "from",
          "last_page",
          "last_page_url",
          "links",
          "next_page_url",
          "path",
          "per_page",
          "prev_page_url",
          "to",
          "total"
        ],
        "description": "Laravel length-aware pagination. Fixed page size 50; only the page query parameter is supported."
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "sandbox",
              "production",
              "suspended"
            ]
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "manufacturer",
                "provider",
                "operator"
              ]
            }
          },
          "device_limit": {
            "type": "integer",
            "minimum": 1
          },
          "site_limit": {
            "type": "integer",
            "minimum": 1
          },
          "infrastructure_issuer": {
            "type": "boolean"
          },
          "production_application": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          },
          "review_notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "reviewed_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "tenant_id",
          "status",
          "capabilities",
          "device_limit",
          "site_limit",
          "created_at",
          "updated_at"
        ],
        "description": "Persisted account record. Capabilities and submitted application JSON are decoded in API responses."
      },
      "AccountState": {
        "type": "object",
        "properties": {
          "account": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Account"
              },
              {
                "type": "null"
              }
            ]
          },
          "can_manage": {
            "type": "boolean"
          },
          "network_enabled": {
            "type": "boolean"
          },
          "limits": {
            "type": "object",
            "properties": {
              "sandbox_devices": {
                "type": "integer",
                "const": 10
              },
              "sandbox_sites": {
                "type": "integer",
                "const": 1
              }
            },
            "required": [
              "sandbox_devices",
              "sandbox_sites"
            ]
          }
        },
        "required": [
          "account",
          "can_manage",
          "network_enabled",
          "limits"
        ]
      },
      "RegisterAccount": {
        "type": "object",
        "properties": {
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "manufacturer",
                "provider",
                "operator"
              ]
            },
            "minItems": 1,
            "maxItems": 3
          }
        },
        "required": [
          "capabilities"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "platform": {
            "type": "string",
            "maxLength": 80
          },
          "category": {
            "type": "string",
            "maxLength": 80
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "account_id",
          "name",
          "platform",
          "category",
          "created_at",
          "updated_at"
        ]
      },
      "CreateProduct": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "platform": {
            "type": "string",
            "maxLength": 80,
            "minLength": 1
          },
          "category": {
            "type": "string",
            "maxLength": 80,
            "minLength": 1
          }
        },
        "required": [
          "name",
          "platform",
          "category"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "Batch": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "product_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "product_id",
          "name",
          "created_at",
          "updated_at"
        ]
      },
      "CreateBatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "product_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          }
        },
        "required": [
          "name",
          "product_id"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "Device": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          },
          "product_id": {
            "type": "string",
            "format": "uuid"
          },
          "batch_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "infrastructure_device_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "active",
              "revoked"
            ]
          },
          "last_report_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_health": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HealthObservation"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "account_id",
          "product_id",
          "batch_id",
          "external_id",
          "name",
          "role",
          "created_at"
        ],
        "description": "Persisted device record. No report-token hash or private key is returned; device list endpoints use the documented reduced projection."
      },
      "DeviceListItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "account_id": {
            "type": "string",
            "format": "uuid"
          },
          "product_id": {
            "type": "string",
            "format": "uuid"
          },
          "batch_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "active",
              "revoked"
            ]
          },
          "last_report_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_health": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HealthObservation"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "account_id",
          "product_id",
          "batch_id",
          "external_id",
          "name",
          "role",
          "state",
          "last_report_at",
          "last_health",
          "created_at"
        ]
      },
      "CreateDevice": {
        "type": "object",
        "properties": {
          "product_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "batch_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "external_id": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "name": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ],
            "default": "endpoint"
          }
        },
        "required": [
          "product_id",
          "external_id",
          "name"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "IssueCredentials": {
        "type": "object",
        "properties": {
          "csr": {
            "type": "string",
            "maxLength": 16384,
            "description": "PEM PKCS#10 CSR. Common name must exactly match the device UUID. Generate and retain the private key locally; never submit it.",
            "minLength": 1
          }
        },
        "required": [
          "csr"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "NetworkProfile": {
        "type": "object",
        "properties": {
          "ssid": {
            "type": "string",
            "enum": [
              "HotSpotVU-IoT",
              "HotSpotVU-Backhaul"
            ]
          },
          "eap_method": {
            "type": "string",
            "const": "TLS"
          },
          "server_name": {
            "type": "string",
            "description": "Authentication-server identity the supplicant must verify."
          },
          "realm": {
            "type": "string"
          }
        },
        "required": [
          "ssid",
          "eap_method",
          "server_name",
          "realm"
        ]
      },
      "IssuedCredentials": {
        "type": "object",
        "properties": {
          "certificate_pem": {
            "type": "string",
            "description": "PEM client certificate."
          },
          "chain_pem": {
            "type": "string",
            "description": "Issuing CA chain in PEM."
          },
          "ca_pem": {
            "type": "string",
            "description": "Trusted CA bundle in PEM."
          },
          "fingerprint": {
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$"
          },
          "expires_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "report_token": {
            "type": "string",
            "description": "Secret hsv_device_ reporting bearer token returned by issuance or renewal, never inventory reads. It expires with its associated certificate. Earlier reporting tokens remain usable while their own certificates and tokens are unexpired and unrevoked, the device is active, and its account is not suspended. Renewal does not immediately invalidate earlier tokens. Store securely; never log."
          },
          "profile": {
            "$ref": "#/components/schemas/NetworkProfile"
          }
        },
        "required": [
          "certificate_pem",
          "chain_pem",
          "ca_pem",
          "fingerprint",
          "expires_at",
          "device_id",
          "report_token",
          "profile"
        ]
      },
      "RevokedDevice": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "const": "revoked"
          },
          "enforcement": {
            "type": "string",
            "const": "pending"
          }
        },
        "required": [
          "state",
          "enforcement"
        ]
      },
      "HealthObservation": {
        "type": "object",
        "properties": {
          "connected": {
            "type": "boolean"
          },
          "internet_reachable": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "ap_active": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "signal_dbm": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": -120,
            "maximum": 0
          },
          "config_version": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          }
        },
        "required": [
          "connected"
        ]
      },
      "PresentedStatus": {
        "type": "object",
        "properties": {
          "authorization": {
            "type": "string",
            "enum": [
              "pending",
              "allowed",
              "denied",
              "revoked"
            ]
          },
          "connection": {
            "type": "string",
            "enum": [
              "awaiting_approval",
              "denied",
              "revoked",
              "not_reporting",
              "connected",
              "disconnected"
            ]
          },
          "internet_reachable": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "ap_active": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "last_confirmed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "fresh_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "enforcement": {
            "type": "string",
            "enum": [
              "pending",
              "applied"
            ]
          },
          "signal_dbm": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": -120,
            "maximum": 0,
            "description": "Reported station/backhaul signal; unknown after freshness expiry."
          }
        },
        "required": [
          "authorization",
          "connection",
          "internet_reachable",
          "ap_active",
          "last_confirmed_at",
          "fresh_until",
          "enforcement"
        ]
      },
      "ConnectionRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "endpoint_id": {
            "type": "string",
            "format": "uuid"
          },
          "site_id": {
            "type": "string",
            "format": "uuid"
          },
          "decision": {
            "type": "string",
            "enum": [
              "pending",
              "allowed",
              "denied",
              "revoked"
            ]
          },
          "enforcement": {
            "type": "string",
            "enum": [
              "pending",
              "applied"
            ]
          },
          "decided_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "decided_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_attempt_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_connected_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_disconnected_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "health": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HealthObservation"
              },
              {
                "type": "null"
              }
            ]
          },
          "health_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "reported_connection": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "connected",
              "disconnected",
              "not_reporting",
              null
            ],
            "description": "Last transition recorded for webhook purposes. Use computed status for current freshness."
          }
        },
        "required": [
          "id",
          "endpoint_id",
          "site_id",
          "decision",
          "enforcement",
          "last_attempt_at"
        ]
      },
      "ConnectionRequestView": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "endpoint_id": {
            "type": "string",
            "format": "uuid"
          },
          "site_id": {
            "type": "string",
            "format": "uuid"
          },
          "decision": {
            "type": "string",
            "enum": [
              "pending",
              "allowed",
              "denied",
              "revoked"
            ]
          },
          "enforcement": {
            "type": "string",
            "enum": [
              "pending",
              "applied"
            ]
          },
          "decided_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "decided_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_attempt_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_connected_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_disconnected_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "health": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/HealthObservation"
              },
              {
                "type": "null"
              }
            ]
          },
          "health_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "device_name": {
            "type": "string"
          },
          "external_id": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ]
          },
          "product_name": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "manufacturer": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/PresentedStatus"
          },
          "reported_connection": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "connected",
              "disconnected",
              "not_reporting",
              null
            ],
            "description": "Last transition recorded for webhook purposes. Use computed status for current freshness."
          }
        },
        "required": [
          "id",
          "endpoint_id",
          "site_id",
          "decision",
          "enforcement",
          "last_attempt_at",
          "device_name",
          "external_id",
          "role",
          "product_name",
          "category",
          "manufacturer",
          "status"
        ]
      },
      "DecideRequest": {
        "type": "object",
        "properties": {
          "decision": {
            "type": "string",
            "enum": [
              "allowed",
              "denied",
              "revoked"
            ]
          }
        },
        "required": [
          "decision"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "Site": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "location_id": {
            "type": "string",
            "format": "uuid"
          },
          "sandbox_account_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "enabled": {
            "type": "boolean"
          },
          "hardware_qualified": {
            "type": "boolean"
          },
          "down_mbps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2500
          },
          "up_mbps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2500
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "qualification_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "A service-admin test window for the explicitly assigned sandbox, never proof of hardware qualification."
          }
        },
        "required": [
          "id",
          "location_id",
          "sandbox_account_id",
          "enabled",
          "hardware_qualified",
          "down_mbps",
          "up_mbps",
          "revision",
          "created_at",
          "updated_at"
        ]
      },
      "LocationSite": {
        "type": "object",
        "properties": {
          "location_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "enabled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "hardware_qualified": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "sandbox_account_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "down_mbps": {
            "type": [
              "integer",
              "null"
            ]
          },
          "up_mbps": {
            "type": [
              "integer",
              "null"
            ]
          },
          "revision": {
            "type": [
              "integer",
              "null"
            ]
          },
          "qualification_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "A service-admin test window for the explicitly assigned sandbox, never proof of hardware qualification."
          }
        },
        "required": [
          "location_id",
          "name",
          "id",
          "enabled",
          "hardware_qualified",
          "sandbox_account_id",
          "down_mbps",
          "up_mbps",
          "revision"
        ],
        "description": "All active-company locations; IoT fields are null where there is no site record."
      },
      "ConfigureSite": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "sandbox_account_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "down_mbps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2500
          },
          "up_mbps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2500
          }
        },
        "required": [
          "enabled",
          "down_mbps",
          "up_mbps"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "ApiToken": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "read",
                "write",
                "enroll"
              ]
            }
          },
          "expires_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "name",
          "scopes",
          "expires_at",
          "revoked_at",
          "last_used_at"
        ]
      },
      "CreateToken": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "read",
                "write",
                "enroll"
              ]
            },
            "minItems": 1
          },
          "days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 90,
            "default": 30
          }
        },
        "required": [
          "name",
          "scopes"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "CreatedToken": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "token": {
            "type": "string",
            "description": "Secret hsv_iot_ partner bearer token, returned once. Store securely."
          },
          "expires_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "token",
          "expires_at"
        ]
      },
      "Delegation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "owner_account_id": {
            "type": "string",
            "format": "uuid"
          },
          "provider_account_id": {
            "type": "string",
            "format": "uuid"
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "owner_account_id",
          "provider_account_id",
          "revoked_at",
          "created_at",
          "updated_at"
        ]
      },
      "DelegateProvider": {
        "type": "object",
        "properties": {
          "provider_account_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "revoke": {
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "provider_account_id"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "SavedDelegation": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "saved"
          },
          "access": {
            "type": "string",
            "const": "read"
          }
        },
        "required": [
          "status",
          "access"
        ]
      },
      "Session": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "started_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "observed_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "ended_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "bytes_up": {
            "type": "integer",
            "minimum": 0
          },
          "bytes_down": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "id",
          "device_id",
          "started_at",
          "observed_at",
          "ended_at",
          "bytes_up",
          "bytes_down"
        ]
      },
      "ProductionApplication": {
        "type": "object",
        "properties": {
          "platforms": {
            "type": "string",
            "maxLength": 2000,
            "minLength": 1
          },
          "expected_devices": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000000
          },
          "use_case": {
            "type": "string",
            "maxLength": 4000,
            "minLength": 1
          },
          "support_contact": {
            "type": "string",
            "format": "email",
            "maxLength": 255,
            "minLength": 1
          }
        },
        "required": [
          "platforms",
          "expected_devices",
          "use_case",
          "support_contact"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "SubmittedApplication": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "submitted"
          },
          "message": {
            "type": "string",
            "const": "Your sandbox remains available while production access is reviewed."
          }
        },
        "required": [
          "status",
          "message"
        ]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "enabled": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          }
        },
        "required": [
          "id",
          "url",
          "enabled",
          "created_at"
        ]
      },
      "CreateWebhook": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "HTTPS URL on an operator-approved host, port 443, no userinfo or fragment. DNS must resolve only to public IPv4 addresses. Redirects are not followed.",
            "minLength": 1
          }
        },
        "required": [
          "url"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "CreatedWebhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "secret": {
            "type": "string",
            "description": "Verification secret returned only once; keep on receiving backend."
          }
        },
        "required": [
          "id",
          "secret"
        ]
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "webhook_id": {
            "type": "string",
            "format": "uuid"
          },
          "attempts": {
            "type": "integer",
            "minimum": 0,
            "maximum": 8
          },
          "next_attempt_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "delivery_failed",
              "subscription_disabled",
              null
            ]
          }
        },
        "required": [
          "id",
          "event_id",
          "webhook_id",
          "attempts",
          "next_attempt_at",
          "delivered_at",
          "last_error"
        ]
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "device.enrolled",
              "credential.issued",
              "device.revoked",
              "connection.requested",
              "connection.allowed",
              "connection.denied",
              "connection.revoked",
              "delegation.changed",
              "account.reviewed",
              "device.connection_changed"
            ]
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          }
        },
        "required": [
          "id",
          "type",
          "occurred_at",
          "data"
        ],
        "description": "Account-scoped audit and connectivity-transition events. device.connection_changed carries connected/disconnected changes accepted from device health and scheduler-driven not_reporting after observations become stale. Events are notifications; query request status for current freshness. Connection events include no location or site identity.",
        "allOf": [
          {
            "if": {
              "properties": {
                "type": {
                  "const": "device.connection_changed"
                }
              },
              "required": [
                "type"
              ]
            },
            "then": {
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/ConnectionChangedEventData"
                }
              }
            }
          }
        ]
      },
      "AuthorizeDevice": {
        "type": "object",
        "properties": {
          "gateway_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "fingerprint": {
            "type": "string",
            "pattern": "^[a-fA-F0-9]{64}$",
            "description": "SHA-256 client certificate fingerprint supplied only after AAA validates EAP-TLS.",
            "minLength": 1
          },
          "nas_id": {
            "type": "string",
            "format": "uuid",
            "description": "Mutual-TLS peer UUID overwritten by the trusted proxy. Satellite NAS permissions are rechecked by the backend."
          },
          "certificate_serial": {
            "type": "string",
            "pattern": "^[a-fA-F0-9:]{1,128}$",
            "description": "Validated TLS leaf serial from FreeRADIUS 3. Use with certificate_common_name and a dedicated CA enforcing unique serials."
          },
          "certificate_common_name": {
            "type": "string",
            "format": "uuid",
            "description": "CN of the validated TLS leaf; never outer User-Name."
          },
          "expected_role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ],
            "default": "endpoint",
            "description": "SSID-specific role. Satellite NAS peers cannot admit chained backhauls."
          }
        },
        "required": [
          "gateway_id"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted.",
        "anyOf": [
          {
            "required": [
              "fingerprint"
            ]
          },
          {
            "required": [
              "certificate_serial",
              "certificate_common_name"
            ]
          }
        ]
      },
      "AuthorizationResult": {
        "type": "object",
        "properties": {
          "allow": {
            "type": "boolean"
          },
          "reason": {
            "type": "string",
            "enum": [
              "site_disabled",
              "credential_unknown",
              "device_revoked",
              "sandbox_site_required",
              "infrastructure_not_approved",
              "pending",
              "allowed",
              "denied",
              "revoked",
              "network_role_mismatch",
              "qualification_site_required"
            ]
          },
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ]
          },
          "site_id": {
            "type": "string",
            "format": "uuid"
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "session_seconds": {
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "allow",
          "reason"
        ],
        "description": "Early rejections have only allow/reason. Eligible identities also return request details; pending/denied/revoked remain allow=false."
      },
      "AccountingEvent": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "gateway_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "request_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "accounting_id": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "mac": {
            "type": "string",
            "pattern": "^(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$",
            "minLength": 1
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "At most 30 seconds in the future.",
            "minLength": 1
          },
          "status": {
            "type": "string",
            "enum": [
              "start",
              "interim",
              "stop"
            ]
          },
          "bytes_up": {
            "type": "integer",
            "minimum": 0
          },
          "bytes_down": {
            "type": "integer",
            "minimum": 0
          },
          "nas_id": {
            "type": "string",
            "format": "uuid"
          },
          "bssid": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(?:[a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$"
          }
        },
        "required": [
          "event_id",
          "gateway_id",
          "request_id",
          "accounting_id",
          "mac",
          "observed_at",
          "status",
          "bytes_up",
          "bytes_down"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "CommittedEvent": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "committed": {
            "type": "boolean",
            "const": true
          }
        },
        "required": [
          "event_id",
          "committed"
        ]
      },
      "GatewayAuthorization": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "decision": {
            "type": "string",
            "enum": [
              "pending",
              "allowed",
              "denied",
              "revoked"
            ]
          },
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "active",
              "revoked"
            ]
          },
          "mac": {
            "type": [
              "string",
              "null"
            ],
            "description": "MAC from the latest active accounting session on this gateway, or null."
          }
        },
        "required": [
          "request_id",
          "decision",
          "device_id",
          "role",
          "state",
          "mac"
        ]
      },
      "GatewayConfig": {
        "type": "object",
        "properties": {
          "schema": {
            "type": "string",
            "const": "hotspotvu.iot.network.v1"
          },
          "enabled": {
            "type": "boolean"
          },
          "site_id": {
            "type": "string",
            "format": "uuid"
          },
          "gateway_id": {
            "type": "string",
            "format": "uuid"
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "down_mbps": {
            "type": "integer",
            "minimum": 1
          },
          "up_mbps": {
            "type": "integer",
            "minimum": 1
          },
          "eap_server_name": {
            "type": "string"
          },
          "authorizations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GatewayAuthorization"
            }
          }
        },
        "required": [
          "schema",
          "enabled",
          "revision",
          "authorizations"
        ],
        "description": "Unconfigured locations return schema, enabled=false, revision=0 and empty authorizations only."
      },
      "AcknowledgeConfig": {
        "type": "object",
        "properties": {
          "revision": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "revision"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "AppliedRevision": {
        "type": "object",
        "properties": {
          "applied_revision": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "applied_revision"
        ]
      },
      "DeviceSite": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string",
            "format": "uuid"
          },
          "site_id": {
            "type": "string",
            "format": "uuid"
          },
          "location_id": {
            "type": "string",
            "format": "uuid"
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "bssid": {
            "type": [
              "string",
              "null"
            ],
            "description": "BSSID from the latest active accounting observation within 90 seconds. Reference runtime matches the observed BSSID when more than one site is approved."
          },
          "guest_ssid": {
            "type": "string",
            "description": "Managed satellites only: current approved location guest SSID, applied before exposing the guest AP."
          },
          "gateway_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Managed satellites only: assigned parent gateway."
          }
        },
        "required": [
          "request_id",
          "site_id",
          "location_id",
          "revision",
          "bssid"
        ]
      },
      "DeviceConfig": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "endpoint",
              "satellite"
            ]
          },
          "network_enabled": {
            "type": "boolean"
          },
          "sites": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeviceSite"
            }
          },
          "report_interval_seconds": {
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "device_id",
          "role",
          "network_enabled",
          "sites",
          "report_interval_seconds"
        ]
      },
      "HealthEvent": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "request_id": {
            "type": "string",
            "format": "uuid",
            "minLength": 1
          },
          "observed_at": {
            "type": "string",
            "format": "date-time",
            "description": "At most 30 seconds in the future.",
            "minLength": 1
          },
          "connected": {
            "type": "boolean"
          },
          "internet_reachable": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "ap_active": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "signal_dbm": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": -120,
            "maximum": 0
          },
          "config_version": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 128
          },
          "guest_ap_bssid": {
            "type": [
              "string",
              "null"
            ],
            "description": "Managed satellites only: observed guest AP BSSID. Not returned in manufacturer health."
          },
          "associated_clients": {
            "type": "array",
            "maxItems": 128,
            "items": {
              "type": "string"
            },
            "description": "Managed satellites only; used for scoped guest attribution. Excluded from manufacturer health and webhook payloads."
          }
        },
        "required": [
          "event_id",
          "request_id",
          "observed_at",
          "connected"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "ReviewAccount": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "sandbox",
              "production",
              "suspended"
            ]
          },
          "device_limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000000
          },
          "site_limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000
          },
          "infrastructure_issuer": {
            "type": "boolean"
          },
          "review_notes": {
            "type": "string",
            "minLength": 10,
            "maxLength": 4000
          }
        },
        "required": [
          "status",
          "device_limit",
          "site_limit",
          "infrastructure_issuer",
          "review_notes"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "ReviewedAccount": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "sandbox",
              "production",
              "suspended"
            ]
          }
        },
        "required": [
          "status"
        ]
      },
      "QualifySite": {
        "type": "object",
        "properties": {
          "passed": {
            "type": "boolean"
          },
          "evidence_reference": {
            "type": "string",
            "minLength": 10,
            "maxLength": 1000,
            "description": "Reference to manual validation evidence; never submit secrets."
          }
        },
        "required": [
          "passed",
          "evidence_reference"
        ],
        "additionalProperties": true,
        "description": " Unknown request fields are ignored by validation, not persisted."
      },
      "QualifiedSite": {
        "type": "object",
        "properties": {
          "hardware_qualified": {
            "type": "boolean"
          },
          "qualification_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "A service-admin test window for the explicitly assigned sandbox, never proof of hardware qualification."
          }
        },
        "required": [
          "hardware_qualified"
        ]
      },
      "AdministrationAccount": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "sandbox",
              "production",
              "suspended"
            ]
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "manufacturer",
                "provider",
                "operator"
              ]
            }
          },
          "device_limit": {
            "type": "integer",
            "minimum": 1
          },
          "site_limit": {
            "type": "integer",
            "minimum": 1
          },
          "infrastructure_issuer": {
            "type": "boolean"
          },
          "production_application": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true
          },
          "review_notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "reviewed_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "tenant_id",
          "status",
          "capabilities",
          "device_limit",
          "site_limit",
          "name"
        ]
      },
      "AdministrationSite": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "location_id": {
            "type": "string",
            "format": "uuid"
          },
          "sandbox_account_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "enabled": {
            "type": "boolean"
          },
          "hardware_qualified": {
            "type": "boolean"
          },
          "down_mbps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2500
          },
          "up_mbps": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2500
          },
          "revision": {
            "type": "integer",
            "minimum": 0
          },
          "created_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "updated_at": {
            "type": "string",
            "description": "UTC database timestamp or ISO-8601 serialized timestamp."
          },
          "name": {
            "type": "string"
          },
          "qualification_expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "A service-admin test window for the explicitly assigned sandbox, never proof of hardware qualification."
          }
        },
        "required": [
          "id",
          "location_id",
          "name",
          "enabled",
          "hardware_qualified",
          "revision"
        ]
      },
      "ProductsPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PaginationMetadata"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            },
            "required": [
              "data"
            ]
          }
        ]
      },
      "BatchesPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PaginationMetadata"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Batch"
                }
              }
            },
            "required": [
              "data"
            ]
          }
        ]
      },
      "DevicesPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PaginationMetadata"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DeviceListItem"
                }
              }
            },
            "required": [
              "data"
            ]
          }
        ]
      },
      "RequestsPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PaginationMetadata"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ConnectionRequestView"
                }
              }
            },
            "required": [
              "data"
            ]
          }
        ]
      },
      "SessionsPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PaginationMetadata"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Session"
                }
              }
            },
            "required": [
              "data"
            ]
          }
        ]
      },
      "DeliveriesPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PaginationMetadata"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/WebhookDelivery"
                }
              }
            },
            "required": [
              "data"
            ]
          }
        ]
      },
      "AdministrationAccountsPage": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PaginationMetadata"
          },
          {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AdministrationAccount"
                }
              }
            },
            "required": [
              "data"
            ]
          }
        ]
      },
      "AdministrationIndex": {
        "type": "object",
        "properties": {
          "accounts": {
            "$ref": "#/components/schemas/AdministrationAccountsPage"
          },
          "sites": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdministrationSite"
            },
            "maxItems": 100
          }
        },
        "required": [
          "accounts",
          "sites"
        ]
      },
      "RenewDeviceCredentials": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid",
            "description": "Idempotency identifier for this device renewal."
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix seconds. A fresh renewal must be within 300 seconds of server time."
          },
          "csr": {
            "type": "string",
            "minLength": 1,
            "maxLength": 16384,
            "description": "PEM CSR with common name equal to the enrolled device UUID. Hash the exact submitted UTF-8 string; never upload its private key."
          },
          "signature": {
            "type": "string",
            "minLength": 1,
            "maxLength": 4096,
            "description": "Standard base64 encoding of the SHA-256 signature made with the private key of the certificate associated with the supplied reporting token. Sign the exact proof described for this operation."
          }
        },
        "required": [
          "event_id",
          "timestamp",
          "csr",
          "signature"
        ],
        "additionalProperties": true
      },
      "ConnectionChangedEventData": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "format": "uuid"
          },
          "request_id": {
            "type": "string",
            "format": "uuid",
            "description": "Opaque request identifier; the payload does not reveal site identity or location details."
          },
          "connection": {
            "type": "string",
            "enum": [
              "connected",
              "disconnected",
              "not_reporting"
            ]
          },
          "internet_reachable": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Included on reported connected/disconnected transitions where supplied; absent on scheduler-driven not_reporting events."
          }
        },
        "required": [
          "device_id",
          "request_id",
          "connection"
        ],
        "additionalProperties": false
      },
      "NasMap": {
        "type": "object",
        "required": [
          "nas_map",
          "revision"
        ],
        "properties": {
          "nas_map": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uuid"
            }
          },
          "revision": {
            "type": "string",
            "description": "SHA256 of the sorted map"
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Public integration and security guides",
    "url": "https://hotspotvu.com/docs/iot"
  }
}
