Scoped authority
Partner, browser, device and infrastructure credentials have different roles.
Implementation candidate · managed-site validation required
The API root is /api/iot/v1. Download /iot/openapi.json for authoritative operations, authentication requirements, request fields, response models, and errors.
Partner, browser, device and infrastructure credentials have different roles.
Use implemented operation IDs, schemas and clients from the downloadable kit.
Paginate results and use bounded retries with operation-specific idempotency.
Target supported hardware and an enabled site. Your application retains its own health and recovery responsibilities.
GET/POST /account supports account state and sandbox registration. /products, /batches, and /devices organize the fleet. /devices/{id}/credentials accepts a CSR; /devices/{id}/revoke handles credential revocation.
/requests shows manufacturer request state. /sites and /sites/{location}/requests provide authorized site views. /requests/{id}/decision accepts allowed, denied, or revoked decisions from the human site owner. /sessions provides authorized connection history.
/tokens, /delegations, /webhooks, /webhook-deliveries, and /production-application support integration and operations. Consult the contract for supported verbs and payloads.
Use stable device identifiers returned by the service. Do not use a MAC address as the durable primary identity or allow device-supplied location identifiers to establish authorization.
Trusted partner services use scoped, expiring service-account bearer credentials. Browser sessions, device credentials, and partner automation credentials are separate.
Authorize every operation within the caller’s company, assigned fleet, or site permissions. A manufacturer can see its own devices without being able to enumerate unrelated businesses or their clients.
/device/config, /device/health, and /device/renew use certificate-bound device reporting bearer tokens. They do not accept partner enrollment authority as a substitute for device identity.
/device/renew also requires a signed private-key proof and idempotent event identifier. See the Linux guide and OpenAPI contract for exact signing bytes and validation. Reporting tokens expire with their associated certificate, and earlier valid tokens are not immediately invalidated by renewal.
AAA, gateway-management, and service-administration endpoints in the contract have separate credentials and permissions. Those secrets never belong in manufacturer firmware, public code, or support messages.
Device enrollment is repeatable using the same external_id, product_id, and batch_id. A conflicting product or batch returns 409. Repeating an unchanged permission decision does not advance the site revision. A generic Idempotency-Key header is not implemented.
Inventory, request, session, and delivery lists use Laravel pagination with 50 records per page. Follow the page query parameter and retain stable identifiers in your own system.
Treat the returned policy decision and observed enforcement separately. An accepted revocation does not prove an offline gateway has received it. Retry transient failures with backoff and retain operation identifiers for support.
The bundled Python client and JavaScript client with TypeScript declarations expose partner-authenticated operations. Client-side bindings omit human-only site decisions and token creation. Install them from the downloaded kit; see the developer overview for installation.
Read request.status for current connection freshness. device.state is an inventory lifecycle field. GET list responses use data and pagination metadata; create-product and enroll-device responses are resource objects.
import os
from hotspotvu_connect import Client, ApiError
api = Client(os.environ["HOTSPOTVU_API"], os.environ["HOTSPOTVU_IOT_TOKEN"])
try:
for device in api.pages("/devices"):
# state is registry lifecycle (active/revoked), not Wi-Fi status.
print(device["id"], device["state"])
for request in api.pages("/requests"):
status = request["status"]
print(request["endpoint_id"], status["authorization"],
status["connection"], status["internet_reachable"],
status["last_confirmed_at"], status["fresh_until"])
except ApiError as error:
# Log the status, never the token or a credential bundle.
print(f"HotSpotVU request failed: HTTP {error.status}")
raiseimport { HotSpotVuClient, HotSpotVuError } from '@hotspotvu/connectivity'
const api = new HotSpotVuClient(
process.env.HOTSPOTVU_API, process.env.HOTSPOTVU_IOT_TOKEN
)
try {
for await (const device of api.devices()) {
console.log(device.id, device.state) // active/revoked; not connectivity
}
for await (const request of api.connectionRequests()) {
const { authorization, connection, internet_reachable, fresh_until } = request.status
console.log(request.endpoint_id, { authorization, connection, internet_reachable, fresh_until })
}
} catch (error) {
if (error instanceof HotSpotVuError) console.error('HotSpotVU HTTP status:', error.status)
throw error
}Build generated clients from the published contract and pin the compatible client version. Validate requests and examples in the sandbox before production use.
Sandbox limits default to ten devices and one authorized test site. Production activation and supported deployment limits are reviewed separately.
Search the implemented operations below. Authentication, field schemas, and response codes come from the downloadable OpenAPI contract.
38 operations · API base path /api/iot/v1
/accountRead active company IoT accountOperation ID: getAccount
Returns account=null before registration. Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.
Authentication: PartnerToken or BrowserSession
{
"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"
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/accountCreate or return self-service sandboxOperation ID: registerAccount
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.
Authentication: BrowserSession + CsrfHeader
{
"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."
}{
"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."
}Response codes: 201, 401, 403, 404, 409, 419, 422, 429, 503
/productsList own and delegated productsOperation ID: listProducts
Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.
Authentication: PartnerToken or BrowserSession
page · query · optional
{
"allOf": [
{
"$ref": "#/components/schemas/PaginationMetadata"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Product"
}
}
},
"required": [
"data"
]
}
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/productsCreate productOperation ID: createProduct
Partner token with write scope, or a company administrator session. Writes affect the own account; delegated access is read-only.
Authentication: PartnerToken or BrowserSession + CsrfHeader
{
"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."
}{
"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"
]
}Response codes: 201, 401, 403, 404, 409, 419, 422, 429, 503
/batchesList own and delegated batchesOperation ID: listBatches
Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.
Authentication: PartnerToken or BrowserSession
page · query · optional
{
"allOf": [
{
"$ref": "#/components/schemas/PaginationMetadata"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Batch"
}
}
},
"required": [
"data"
]
}
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/batchesCreate manufacturing batchOperation ID: createBatch
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.
Authentication: PartnerToken or BrowserSession + CsrfHeader
{
"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."
}{
"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"
]
}Response codes: 201, 401, 403, 404, 409, 419, 422, 429, 503
/devicesList own and delegated devicesOperation ID: listDevices
Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.
Authentication: PartnerToken or BrowserSession
page · query · optional
{
"allOf": [
{
"$ref": "#/components/schemas/PaginationMetadata"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/DeviceListItem"
}
}
},
"required": [
"data"
]
}
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/devicesEnroll individual deviceOperation ID: enrollDevice
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.
Authentication: PartnerToken or BrowserSession + CsrfHeader
{
"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."
}{
"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."
}Response codes: 201, 401, 403, 404, 409, 419, 422, 429, 503
/devices/{device}/credentialsIssue or renew device credentialsOperation ID: issueDeviceCredentials
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.
Authentication: PartnerToken or BrowserSession + CsrfHeader
device · path · required
{
"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."
}{
"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"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 502, 503
/devices/{device}/revokeRevoke device credentials and site permissionsOperation ID: revokeDevice
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.
Authentication: PartnerToken or BrowserSession + CsrfHeader
device · path · required
{
"type": "object",
"properties": {
"state": {
"type": "string",
"const": "revoked"
},
"enforcement": {
"type": "string",
"const": "pending"
}
},
"required": [
"state",
"enforcement"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 503
/requestsList own and delegated requestsOperation ID: listConnectionRequests
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.
Authentication: PartnerToken or BrowserSession
page · query · optional
{
"allOf": [
{
"$ref": "#/components/schemas/PaginationMetadata"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ConnectionRequestView"
}
}
},
"required": [
"data"
]
}
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/requests/{connection}/decisionAllow, deny or revoke device at siteOperation ID: decideConnectionRequest
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.
Authentication: BrowserSession + CsrfHeader
connection · path · required
{
"type": "object",
"properties": {
"decision": {
"type": "string",
"enum": [
"allowed",
"denied",
"revoked"
]
}
},
"required": [
"decision"
],
"additionalProperties": true,
"description": " Unknown request fields are ignored by validation, not persisted."
}{
"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"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 503
/sitesList company locations and IoT stateOperation ID: listSites
Any active-company member can read; unconfigured locations have null IoT fields. Partner bearer tokens not accepted.
Authentication: BrowserSession
{
"type": "array",
"items": {
"$ref": "#/components/schemas/LocationSite"
}
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/sites/{location}Configure local IoT policyOperation ID: configureSite
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.
Authentication: BrowserSession + CsrfHeader
location · path · required
{
"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."
}{
"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"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 503
/sites/{location}/requestsList requests at owned locationOperation ID: listSiteRequests
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.
Authentication: BrowserSession
location · path · required
page · query · optional
{
"allOf": [
{
"$ref": "#/components/schemas/PaginationMetadata"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ConnectionRequestView"
}
}
},
"required": [
"data"
]
}
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/tokensList own token metadataOperation ID: listPartnerTokens
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.
Authentication: BrowserSession
{
"type": "array",
"items": {
"$ref": "#/components/schemas/ApiToken"
}
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/tokensCreate scoped expiring partner tokenOperation ID: createPartnerToken
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.
Authentication: BrowserSession + CsrfHeader
{
"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."
}{
"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"
]
}Response codes: 201, 401, 403, 404, 409, 419, 422, 429, 503
/tokens/{token}Revoke own partner tokenOperation ID: revokePartnerToken
Human company owner/admin or member with hotspotvu.iot.manage, using the active company session and CSRF protection. Partner tokens cannot perform this action.
Authentication: BrowserSession + CsrfHeader
token · path · required
Response codes: 204, 401, 403, 404, 409, 419, 422, 429, 503
/delegationsList grants made by own accountOperation ID: listDelegations
Includes revoked grants. Partner token with read scope, or an authenticated active-company member session. Read-only delegation includes authorized owner fleets.
Authentication: PartnerToken or BrowserSession
{
"type": "array",
"items": {
"$ref": "#/components/schemas/Delegation"
}
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/delegationsGrant or revoke provider read delegationOperation ID: setDelegation
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.
Authentication: BrowserSession + CsrfHeader
{
"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."
}{
"type": "object",
"properties": {
"status": {
"type": "string",
"const": "saved"
},
"access": {
"type": "string",
"const": "read"
}
},
"required": [
"status",
"access"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 503
/sessionsList own and delegated usage sessionsOperation ID: listSessions
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.
Authentication: PartnerToken or BrowserSession
page · query · optional
{
"allOf": [
{
"$ref": "#/components/schemas/PaginationMetadata"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Session"
}
}
},
"required": [
"data"
]
}
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/production-applicationSubmit production applicationOperation ID: applyForProduction
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.
Authentication: BrowserSession + CsrfHeader
{
"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."
}{
"type": "object",
"properties": {
"status": {
"type": "string",
"const": "submitted"
},
"message": {
"type": "string",
"const": "Your sandbox remains available while production access is reviewed."
}
},
"required": [
"status",
"message"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 503
/webhooksList own subscriptionsOperation ID: listWebhooks
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.
Authentication: BrowserSession
{
"type": "array",
"items": {
"$ref": "#/components/schemas/Webhook"
}
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/webhooksCreate approved HTTPS subscriptionOperation ID: createWebhook
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.
Authentication: BrowserSession + CsrfHeader
{
"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."
}{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"secret": {
"type": "string",
"description": "Verification secret returned only once; keep on receiving backend."
}
},
"required": [
"id",
"secret"
]
}Response codes: 201, 401, 403, 404, 409, 419, 422, 429, 503
/webhooks/{webhook}Disable own subscriptionOperation ID: disableWebhook
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.
Authentication: BrowserSession + CsrfHeader
webhook · path · required
Response codes: 204, 401, 403, 404, 409, 419, 422, 429, 503
/webhook-deliveriesList own webhook delivery attemptsOperation ID: listWebhookDeliveries
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.
Authentication: BrowserSession
page · query · optional
{
"allOf": [
{
"$ref": "#/components/schemas/PaginationMetadata"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WebhookDelivery"
}
}
},
"required": [
"data"
]
}
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/infrastructure/accountingInternal: ingest AAA accountingOperation ID: recordInfrastructureAccounting
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.
Authentication: AaaToken
{
"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."
}{
"type": "object",
"properties": {
"event_id": {
"type": "string",
"format": "uuid"
},
"committed": {
"type": "boolean",
"const": true
}
},
"required": [
"event_id",
"committed"
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/gateway/configInternal: retrieve site enforcement policyOperation ID: getGatewayConfig
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.
Authentication: GatewayDeviceId + GatewayApiKey
{
"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."
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/gateway/acknowledgeInternal: acknowledge applied revisionOperation ID: acknowledgeGatewayConfig
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.
Authentication: GatewayDeviceId + GatewayApiKey
{
"type": "object",
"properties": {
"revision": {
"type": "integer",
"minimum": 0
}
},
"required": [
"revision"
],
"additionalProperties": true,
"description": " Unknown request fields are ignored by validation, not persisted."
}{
"type": "object",
"properties": {
"applied_revision": {
"type": "integer",
"minimum": 0
}
},
"required": [
"applied_revision"
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/device/configDevice runtime: retrieve allowed site referencesOperation ID: getDeviceConfig
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.
Authentication: DeviceReportToken
{
"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"
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/device/healthDevice runtime: report observed connectivityOperation ID: reportDeviceHealth
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.
Authentication: DeviceReportToken
{
"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."
}{
"type": "object",
"properties": {
"event_id": {
"type": "string",
"format": "uuid"
},
"committed": {
"type": "boolean",
"const": true
}
},
"required": [
"event_id",
"committed"
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/administrationInternal: inspect accounts and sitesOperation ID: listAdministration
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.
Authentication: ServiceSession
page · query · optional
{
"type": "object",
"properties": {
"accounts": {
"$ref": "#/components/schemas/AdministrationAccountsPage"
},
"sites": {
"type": "array",
"items": {
"$ref": "#/components/schemas/AdministrationSite"
},
"maxItems": 100
}
},
"required": [
"accounts",
"sites"
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503
/administration/accounts/{account}/reviewInternal: review account access and limitsOperation ID: reviewAccount
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.
Authentication: ServiceSession + CsrfHeader
account · path · required
{
"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."
}{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"sandbox",
"production",
"suspended"
]
}
},
"required": [
"status"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 503
/administration/sites/{site}/qualificationInternal: record manual qualificationOperation ID: recordSiteQualification
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.
Authentication: ServiceSession + CsrfHeader
site · path · required
{
"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."
}{
"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"
]
}Response codes: 200, 401, 403, 404, 409, 419, 422, 429, 503
/device/renewDevice runtime: renew credentials with private-key proofOperation ID: renewDeviceCredentials
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.
Authentication: DeviceReportToken
{
"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
}{
"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"
]
}Response codes: 200, 401, 403, 404, 409, 422, 429, 502, 503
/infrastructure/nas-mapInternal AAA: active mutually authenticated NAS registryOperation ID: getInfrastructureNasMap
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.
Authentication: AaaToken
{
"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"
}
}
}Response codes: 200, 403, 429, 503
/administration/sites/{site}/qualification-windowInternal: open or close bounded sandbox hardware test windowOperation ID: setQualificationWindow
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.
Authentication: ServiceSession + CsrfHeader
site · path · required
{
"type": "object",
"required": [
"hours",
"evidence_reference"
],
"properties": {
"hours": {
"type": "integer",
"minimum": 0,
"maximum": 8
},
"evidence_reference": {
"type": "string",
"minLength": 10,
"maxLength": 1000
}
}
}{
"type": "object",
"required": [
"qualification_expires_at",
"hardware_qualified"
],
"properties": {
"qualification_expires_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"hardware_qualified": {
"type": "boolean"
}
}
}Response codes: 200, 401, 403, 404, 409, 422, 429, 503