> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hashgrid.net/llms.txt
> Use this file to discover all available pages before exploring further.

# UNIFI API

# UniFi Network API Documentation (v11.0.97)

## Overview

This document provides comprehensive reference documentation for the UniFi Network API version 11.0.97. Each UniFi Application has its own API endpoints running locally on each site, offering detailed analytics and control related to that specific application. For a single endpoint with high-level insights across all your UniFi sites, refer to the [UniFi Site Manager API](https://developer.ui.com/).

## Operator usage

### Objective

Treat this as the source of truth for Network API shape when verifying endpoint coverage, creating mocks, or checking drift against implementation.

### Prerequisites

* You know the controller type and the applicable API base path.
* You know whether you are validating a read path, write path, or model/schema change.
* You have the current roadmap and phase docs available for cross-checking.

### Procedure

1. Use the table of contents to find the domain you are changing.
2. Confirm the version history before assuming schema or field stability.
3. Check the roadmap alignment note to see whether the behavior is implemented or planned.
4. Use the relevant endpoint details to build tests, runbooks, or operational checks.

### Verification

* The endpoint surface in this doc matches the code and fixtures.
* New fields or schemas are reflected in tests and runbooks.
* The doc does not describe future phase work as already shipped.

### Rollback

* If drift is detected, revert the doc claim to the last known-good surface and log the discrepancy for the next phase update.

### Common failure modes

* Copying upstream API details without checking whether the repo supports them yet.
* Missing a schema drift when the version history changes.
* Using this reference without checking the phase-specific runbooks for operator procedure.

## Table of Contents

* [Getting Started](#getting-started)
* [Example Prompts for MCP Interaction](#example-prompts-for-mcp-interaction)
* [Filtering](#filtering)
* [Error Handling](#error-handling)
* [Application Info](#application-info)
* [Sites](#sites)
* [UniFi Devices](#unifi-devices)
* [Clients](#clients)
* [Networks](#networks)
* [WiFi Broadcasts](#wifi-broadcasts)
* [Hotspot](#hotspot)
* [RADIUS & Guest Portal](#radius--guest-portal)
* [Firewall](#firewall)
* [Firewall Policies](#firewall-policies)
* [Access Control (ACL Rules)](#access-control-acl-rules)
* [Switching](#switching)
* [DNS Policies](#dns-policies)
* [Traffic Matching Lists](#traffic-matching-lists)
* [Quality of Service (QoS)](#quality-of-service-qos)
* [Backup and Restore](#backup-and-restore)
* [Site Manager API](#site-manager-api)
* [Supporting Resources](#supporting-resources)
* [Version History](#version-history)

***

## Version History

### v11.0.97 (October 2026)

Verified against the canonical OpenAPI spec snapshot (`scripts/scraped-api-spec-v11.0.97.json`, audit 2026-10-27). Endpoint count unchanged (73 total, 44 paths) — the Integration API surface has been stable since v10.3.55; all 73 operations confirmed covered by this document. Two optional fields were added to the live spec: `reportFlowEnabled` (boolean) on the firewall-policy create/read/patch schemas, and a `DISABLED` enum value on the read-only `Wireless radio overview` schema's `txPowerMode` field. Neither reaches this server's current implementation: firewall policy CRUD and AP radio configuration both call the v2 local API / legacy `rest/device` endpoints rather than the public Integration API paths these fields belong to (`/v1/sites/{siteId}/firewall/policies/*`), per the existing architecture documented in `DEVELOPMENT_PLAN.md` §2.1. Recorded as a documented, not-yet-implemented capability rather than acted on, since confirming the v2/legacy endpoints' own field support needs a live controller. Also reconfirmed Protect unchanged at v7.3.70 against the pinned v7.3.68 snapshot (same 74 operations, 55 paths, 302 schemas, zero property changes). See `DEVELOPMENT_PLAN.md` §2.3 for the full audit findings.

### v10.6.106 (September 2026)

Verified against the canonical OpenAPI spec snapshot (`scripts/scraped-api-spec-v10.6.106.json`, audit 2026-09-26). Endpoint count unchanged (73 total, 44 paths) — the Integration API surface has been stable since v10.3.55; all 73 operations confirmed covered by this document. Cleanup: embedded v10.1.68 example payloads and reference links updated to v10.6.106. See `DEVELOPMENT_PLAN.md` §2.3 for the full audit findings.

### v10.3.55 (April 2026)

Updated from OpenAPI spec extracted from UniFi Network 10.3.55. Endpoint count unchanged (73 total). Key schema changes:

**Added**

* **DNS Assistance Configuration** — New WiFi broadcast field `dnsAssistanceConfiguration` supporting `AUTO` and `MANUAL` modes. Manual mode allows specifying up to 2 failover DNS servers.
* **Local LAG** — New LAG type `LOCAL` added alongside existing `SWITCH_STACK` and `MULTI_CHASSIS` types. Represented by `IntegrationLocalLagGlobalDto` and `IntegrationLocalLagLocalDto` schemas.
* **IntegrationLagMemberDto** — New unified LAG member schema replacing the removed abstract hierarchy.

**Changed**

* **WiFi Broadcasts** — `IntegrationStandardWifiBroadcastCreateUpdateDto` and `IntegrationStandardWifiBroadcastDetailDto` now include `dnsAssistanceConfiguration`.
* **Open Security Configuration** — `IntegrationWifiOpenSecurityConfigurationDetailDto` gained an `encryption` enum field supporting `ENHANCED_OPEN` and `ENHANCED_OPEN_WITH_TRANSITION`.
* **LAG Details** — Discriminator now includes `LOCAL` mapping.
* **Switching Feature Overview** — Renamed from `Switch feature overview`.

**Removed**

* `AbstractIntegrationLagMemberDto` (replaced by `IntegrationLagMemberDto`)
* `IntegrationMcLagMemberDto` (replaced by unified member schema)
* `IntegrationSwitchStackLagMemberDto` (replaced by unified member schema)

### v10.2.105 (Prior)

Previous baseline. Added Switching section (Switch Stacks, MC-LAG Domains, LAGs), WiFi broadcast parity, and firewall zone/policy endpoints.

***

## Roadmap alignment

This reference currently covers the Network API surface (verified against v10.6.106) plus the Phase 3 Protect read surfaces (cameras, NVRs, devices, views, and events) at their v6-era versions. The Protect v7.3.68 additions are documented below as a planned, not-yet-implemented surface. The broader product roadmap still adds Mobility, InnerSpace, and Carrier Fabric coverage (Phase 6), multi-controller orchestration, dry-run controls, metrics, audit logging, and webhook/event-bus documentation in separate phase-specific docs. Access remains blocked upstream (no official spec published as of 2026-09-26).

***

## Getting Started

### Introduction

Each UniFi Application has its own API endpoints running locally on each site, offering detailed analytics and control related to that specific application. For a single endpoint with high-level insights across all your UniFi sites, refer to the [UniFi Site Manager API](https://developer.ui.com/).

### Authentication and Request Format

An API Key is a unique identifier used to authenticate API requests. To generate API Keys and view an example of the API Request Format, visit the Integrations section of your UniFi application.

**Authentication Header:**

```
X-API-KEY: {YOUR_API_KEY}
Content-Type: application/json
```

### Base URL

All API endpoints are relative to your UniFi controller:

**Integration API (Recommended):**

```
https://{CONTROLLER_IP}/proxy/network/integration/v1
```

**Local API:**

```
https://{CONTROLLER_IP}/proxy/network/api
```

***

## Example Prompts for MCP Interaction

When using an AI assistant with the UniFi MCP Server, you can use natural language prompts to accomplish complex network management tasks. Here are example prompts organized by category:

### Network Discovery & Monitoring

```
"Show me all offline devices on my network"
"List all clients connected to the Guest WiFi network"
"What devices are connected to the main switch in the living room?"
"Show me devices with firmware updates available"
"Which access points have the highest client load right now?"
"Find all devices with uptime less than 24 hours"
```

### QoS & Traffic Management

```
"Create a QoS profile for Zoom video conferencing with 5 Mbps guaranteed bandwidth"
"Set up a ProAV profile for our Dante audio system in the studio"
"Configure Smart Queue Management on WAN1 for my 100 Mbps connection"
"Create a traffic route to prioritize all UDP port 5060 traffic (SIP/VoIP)"
"Show me all QoS profiles and their current bandwidth allocations"
"Validate if my network can support SMPTE 2110 professional video"
```

### Firewall & Security

```
"Create a firewall rule to block all inbound traffic on port 445 (SMB)"
"Set up a firewall policy to allow VPN traffic from the remote office subnet"
"List all firewall rules that are currently blocking traffic"
"Create a zone-based policy to isolate the IoT network from the main LAN"
"Show me recent traffic flows from the Guest network to the internet"
"Block all traffic from China and Russia to my web server"
```

### WiFi & Guest Access

```
"Create a guest WiFi network with a daily voucher system"
"Generate 10 WiFi vouchers valid for 24 hours with 10 Mbps speed limit"
"List all active guest clients and their bandwidth usage"
"Create a separate SSID for IoT devices with device isolation enabled"
"Show me WiFi channel utilization across all access points"
"Set up a hotspot portal with social media authentication"
```

### Network Configuration

```
"Create a new VLAN 20 for the security cameras with 192.168.20.0/24 subnet"
"Set up a static route to reach the remote office subnet via the VPN gateway"
"Configure port forwarding for SSH (port 22) to my home server at 192.168.2.100"
"Create a DHCP reservation for the printer at 192.168.1.50"
"Show me all networks and their current IP address assignments"
"Set up inter-VLAN routing between the main LAN and the security camera network"
```

### RADIUS & Guest Portal

```
"Create a RADIUS profile for our corporate WiFi using the FreeRADIUS server"
"Set up WPA2-Enterprise authentication with VLAN assignment enabled"
"List all RADIUS user accounts for the guest network"
"Create a RADIUS account for the contractor with 7-day expiration"
"Configure the guest portal with a custom welcome message and company logo"
"Set the guest WiFi session timeout to 4 hours with 5 Mbps download limit"
"Create a hotspot package: 1 hour access for $5 with 1GB data quota"
"Show me all active hotspot packages and their pricing"
"Update the guest portal to require terms of service acceptance"
"Enable redirect to our company website after guest login"
```

### Site Management & Health

```
"Show me the overall health status of all my UniFi sites"
"What's the internet connectivity status for the remote office location?"
"List all sites and their WAN uplink speeds"
"Show me any sites experiencing issues or alerts"
"Compare network performance metrics across all sites"
```

### Backups & Recovery

```
"Create a full backup of my site configuration right now"
"Schedule automatic backups every night at 2 AM"
"List all available backups and their creation dates"
"Restore the site configuration from the backup created on January 15th"
"Validate the integrity of my most recent backup"
```

### Advanced Workflows

```
"Set up a home office network with:
- Main LAN on VLAN 10
- Guest WiFi on VLAN 20 (isolated)
- IoT devices on VLAN 30 (restricted internet only)
- Firewall rules to prevent cross-VLAN traffic
- QoS to prioritize video conferencing"

"Configure a ProAV network for live streaming:
- Dedicated VLAN for NDI devices
- QoS profile with 100 Mbps guaranteed bandwidth
- Multicast support enabled
- Traffic routes to prioritize NDI ports
- Monitoring for packet loss and jitter"

"Implement a secure remote access setup:
- L2TP VPN server with strong encryption
- Firewall rules to allow VPN traffic
- QoS to ensure VPN performance
- Traffic routes to route VPN clients through main gateway
- Monitoring for active VPN connections"
```

### Troubleshooting & Diagnostics

```
"Why is my WiFi so slow in the bedroom? Show me the access point status and client connections"
"Diagnose connectivity issues between the printer and my laptop"
"Show me all firewall rules that might be blocking port 443"
"Which device is consuming the most bandwidth right now?"
"List all clients with poor WiFi signal strength (RSSI below -70 dBm)"
"Find any device that's been disconnecting frequently"
```

### Batch Operations

```
"Reboot all access points in the main building"
"Upgrade firmware on all switches to the latest version"
"Create firewall rules to block the top 10 malicious IP addresses"
"Generate 100 guest vouchers for the conference next week"
"Apply the 'Video Conference' QoS profile to all Zoom traffic"
```

### Best Practices for Effective Prompts

1. **Be Specific**: Include exact values (IP addresses, port numbers, VLAN IDs)
2. **Use Context**: Reference existing configurations ("the Guest WiFi", "my main switch")
3. **Request Confirmation**: Ask the AI to explain changes before applying them
4. **Combine Operations**: Chain related tasks in a single conversational flow
5. **Ask for Validation**: Request health checks or impact analysis before major changes
6. **Leverage Dry-Run**: Ask the AI to show what would happen without actually making changes

**Example Multi-Step Conversation:**

```
User: "I need to set up QoS for my Zoom calls. What do you recommend?"

AI: "I recommend creating a QoS profile with priority level 5, DSCP marking 34 (AF41),
     and guaranteed bandwidth of 5 Mbps down / 2 Mbps up. This ensures high-quality
     video even during network congestion. Would you like me to create this?"

User: "Yes, but first show me what the configuration would look like in dry-run mode."

AI: [Shows dry-run output with exact configuration values]

User: "Perfect, go ahead and create it. Also, create a traffic route to apply this
      QoS profile to all UDP traffic on port 8801 (Zoom media)."

AI: [Creates QoS profile and traffic route, confirms success]

User: "Now validate that this is working correctly."

AI: [Shows active traffic flows with DSCP marking applied, confirms QoS is active]
```

***

## Filtering

Explains how to use the filter query parameter for advanced querying across list endpoints.

Some `GET` and `DELETE` endpoints support filtering using the `filter` query parameter. Each endpoint supporting filtering will have a detailed list of filterable properties, their types, and allowed functions.

### Filtering Syntax

Filtering follows a structured, URL-safe syntax with three types of expressions.

#### 1. Property Expressions

Apply functions to an individual property using the form `<property>.<function>(<arguments>)`, where argument values are separated by commas.

**Examples:**

* `id.eq(123)` - checks if `id` is equal to `123`
* `name.isNotNull()` - checks if `name` is not null
* `createdAt.in(2025-01-01, 2025-01-05)` - checks if `createdAt` is either `2025-01-01` or `2025-01-05`

#### 2. Compound Expressions

Combine two or more expressions with logical operators using the form `<logical-operator>(<expressions>)`, where expressions are separated by commas.

**Examples:**

* `and(name.isNull(), createdAt.gt(2025-01-01))` - checks if `name` is null **and** `createdAt` is greater than `2025-01-01`
* `or(name.isNull(), expired.isNull(), expiresAt.isNull())` - checks if **any** of `name`, `expired`, or `expiresAt` is null

#### 3. Negation Expressions

Negate any other expressions using the form `not(<expression>)`.

**Example:**

* `not(name.like('guest*'))` - matches all values except those that start with `guest`

### Filterable Property Types

| Type | Examples | Syntax |
| - | - | - |
| `STRING` | `'Hello, ''World''!'` | Must be wrapped in single quotes. To escape a single quote, use another single quote. |
| `INTEGER` | `123` | Must start with a digit. |
| `DECIMAL` | `123`, `123.321` | Must start with a digit. Can include a decimal point (.). |
| `TIMESTAMP` | `2025-01-29`, `2025-01-29T12:39:11Z` | Must follow ISO 8601 format (date or date-time). |
| `BOOLEAN` | `true`, `false` | Can be `true` or `false`. |
| `UUID` | `550e8400-e29b-41d4-a716-446655440000` | Must be a valid UUID format (8-4-4-4-12). |
| `SET(STRING\|INTEGER\|DECIMAL\|TIMESTAMP\|UUID)` | `[1, 2, 3, 4, 5]` | A set of (unique) values. |

### Filtering Functions

| Function | Arguments | Semantics | Supported Property Types |
| - | - | - | - |
| `isNull` | 0 | is null | all types |
| `isNotNull` | 0 | is not null | all types |
| `eq` | 1 | equals | STRING, INTEGER, DECIMAL, TIMESTAMP, BOOLEAN, UUID |
| `ne` | 1 | not equals | STRING, INTEGER, DECIMAL, TIMESTAMP, BOOLEAN, UUID |
| `gt` | 1 | greater than | STRING, INTEGER, DECIMAL, TIMESTAMP, UUID |
| `ge` | 1 | greater than or equals | STRING, INTEGER, DECIMAL, TIMESTAMP, UUID |
| `lt` | 1 | less than | STRING, INTEGER, DECIMAL, TIMESTAMP, UUID |
| `le` | 1 | less than or equals | STRING, INTEGER, DECIMAL, TIMESTAMP, UUID |
| `like` | 1 | matches pattern | STRING |
| `in` | 1 or more | one of | STRING, INTEGER, DECIMAL, TIMESTAMP, UUID |
| `notIn` | 1 or more | not one of | STRING, INTEGER, DECIMAL, TIMESTAMP, UUID |
| `isEmpty` | 0 | is empty | SET |
| `contains` | 1 | contains | SET |
| `containsAny` | 1 or more | contains any of | SET |
| `containsAll` | 1 or more | contains all of | SET |
| `containsExactly` | 1 or more | contains exactly | SET |

#### Pattern Matching (`like` Function)

* `.` matches any **single** character. Example: `type.like('type.')` matches `type1`, but not `type100`
* `*` matches **any number** of characters. Example: `name.like('guest*')` matches `guest1` and `guest100`
* `\` is used to escape `.` and `*`

***

## Error Handling

Describes the standard API error response structure.

### Error Message Schema

| Field | Type | Description |
| - | - | - |
| `statusCode` | integer (int32) | HTTP status code |
| `statusName` | string | Status name (e.g., UNAUTHORIZED) |
| `code` | string | Error code (e.g., api.authentication.missing-credentials) |
| `message` | string | Human-readable error message |
| `timestamp` | string (date-time) | ISO 8601 timestamp |
| `requestPath` | string | The request path |
| `requestId` | string (uuid) | Request ID for tracking (useful for 500 errors) |

**Example Response:**

```json theme={null}
{
  "statusCode": 400,
  "statusName": "UNAUTHORIZED",
  "code": "api.authentication.missing-credentials",
  "message": "Missing credentials",
  "timestamp": "2024-11-27T08:13:46.966Z",
  "requestPath": "/integration/v1/sites/123",
  "requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
```

***

## Application Info

Returns general details about the UniFi Network application.

### Get Application Info

Retrieve general information about the UniFi Network application.

* **Method:** `GET`
* **Endpoint:** `/v1/info`
* **Response:** `200 OK`

**Example Response:**

```json theme={null}
{
  "applicationVersion": "9.1.0"
}
```

***

## Sites

Endpoints for listing and managing UniFi sites. Site ID is required for most other API requests.

### List Local Sites

Retrieve a paginated list of local sites managed by this Network application.

* **Method:** `GET`
* **Endpoint:** `/v1/sites`

**Query Parameters:**

| Parameter | Type | Default | Description |
| - | - | - | - |
| `offset` | number (int32) | 0 | Pagination offset (>= 0) |
| `limit` | number (int32) | 25 | Pagination limit (0-200) |
| `filter` | string | - | Filter expression |

**Response:** `200 OK`

```json theme={null}
{
  "offset": 0,
  "limit": 25,
  "count": 2,
  "totalCount": 2,
  "data": [
    {
      "id": "default",
      "name": "Default",
      "description": "Default site"
    }
  ]
}
```

***

## UniFi Devices

Endpoints to list, inspect, and interact with UniFi devices.

### List Devices Pending Adoption

* **Method:** `GET`
* **Endpoint:** `/v1/pending-devices`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### List Adopted Devices

Retrieve a paginated list of all adopted devices on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/devices`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Adopt Device

Adopt a device to a site.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/devices`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `macAddress` | string | Yes | MAC address of the device to adopt |
| `ignoreDeviceLimit` | boolean | Yes | Whether to ignore device limit |

**Example Request:**

```json theme={null}
{
  "macAddress": "00:1A:2B:3C:4D:5E",
  "ignoreDeviceLimit": true
}
```

**Response:** `200 OK`

Returns device details including IDs, MAC/IP, firmware, features, and interface lists.

### Get Adopted Device Details

Retrieve detailed information about a specific adopted device.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/devices/{deviceId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |
| `deviceId` | string (uuid) | Yes |

**Response:** `200 OK`

**Response Fields:**

* `id`, `macAddress`, `ipAddress`, `name`, `model`, `supported`, `state`
* `firmwareVersion`, `firmwareUpdatable`
* `adoptedAt`, `provisionedAt`
* `configurationId`, `uplink.deviceId`
* `features.switching`, `features.accessPoint`
* `interfaces.ports[...]`, `interfaces.radios[...]`

### Get Latest Adopted Device Statistics

Retrieve real-time statistics including uptime, CPU, memory utilization.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/devices/{deviceId}/statistics/latest`

**Response:** `200 OK`

```json theme={null}
{
  "uptimeSec": 86400,
  "lastHeartbeatAt": "2025-11-26T12:00:00Z",
  "nextHeartbeatAt": "2025-11-26T12:05:00Z",
  "loadAverage1Min": 0.5,
  "loadAverage5Min": 0.4,
  "loadAverage15Min": 0.3,
  "cpuUtilizationPct": 15.5,
  "memoryUtilizationPct": 45.2,
  "uplink": {
    "txRateBps": 1000000,
    "rxRateBps": 500000
  }
}
```

### Execute Adopted Device Action

Perform an action on a specific adopted device.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/devices/{deviceId}/actions`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |
| `deviceId` | string (uuid) | Yes |

**Request Body:**

| Field | Type | Required | Values |
| - | - | - | - |
| `action` | string | Yes | `RESTART` |

**Response:** `200 OK`

### Execute Port Action

Perform an action on a specific device port.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/devices/{deviceId}/interfaces/ports/{portIdx}/actions`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `portIdx` | integer (int32) | Yes |
| `siteId` | string (uuid) | Yes |
| `deviceId` | string (uuid) | Yes |

**Request Body:**

| Field | Type | Required | Values |
| - | - | - | - |
| `action` | string | Yes | `POWER_CYCLE` |

**Response:** `200 OK`

### Remove (Unadopt) Device

Removes (unadopts) an adopted device from the site. If the device is online, it will be reset to factory defaults.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/devices/{deviceId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |
| `deviceId` | string (uuid) | Yes |

**Response:** `200 OK`

***

### Device Migration (legacy commands)

Local gateway only. Both commands key on the device MAC and are sent to the
site the device is in now.

**Move to another site on this controller**

* **Method:** `POST`
* **Endpoint:** `/api/s/{site}/cmd/sitemgr`
* **Body:** `{"cmd": "move-device", "site": "<target site _id>", "mac": "<mac>"}`
* **MCP Tool:** `move_device_to_site()`
* `site` is the target site's 24-hex `_id`, which only the legacy `/api/self/sites` listing returns. The tool resolves it from a short name, UI description, or `_id`.

**Migrate to another controller**

* **Method:** `POST`
* **Endpoint:** `/api/s/{site}/cmd/devmgr`
* **Body:** `{"cmd": "migrate", "mac": "<mac>", "inform_url": "http://<host>:8080/inform"}`; `{"cmd": "cancel-migrate", "mac": "<mac>"}` aborts
* **MCP Tools:** `migrate_device()`, `cancel_device_migration()`
* After `migrate` the device appears on the new controller as pending adoption.

**Verification:** unit-tested against mocked responses; not yet exercised on live hardware.

***

## Clients

Endpoints for viewing and managing connected clients (wired, wireless, VPN, and guest).

### List Connected Clients

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/clients`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Get Connected Client Details

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/clients/{clientId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `clientId` | string (uuid) | Yes |
| `siteId` | string (uuid) | Yes |

**Response:** `200 OK`

**Response Fields:**

* `type` – one of `WIRED`, `WIRELESS`, `VPN`, `TELEPORT`
* `id`, `name`, `connectedAt`
* `ipAddress`, `macAddress`
* `access.type`
* `uplinkDeviceId`

### Execute Client Action

Perform an action on a specific connected client.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/clients/{clientId}/actions`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `action` | string | Yes | `AUTHORIZE_GUEST_ACCESS` or `UNAUTHORIZE_GUEST_ACCESS` |
| `timeLimitMinutes` | integer (int64) | No | Guest authorization time limit (1-1000000 minutes) |
| `dataUsageLimitMBytes` | integer (int64) | No | Data usage limit (1-1048576 MB) |
| `rxRateLimitKbps` | integer (int64) | No | Download rate limit (2-100000 Kbps) |
| `txRateLimitKbps` | integer (int64) | No | Upload rate limit (2-100000 Kbps) |

**Response:** `200 OK`

***

## Networks

Endpoints for creating, updating, deleting, and inspecting network configurations including VLANs, DHCP, NAT, and IPv4/IPv6 settings.

> **API Limitations (verified 2026-04-13):**
>
> * The v1 Network API only exposes `management`, `name`, `enabled`, `vlanId`, and `dhcpGuarding`. DHCP range, subnet, purpose, and isolation settings are NOT available through the v1 API.
> * The legacy REST API (`/rest/networkconf`) exposes more fields (DHCP, subnet, purpose) but `purpose` is **immutable after creation**.
> * **Network-level client isolation** ("Isolate Network" in the UI) is not available through any documented API. Use `clientIsolationEnabled` on WiFi Broadcasts for SSID-level isolation instead.
> * The legacy REST API uses `"vlan"` (not `"vlan_id"`) for the VLAN number field.

### List Networks

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/networks`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Create Network

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/networks`
* **Response:** `201 Created`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `management` | string | Yes | `UNMANAGED`, `GATEWAY`, or `SWITCH` |
| `name` | string | Yes | Network name |
| `enabled` | boolean | Yes | Enable/disable |
| `vlanId` | integer (int32) | Yes | VLAN ID (2-4000) |
| `dhcpGuarding` | object | No | DHCP Guarding settings |

### Get Network Details

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/networks/{networkId}`

**Response:** `200 OK`

**Response Fields:**

* `management` – `UNMANAGED`, `GATEWAY`, or `SWITCH`
* `id`, `name`, `enabled`
* `vlanId` (2–4000)
* `metadata.origin`
* `dhcpGuarding.trustedDhcpServerIpAddresses[...]`

### Update Network

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/networks/{networkId}`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `management` | string | Yes | `UNMANAGED`, `GATEWAY`, or `SWITCH` |
| `name` | string | Yes | Network name (non-empty) |
| `enabled` | boolean | Yes | Enable/disable |
| `vlanId` | integer | Yes | VLAN ID (2-4000) |
| `dhcpGuarding` | object | No | DHCP Guarding settings (null to disable) |

**Response:** `200 OK`

### Delete Network

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/networks/{networkId}`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `cascade` | boolean | false |
| `force` | boolean | false |

**Response:** `200 OK`

### Get Network References

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/networks/{networkId}/references`

**Response:** `200 OK`

```json theme={null}
{
  "referenceResources": [
    {
      ...
    }
  ]
}
```

***

## WiFi Broadcasts

Endpoints to create, update, or remove WiFi networks (SSIDs). Supports configuration of security, band steering, multicast filtering, and captive portals.

### List Wifi Broadcasts

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/wifi/broadcasts`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Create Wifi Broadcast

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/wifi/broadcasts`
* **Response:** `201 Created`

**Request Body Fields:**

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | string | Yes | `STANDARD` or `IOT_OPTIMIZED` |
| `name` | string | Yes | WiFi broadcast name |
| `enabled` | boolean | Yes | Enable/disable broadcast |
| `network` | object | No | WiFi network reference |
| `securityConfiguration` | object | Yes | WiFi security configuration detail |
| `broadcastingDeviceFilter` | object | No | Custom scope of devices that will broadcast. If null, all AP-capable devices broadcast. |
| `mdnsProxyConfiguration` | object | No | mDNS filtering configuration |
| `multicastFilteringPolicy` | object | No | Multicast filtering policy |
| `multicastToUnicastConversionEnabled` | boolean | Yes | Enable multicast to unicast conversion |
| `clientIsolationEnabled` | boolean | Yes | Enable client isolation |
| `hideName` | boolean | Yes | Hide SSID |
| `uapsdEnabled` | boolean | Yes | Enable Unscheduled Automatic Power Save Delivery (U-APSD) |
| `basicDataRateKbpsByFrequencyGHz` | object | No | Basic data rates by frequency (e.g., `{"5":6000,"2.4":2000}`) |
| `clientFilteringPolicy` | object | No | Client connection filtering policy (allow/restrict by MAC) |
| `blackoutScheduleConfiguration` | object | No | Blackout schedule configuration |
| `broadcastingFrequenciesGHz` | array | Yes | Unique items: `2.4`, `5`, `6` |
| `hotspotConfiguration` | object | No | WiFi hotspot configuration |
| `mloEnabled` | boolean | No | Enable MLO |
| `bandSteeringEnabled` | boolean | No | Enable band steering |
| `arpProxyEnabled` | boolean | Yes | Enable ARP proxy |
| `bssTransitionEnabled` | boolean | Yes | Enable BSS transition |
| `advertiseDeviceName` | boolean | Yes | Advertise device name in beacon frames |
| `dtimPeriodByFrequencyGHzOverride` | object | No | DTIM period configuration by frequency |
| `dnsAssistanceConfiguration` | object | No | DNS assistance configuration. Mode: `AUTO` or `MANUAL`. Manual mode accepts `servers` array (max 2 failover DNS servers). |

### Get Wifi Broadcast Details

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/wifi/broadcasts/{wifiBroadcastId}`

**Response:** `200 OK`

**Response Fields:**

* `type` – `STANDARD` or `IOT_OPTIMIZED`
* `id`, `name`, `enabled`
* `metadata.origin`
* `network.type`
* `securityConfiguration.type`, `securityConfiguration.radiusConfiguration`
* `broadcastingDeviceFilter.type`
* `mdnsProxyConfiguration.mode`
* `multicastFilteringPolicy.action`
* `multicastToUnicastConversionEnabled`
* `clientIsolationEnabled`
* `hideName`, `uapsdEnabled`
* `basicDataRateKbpsByFrequencyGHz`
* `clientFilteringPolicy.action`, `clientFilteringPolicy.macAddressFilter[...]`
* `blackoutScheduleConfiguration.days[...]`
* `broadcastingFrequenciesGHz`
* `hotspotConfiguration.type`
* `mloEnabled`, `bandSteeringEnabled`, `arpProxyEnabled`, `bssTransitionEnabled`, `advertiseDeviceName`
* `dtimPeriodByFrequencyGHzOverride`
* `dnsAssistanceConfiguration.mode`, `dnsAssistanceConfiguration.servers`

### Update Wifi Broadcast

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/wifi/broadcasts/{wifiBroadcastId}`

**Request Body:** Same schema as Create Wifi Broadcast.

**Response:** `200 OK`

### Delete Wifi Broadcast

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/wifi/broadcasts/{wifiBroadcastId}`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `force` | boolean | false |

**Response:** `200 OK`

***

## Hotspot

Endpoints for managing guest access via Hotspot vouchers.

### List Vouchers

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/vouchers`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 100 (max 1000) |
| `filter` | string | - |

**Response:** `200 OK`

### Generate Vouchers

Create one or more Hotspot vouchers.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/vouchers`
* **Response:** `201 Created`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `count` | integer (int32) | No | Number of vouchers to generate (1-1000), Default: 1 |
| `name` | string | Yes | Voucher note, duplicated across all generated vouchers |
| `authorizedGuestLimit` | integer (int64) | No | Limit for how many different guests can use the same voucher (>= 1) |
| `timeLimitMinutes` | integer (int64) | Yes | How long (in minutes) the voucher provides access (1-1000000) |
| `dataUsageLimitMBytes` | integer (int64) | No | Data usage limit in megabytes (1-1048576) |
| `rxRateLimitKbps` | integer (int64) | No | Download rate limit in kilobits per second (2-100000) |
| `txRateLimitKbps` | integer (int64) | No | Upload rate limit in kilobits per second (2-100000) |

### Delete Vouchers

Remove Hotspot vouchers based on the specified filter criteria.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/vouchers`

**Query Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `filter` | string | Yes |

**Response:** `200 OK`

```json theme={null}
{
  "vouchersDeleted": 5
}
```

### Get Voucher Details

Retrieve details of a specific Hotspot voucher.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/vouchers/{voucherId}`

**Response Fields:**

| Field | Type | Description |
| - | - | - |
| `id` | string (uuid) | Voucher ID |
| `createdAt` | string (date-time) | Creation timestamp |
| `name` | string | Voucher note |
| `code` | integer | Voucher code |
| `authorizedGuestLimit` | integer | Max guests allowed |
| `authorizedGuestCount` | integer | Current guests using voucher |
| `activatedAt` | string (date-time) | Activation timestamp |
| `expiresAt` | string (date-time) | Expiration timestamp |
| `expired` | boolean | Expiration status |
| `timeLimitMinutes` | integer | Time limit in minutes |
| `dataUsageLimitMBytes` | integer | Data limit in MB |
| `rxRateLimitKbps` | integer | Download rate limit |
| `txRateLimitKbps` | integer | Upload rate limit |

### Delete Voucher

Remove a specific Hotspot voucher.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/vouchers/{voucherId}`

**Response:** `200 OK`

***

## RADIUS & Guest Portal

Endpoints for managing RADIUS authentication profiles, guest portal configuration, and hotspot packages.

### RADIUS Profile Management

#### List RADIUS Profiles

List all RADIUS authentication profiles for a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/radius/profiles`
* **Response:** `200 OK`

**Response Fields:**

| Field | Type | Description |
| - | - | - |
| `id` | string | RADIUS profile ID |
| `name` | string | Profile name |
| `auth_server` | string | Authentication server IP/hostname |
| `auth_port` | integer | Authentication port (default: 1812) |
| `acct_server` | string | Accounting server IP/hostname |
| `acct_port` | integer | Accounting port (default: 1813) |
| `vlan_enabled` | boolean | VLAN assignment enabled |
| `enabled` | boolean | Profile is active |

#### Get RADIUS Profile

Retrieve a specific RADIUS profile.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/radius/profiles/{profileId}`
* **Response:** `200 OK`

#### Create RADIUS Profile

Create a new RADIUS authentication profile for WPA2-Enterprise.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/radius/profiles`
* **Response:** `201 Created`
* **Requires Confirmation:** `confirm=true`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Profile name |
| `auth_server` | string | Yes | Authentication server IP/hostname |
| `auth_port` | integer | No | Authentication port (default: 1812) |
| `auth_secret` | string | Yes | Shared secret for authentication |
| `acct_server` | string | No | Accounting server IP/hostname |
| `acct_port` | integer | No | Accounting port (default: 1813) |
| `acct_secret` | string | No | Shared secret for accounting |
| `use_same_secret` | boolean | No | Use auth\_secret for accounting (default: true) |
| `vlan_enabled` | boolean | No | Enable VLAN assignment (default: false) |
| `vlan_wlan_mode` | string | No | VLAN mode for WLAN |
| `interim_update_interval` | integer | No | Accounting update interval in seconds |

**Example Request:**

```json theme={null}
{
  "name": "Corporate RADIUS",
  "auth_server": "radius.example.com",
  "auth_port": 1812,
  "auth_secret": "supersecret",
  "acct_port": 1813,
  "vlan_enabled": true
}
```

#### Update RADIUS Profile

Modify an existing RADIUS profile.

* **Method:** `PATCH`
* **Endpoint:** `/v1/sites/{siteId}/radius/profiles/{profileId}`
* **Response:** `200 OK`
* **Requires Confirmation:** `confirm=true`

#### Delete RADIUS Profile

Remove a RADIUS profile.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/radius/profiles/{profileId}`
* **Response:** `200 OK`
* **Requires Confirmation:** `confirm=true`

### RADIUS Account Management

#### List RADIUS Accounts

List all RADIUS user accounts (passwords redacted).

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/radius/accounts`
* **Response:** `200 OK`

**Response Fields:**

| Field | Type | Description |
| - | - | - |
| `id` | string | Account ID |
| `name` | string | Username |
| `password` | string | ***REDACTED*** |
| `enabled` | boolean | Account is active |
| `vlan_id` | integer | Assigned VLAN ID |
| `start_time` | integer | Activation timestamp (Unix) |
| `end_time` | integer | Expiration timestamp (Unix) |

#### Create RADIUS Account

Create a new RADIUS user account for guest access.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/radius/accounts`
* **Response:** `201 Created`
* **Requires Confirmation:** `confirm=true`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Username |
| `password` | string | Yes | Password |
| `enabled` | boolean | No | Account enabled (default: true) |
| `vlan_id` | integer | No | Assigned VLAN ID |
| `start_time` | integer | No | Activation timestamp (Unix) |
| `end_time` | integer | No | Expiration timestamp (Unix) |
| `tunnel_type` | integer | No | RADIUS tunnel type |
| `tunnel_medium_type` | integer | No | RADIUS tunnel medium type |

#### Delete RADIUS Account

Remove a RADIUS user account.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/radius/accounts/{accountId}`
* **Response:** `200 OK`
* **Requires Confirmation:** `confirm=true`

### Guest Portal Configuration

#### Get Guest Portal Config

Retrieve the current guest portal configuration.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/guest-portal/config`
* **Response:** `200 OK`

**Response Fields:**

| Field | Type | Description |
| - | - | - |
| `enabled` | boolean | Guest portal enabled |
| `portal_title` | string | Portal page title |
| `auth_method` | string | Authentication method (none/password/voucher/radius/external) |
| `session_timeout` | integer | Session timeout in minutes (0=unlimited) |
| `redirect_enabled` | boolean | Redirect after authentication |
| `redirect_url` | string | Redirect URL |
| `terms_of_service_enabled` | boolean | Require ToS acceptance |
| `download_limit_kbps` | integer | Download speed limit in kbps |
| `upload_limit_kbps` | integer | Upload speed limit in kbps |

#### Configure Guest Portal

Customize guest portal settings.

* **Method:** `PATCH`
* **Endpoint:** `/v1/sites/{siteId}/guest-portal/config`
* **Response:** `200 OK`
* **Requires Confirmation:** `confirm=true`

**Request Body (all fields optional):**

| Field | Type | Description |
| - | - | - |
| `portal_title` | string | Portal page title |
| `auth_method` | string | Authentication method |
| `password` | string | Portal password (if auth\_method=password) |
| `session_timeout` | integer | Session timeout in minutes |
| `redirect_enabled` | boolean | Enable redirect after auth |
| `redirect_url` | string | Redirect URL |
| `terms_of_service_enabled` | boolean | Require ToS acceptance |
| `terms_of_service_text` | string | Terms of service text |
| `download_limit_kbps` | integer | Download speed limit |
| `upload_limit_kbps` | integer | Upload speed limit |
| `background_image_url` | string | Background image URL |
| `logo_url` | string | Logo image URL |

### Hotspot Package Management

#### List Hotspot Packages

List all available hotspot packages with time and bandwidth limits.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/packages`
* **Response:** `200 OK`

**Response Fields:**

| Field | Type | Description |
| - | - | - |
| `id` | string | Package ID |
| `name` | string | Package name |
| `duration_minutes` | integer | Duration in minutes |
| `download_limit_kbps` | integer | Download speed limit in kbps |
| `upload_limit_kbps` | integer | Upload speed limit in kbps |
| `download_quota_mb` | integer | Download quota in MB |
| `upload_quota_mb` | integer | Upload quota in MB |
| `price` | float | Package price |
| `currency` | string | Currency code |
| `enabled` | boolean | Package is available |

#### Create Hotspot Package

Create a new hotspot package with pricing.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/packages`
* **Response:** `201 Created`
* **Requires Confirmation:** `confirm=true`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Package name |
| `duration_minutes` | integer | Yes | Duration in minutes |
| `download_limit_kbps` | integer | No | Download speed limit in kbps |
| `upload_limit_kbps` | integer | No | Upload speed limit in kbps |
| `download_quota_mb` | integer | No | Download quota in MB |
| `upload_quota_mb` | integer | No | Upload quota in MB |
| `price` | float | No | Package price |
| `currency` | string | No | Currency code (default: USD) |

**Example Request:**

```json theme={null}
{
  "name": "1 Hour Premium",
  "duration_minutes": 60,
  "download_limit_kbps": 10000,
  "upload_limit_kbps": 5000,
  "download_quota_mb": 500,
  "price": 5.99,
  "currency": "USD"
}
```

#### Delete Hotspot Package

Remove a hotspot package.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/hotspot/packages/{packageId}`
* **Response:** `200 OK`
* **Requires Confirmation:** `confirm=true`

***

## Firewall

Endpoints for managing custom firewall zones within a site.

### List Firewall Zones

Retrieve a list of all firewall zones on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/firewall/zones`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Create Custom Firewall Zone

Create a new custom firewall zone on a site.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/firewall/zones`
* **Response:** `201 Created`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Name of firewall zone |
| `networkIds` | array | Yes | List of Network IDs (UUIDs) |

**Example Request:**

```json theme={null}
{
  "name": "My custom zone",
  "networkIds": ["dfb21062-8ea0-4dca-b1d8-1eb3da00e58b"]
}
```

### Get Firewall Zone

Get a firewall zone on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/firewall/zones/{firewallZoneId}`

**Response Fields:**

| Field | Type |
| - | - |
| `id` | string (uuid) |
| `name` | string |
| `networkIds` | array of strings (uuid) |
| `metadata.origin` | string |

### Update Firewall Zone

Update a firewall zone on a site.

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/firewall/zones/{firewallZoneId}`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Name of firewall zone |
| `networkIds` | array | Yes | List of Network IDs (>= 0 items) |

**Response:** `200 OK`

### Delete Custom Firewall Zone

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/firewall/zones/{firewallZoneId}`

**Response:** `200 OK`

***

## Firewall Policies

Endpoints for managing firewall policies within a site. Define or update network segmentation and security boundaries.

### List Firewall Policies

Retrieve a list of all firewall policies on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Create Firewall Policy

Create a new firewall policy on a site.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies`
* **Response:** `201 Created`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `enabled` | boolean | Yes | Enable/disable policy |
| `name` | string | Yes | Policy name (non-empty) |
| `description` | string | No | Policy description |
| `action` | object | Yes | Defines action for matched traffic |
| `source` | object | Yes | Firewall policy source |
| `destination` | object | Yes | Firewall policy destination |
| `ipProtocolScope` | object | Yes | Defines rules for matching by IP version and protocol |
| `connectionStateFilter` | array | No | Match on firewall connection state. Values: `NEW`, `INVALID`, `ESTABLISHED`, `RELATED`. If null, matches all. |
| `ipsecFilter` | string | No | Match on traffic encrypted or not encrypted by IPsec. Values: `MATCH_ENCRYPTED`, `MATCH_NOT_ENCRYPTED`. If null, matches all. |
| `loggingEnabled` | boolean | Yes | Generate syslog entries when traffic is matched |
| `schedule` | object | No | Defines date and time when the entity is active. If null, the entity is always active. |

**Response:** Returns created policy with all fields including `id`, `index`, and `metadata`.

### Get Firewall Policy

Retrieve specific firewall policy.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies/{firewallPolicyId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `firewallPolicyId` | string (uuid) | Yes |
| `siteId` | string (uuid) | Yes |

**Response:** `200 OK`

**Response Fields:**

* `id`, `enabled`, `name`, `description`, `index`
* `action.type`
* `source.firewallZoneId`, `source.trafficFilter`
* `destination.firewallZoneId`, `destination.trafficFilter`
* `ipProtocolScope.ipVersion`
* `connectionStateFilter` (array: `NEW`, `INVALID`, `ESTABLISHED`, `RELATED`)
* `ipsecFilter` (`MATCH_ENCRYPTED`, `MATCH_NOT_ENCRYPTED`)
* `loggingEnabled`
* `schedule.mode`
* `metadata.origin`

### Update Firewall Policy

Update an existing firewall policy on a site.

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies/{firewallPolicyId}`

**Request Body:** Same schema as Create Firewall Policy.

**Response:** `200 OK`

### Patch Firewall Policy

Patch an existing firewall policy on a site.

* **Method:** `PATCH`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies/{firewallPolicyId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `firewallPolicyId` | string (uuid) | Yes |
| `siteId` | string (uuid) | Yes |

**Request Body:**

Partial policy object with only the fields to update.

**Example Request:**

```json theme={null}
{
  "loggingEnabled": true
}
```

**Response:** `200 OK`

### Delete Firewall Policy

Delete an existing firewall policy on a site.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies/{firewallPolicyId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `firewallPolicyId` | string (uuid) | Yes |
| `siteId` | string (uuid) | Yes |

**Response:** `200 OK`

### Get User-Defined Firewall Policy Ordering

Retrieve user-defined firewall policy ordering for a specific source/destination zone pair.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies/ordering`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `sourceFirewallZoneId` | string (uuid) | Yes |
| `destinationFirewallZoneId` | string (uuid) | Yes |

**Response:** `200 OK`

```json theme={null}
{
  "orderedFirewallPolicyIds": {
    "beforeSystemDefined": [...],
    "afterSystemDefined": [...]
  }
}
```

### Reorder User-Defined Firewall Policies

Reorder user-defined firewall policies for a specific source/destination zone pair.

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/firewall/policies/ordering`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `sourceFirewallZoneId` | string (uuid) | Yes |
| `destinationFirewallZoneId` | string (uuid) | Yes |

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `orderedFirewallPolicyIds` | object | Yes | Ordered firewall policy IDs |

**Example Request:**

```json theme={null}
{
  "orderedFirewallPolicyIds": {
    "beforeSystemDefined": [...],
    "afterSystemDefined": [...]
  }
}
```

**Response:** `200 OK`

***

## Access Control (ACL Rules)

Endpoints for creating, listing, and managing ACL rules that enforce traffic filtering across devices and networks.

### List ACL Rules

Retrieve a paginated list of all ACL rules on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/acl-rules`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Create ACL Rule

Create a new user defined ACL rule.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/acl-rules`
* **Response:** `201 Created`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | string | Yes | `IPV4` or `MAC` |
| `enabled` | boolean | Yes | Enable/disable rule |
| `name` | string | Yes | ACL rule name (non-empty) |
| `description` | string | No | ACL rule description |
| `action` | string | Yes | `ALLOW` or `BLOCK` |
| `enforcingDeviceFilter` | object | No | IDs of Switch-capable devices to enforce. When null, rule applies to all switches. |
| `index` | integer (int32) | Yes | Rule priority (>= 0, lower = higher priority). **Deprecated:** Use ACL rule reordering endpoint. |
| `sourceFilter` | object | No | Traffic source filter |
| `destinationFilter` | object | No | Traffic destination filter |
| `protocolFilter` | array | No | Protocols (`TCP`, `UDP`), null = all |

### Get ACL Rule

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/acl-rules/{aclRuleId}`

**Response Fields:**

| Field | Type |
| - | - |
| `type` | string (`IPV4` or `MAC`) |
| `id` | string (uuid) |
| `enabled` | boolean |
| `name` | string |
| `description` | string |
| `action` | string (`ALLOW` or `BLOCK`) |
| `enforcingDeviceFilter` | object |
| `index` | integer |
| `sourceFilter` | object |
| `destinationFilter` | object |
| `metadata.origin` | string |
| `protocolFilter` | array (`TCP`, `UDP`) |

### Update ACL Rule

Update an existing user defined ACL rule.

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/acl-rules/{aclRuleId}`

**Request Body:** Same schema as Create ACL Rule.

**Response:** `200 OK`

### Delete ACL Rule

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/acl-rules/{aclRuleId}`

**Response:** `200 OK`

### Get User-Defined ACL Rule Ordering

Retrieve user-defined ACL rule ordering on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/acl-rules/ordering`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Response:** `200 OK`

```json theme={null}
{
  "orderedAclRuleIds": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"]
}
```

### Reorder User-Defined ACL Rules

Reorder user-defined ACL rules on a site.

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/acl-rules/ordering`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `orderedAclRuleIds` | array | Yes | Array of ACL rule IDs (UUIDs) in desired order |

**Example Request:**

```json theme={null}
{
  "orderedAclRuleIds": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"]
}
```

**Response:** `200 OK`

***

## Switching

Endpoints for managing switching features like Switch Stacking, MC-LAG Domains, and LAG (Link Aggregation Groups). The switching feature overview schema was renamed from `Switch feature overview` to `Switching feature overview` in v10.3.55.

### List Switch Stacks

Retrieve a paginated list of all Switch Stacks on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/switching/switch-stacks`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | integer (int32) | 0 |
| `limit` | integer (int32) | 25 |
| `filter` | string | - |

**Response:** `200 OK` — paginated list

### Get Switch Stack

Retrieve Switch Stack details.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/switching/switch-stacks/{switchStackId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |
| `switchStackId` | string (uuid) | Yes |

**Response:** `200 OK`

```json theme={null}
{
  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  "name": "string",
  "members": [{}, {}],
  "lags": [{}],
  "metadata": {
    "origin": "string"
  }
}
```

### List MC-LAG Domains

Retrieve a paginated list of all MC-LAG Domains on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/switching/mc-lag-domains`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | integer (int32) | 0 |
| `limit` | integer (int32) | 25 |
| `filter` | string | - |

**Response:** `200 OK` — paginated list

### Get MC-LAG Domain

Retrieve MC-LAG Domain details.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/switching/mc-lag-domains/{mcLagDomainId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |
| `mcLagDomainId` | string (uuid) | Yes |

**Response:** `200 OK`

```json theme={null}
{
  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  "name": "string",
  "peers": [{}],
  "lags": [{}],
  "metadata": {
    "origin": "string"
  }
}
```

### List LAGs

Retrieve a paginated list of all LAGs (Link Aggregation Groups) on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/switching/lags`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | integer (int32) | 0 |
| `limit` | integer (int32) | 25 |
| `filter` | string | - |

**Response:** `200 OK` — paginated list

### Get LAG Details

Retrieve LAG details.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/switching/lags/{lagId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |
| `lagId` | string (uuid) | Yes |

**Response:** `200 OK`

```json theme={null}
{
  "type": "SWITCH_STACK",
  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  "members": [
    {
      "deviceId": "bd2c5532-16a4-4f97-91d1-09f6ed6a3b97",
      "portIdxs": [1, 2]
    }
  ],
  "switchStackId": "bd2c5532-16a4-4f97-91d1-09f6ed6a3b97"
}
```

**LAG Types:**

| Type | Description |
| - | - |
| `LOCAL` | Link aggregation on a single switch (new in v10.3.55) |
| `SWITCH_STACK` | Link aggregation across a switch stack |
| `MULTI_CHASSIS` | Multi-chassis link aggregation (MC-LAG) |

**Member Schema:** LAG members use the unified `IntegrationLagMemberDto` schema (replaced `AbstractIntegrationLagMemberDto` and its subclasses in v10.3.55). Each member requires `deviceId` (UUID) and `portIdxs` (array of port indices).

***

## DNS Policies

Endpoints for managing DNS Policies within a site. Supports A, AAAA, CNAME, MX, TXT, SRV records, and domain forwarding.

### List DNS Policies

Retrieve a paginated list of all DNS policies on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/dns/policies`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `siteId` | string (uuid) | Yes |

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Create DNS Policy

Create a new DNS policy on a site.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/dns/policies`
* **Response:** `201 Created`

**Request Body (A\_RECORD example):**

| Field | Type | Required | Description |
| - | - | - | - |
| `type` | string | Yes | Record type (see supported types below) |
| `enabled` | boolean | Yes | Enable/disable policy |
| `domain` | string | Yes | Domain name (1-127 chars) |
| `ipv4Address` | string | Yes\* | IPv4 address (\*for A\_RECORD type) |
| `ttlSeconds` | integer | Yes | Time to live in seconds (0-604800) |

**Supported Types:** `A_RECORD`, `AAAA_RECORD`, `CNAME_RECORD`, `MX_RECORD`, `TXT_RECORD`, `SRV_RECORD`, `FORWARD_DOMAIN`

**Example Request (A\_RECORD):**

```json theme={null}
{
  "type": "A_RECORD",
  "enabled": true,
  "domain": "example.com",
  "ipv4Address": "192.168.2.10",
  "ttlSeconds": 14400
}
```

**Response:** Returns created DNS policy with `id`.

### Get DNS Policy

Retrieve specific DNS policy.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/dns/policies/{dnsPolicyId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `dnsPolicyId` | string (uuid) | Yes |
| `siteId` | string (uuid) | Yes |

**Response:** `200 OK`

**Example Response (A\_RECORD):**

```json theme={null}
{
  "type": "A_RECORD",
  "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  "enabled": true,
  "domain": "example.com",
  "ipv4Address": "192.168.2.10",
  "ttlSeconds": 14400
}
```

### Update DNS Policy

Update an existing DNS policy on a site.

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/dns/policies/{dnsPolicyId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `dnsPolicyId` | string (uuid) | Yes |
| `siteId` | string (uuid) | Yes |

**Request Body:** Same schema as Create DNS Policy for the appropriate record type.

**Response:** `200 OK`

### Delete DNS Policy

Delete an existing DNS policy on a site.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/dns/policies/{dnsPolicyId}`

**Path Parameters:**

| Parameter | Type | Required |
| - | - | - |
| `dnsPolicyId` | string (uuid) | Yes |
| `siteId` | string (uuid) | Yes |

**Response:** `200 OK`

***

## Traffic Matching Lists

Endpoints for managing port and IP address lists used across firewall policy configurations.

### List Traffic Matching Lists ✅

Retrieve all traffic matching lists on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/traffic-matching-lists`
* **MCP Tool:** `list_traffic_matching_lists()`
* **Implementation:** Batch 1 (92.47% coverage)

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### Create Traffic Matching List ✅

Create a new traffic matching list on a site.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/traffic-matching-lists`
* **MCP Tool:** `create_traffic_matching_list()`
* **Implementation:** Batch 1 (92.47% coverage)
* **Response:** `201 Created`

**Request Body:**

| Field | Type | Required |
| - | - | - |
| `type` | string | Yes (`PORTS`, `IPV4_ADDRESSES`, `IPV6_ADDRESSES`) |
| `name` | string | Yes (non-empty) |
| `items` | array | Yes (non-empty) |

**Item shape (issue #282).** Each entry is an object carrying a `type`
discriminator, not a bare string — the API rejects a string with "Missing
`$.items[0].type` value". The MCP tools accept plain values (`"80"`,
`"192.168.3.0/24"`) and map them onto the right object for the list type,
or accept the objects directly:

| List type | Item types | Value fields |
| - | - | - |
| `PORTS` | `PORT_NUMBER`, `PORT_NUMBER_RANGE` | `value`, or `start`/`stop` |
| `IPV4_ADDRESSES` | `IP_ADDRESS`, `IP_ADDRESS_RANGE`, `SUBNET` | `value`, or `start`/`stop` |
| `IPV6_ADDRESSES` | `IP_ADDRESS`, `SUBNET` | `value` |

```json theme={null}
{
  "type": "PORTS",
  "name": "Common Web Ports",
  "items": [
    {"type": "PORT_NUMBER", "value": 80},
    {"type": "PORT_NUMBER", "value": 443}
  ]
}
```

### Get Traffic Matching List ✅

Get an existing traffic matching list on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/traffic-matching-lists/{trafficMatchingListId}`
* **MCP Tool:** `get_traffic_matching_list()`
* **Implementation:** Batch 1 (92.47% coverage)

**Response Fields:**

| Field | Type |
| - | - |
| `type` | string (`PORTS`, `IPV4_ADDRESSES`, `IPV6_ADDRESSES`) |
| `id` | string (uuid) |
| `name` | string |
| `items` | array |

**Example Response (PORTS type):**

```json theme={null}
{
  "type": "PORTS",
  "id": "ffcdb32c-6278-4364-8947-df4f77118df8",
  "name": "Allowed port list",
  "items": [...]
}
```

### Update Traffic Matching List ✅

* **Method:** `PUT`
* **Endpoint:** `/v1/sites/{siteId}/traffic-matching-lists/{trafficMatchingListId}`
* **MCP Tool:** `update_traffic_matching_list()`
* **Implementation:** Batch 1 (92.47% coverage)

**Request Body:**

| Field | Type | Required |
| - | - | - |
| `type` | string | Yes (`PORTS`, `IPV4_ADDRESSES`, `IPV6_ADDRESSES`) |
| `name` | string | Yes (non-empty) |
| `items` | array | Yes (non-empty) |

**Response:** `200 OK`

### Delete Traffic Matching List ✅

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/traffic-matching-lists/{trafficMatchingListId}`
* **MCP Tool:** `delete_traffic_matching_list()`
* **Implementation:** Batch 1 (92.47% coverage)

**Response:** `200 OK`

***

## Quality of Service (QoS)

Manage Quality of Service profiles, ProAV (Professional Audio/Video) protocols, Smart Queue Management (bufferbloat mitigation), and policy-based traffic routing rules.

### Overview

UniFi's QoS system provides comprehensive traffic prioritization and shaping capabilities:

* **QoS Profiles**: Define traffic priority levels (0-7) with DSCP marking (0-63) for bandwidth guarantees
* **ProAV Protocols**: Pre-configured templates for professional audio/video standards (Dante, Q-SYS, SDVoE, AVB, RAVENNA, NDI, SMPTE 2110)
* **Smart Queue Management (SQM)**: Bufferbloat mitigation using fq\_codel on the WAN
* **Traffic Routes**: Policy-based routing rules with match criteria (IP, port, protocol, VLAN) and actions (allow, deny, mark, shape)

**Best Practices:**

* Use priority levels 5-7 for real-time traffic (voice, video conferencing)
* Apply DSCP marking EF (46) for voice, AF41 (34) for high-quality video
* Enable SQM on WAN interfaces under 300 Mbps for best bufferbloat mitigation
* Use reference profiles (voice-first, video-conferencing, cloud-gaming) as starting points
* Test QoS rules during peak hours to validate bandwidth guarantees

### List QoS Profiles ✅

Retrieve all QoS profiles configured for traffic prioritization and bandwidth shaping.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/qos/profiles`
* **MCP Tool:** `list_qos_profiles()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)

**Query Parameters:**

| Parameter | Type | Default | Description |
| - | - | - | - |
| `offset` | number | 0 | Number of items to skip |
| `limit` | number | 100 | Maximum items to return |

**Response:** `200 OK`

```json theme={null}
{
  "data": [
    {
      "_id": "profile-001",
      "name": "Voice Priority",
      "priority_level": 6,
      "dscp_marking": 46,
      "bandwidth_guaranteed_down_kbps": 256,
      "bandwidth_guaranteed_up_kbps": 256,
      "bandwidth_limit_down_kbps": 1024,
      "bandwidth_limit_up_kbps": 512,
      "enabled": true
    }
  ],
  "total": 5,
  "offset": 0,
  "limit": 100
}
```

***

### Get QoS Profile ✅

Retrieve detailed information about a specific QoS profile.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/qos/profiles/{profileId}`
* **MCP Tool:** `get_qos_profile()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)

**Response:** `200 OK`

***

### Create QoS Profile ✅

Create a new QoS profile with comprehensive traffic shaping configuration.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/qos/profiles`
* **MCP Tool:** `create_qos_profile()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)
* **Requires:** `confirm=true`
* **Supports:** `dry_run=true`

**Request Body:**

| Field | Type | Required | Constraints |
| - | - | - | - |
| `name` | string | Yes | Unique profile name |
| `priority_level` | number | Yes | 0-7 (0=lowest, 7=highest) |
| `dscp_marking` | number | No | 0-63 (DSCP value) |
| `bandwidth_guaranteed_down_kbps` | number | No | ≥0 |
| `bandwidth_guaranteed_up_kbps` | number | No | ≥0 |
| `bandwidth_limit_down_kbps` | number | No | ≥0 |
| `bandwidth_limit_up_kbps` | number | No | ≥0 |
| `enabled` | boolean | No | Default: true |
| `schedule` | object | No | Time-based activation |

**Example Request:**

```json theme={null}
{
  "name": "Video Conferencing Premium",
  "priority_level": 5,
  "dscp_marking": 34,
  "bandwidth_guaranteed_down_kbps": 5000,
  "bandwidth_guaranteed_up_kbps": 2000,
  "bandwidth_limit_down_kbps": 10000,
  "bandwidth_limit_up_kbps": 5000,
  "enabled": true,
  "schedule": {
    "days_of_week": [1, 2, 3, 4, 5],
    "start_time": "08:00",
    "end_time": "18:00"
  }
}
```

**Response:** `201 Created`

***

### Update QoS Profile ✅

Update an existing QoS profile's configuration.

* **Method:** `PATCH`
* **Endpoint:** `/v1/sites/{siteId}/qos/profiles/{profileId}`
* **MCP Tool:** `update_qos_profile()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)
* **Requires:** `confirm=true`
* **Supports:** `dry_run=true`

**Request Body:** All fields optional (only provided fields are updated)

**Response:** `200 OK`

***

### Delete QoS Profile ✅

Delete a QoS profile from the site.

* **Method:** `DELETE`
* **Endpoint:** `/v1/sites/{siteId}/qos/profiles/{profileId}`
* **MCP Tool:** `delete_qos_profile()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)
* **Requires:** `confirm=true`

**Response:** `200 OK`

***

### List ProAV Templates ✅

List available Professional Audio/Video protocol templates and reference QoS profiles.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/qos/proav/templates`
* **MCP Tool:** `list_proav_templates()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)

**Response:** `200 OK`

```json theme={null}
{
  "templates": [
    {
      "protocol": "dante",
      "name": "Dante",
      "description": "Audinate Dante professional audio over IP",
      "priority_level": 6,
      "dscp_marking": 46,
      "bandwidth_requirement_mbps": 100,
      "latency_requirement_ms": 5,
      "recommendations": [
        "Enable PTP (Precision Time Protocol) for clock synchronization",
        "Use dedicated VLAN for Dante traffic",
        "Multicast support required",
        "Minimum 1 Gbps network recommended"
      ]
    }
  ],
  "total": 13
}
```

**Available ProAV Protocols:**

* **dante**: Audinate Dante (100 Mbps, 5ms latency, DSCP 46)
* **q-sys**: Q-SYS by QSC (50 Mbps, 10ms latency, DSCP 34)
* **sdvoe**: SDVoE (10 Gbps, 100µs latency, DSCP 46)
* **avb**: Audio Video Bridging (100 Mbps, 2ms latency, DSCP 46)
* **ravenna**: RAVENNA (100 Mbps, 1ms latency, DSCP 46)
* **ndi**: NDI (Network Device Interface) (100 Mbps, 16ms latency, DSCP 34)
* **smpte-2110**: SMPTE 2110 (10 Gbps, 1ms latency, DSCP 46)

**Reference Profiles:**

* **voice-first**: Voice-optimized (128 Kbps guaranteed, DSCP 46)
* **video-conferencing**: Balanced video conferencing (5 Mbps guaranteed, DSCP 34)
* **cloud-gaming**: Low-latency gaming (10 Mbps guaranteed, DSCP 28)
* **streaming-media**: High-bandwidth streaming (25 Mbps guaranteed, DSCP 26)
* **bulk-backup**: Bulk data transfer (no guarantee, DSCP 8)
* **guest-best-effort**: Guest network (throttled to 10 Mbps, DSCP 0)

***

### Create ProAV Profile ✅

Create a QoS profile from a ProAV or reference template with optional customizations.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/qos/proav/profiles`
* **MCP Tool:** `create_proav_profile()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)
* **Requires:** `confirm=true`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `protocol` | string | Yes | ProAV protocol or reference profile name |
| `name` | string | No | Custom name (defaults to protocol name) |
| `priority_level` | number | No | Override template priority |
| `dscp_marking` | number | No | Override template DSCP |
| `bandwidth_multiplier` | number | No | Scale bandwidth (default: 1.0) |
| `enabled` | boolean | No | Enable immediately (default: true) |

**Example Request:**

```json theme={null}
{
  "protocol": "dante",
  "name": "Dante Audio System - Studio A",
  "bandwidth_multiplier": 1.5,
  "enabled": true
}
```

**Response:** `201 Created`

***

### Validate ProAV Profile ✅

Validate that network infrastructure meets ProAV protocol requirements.

* **Method:** `POST`
* **Endpoint:** `/v1/sites/{siteId}/qos/proav/validate`
* **MCP Tool:** `validate_proav_profile()`
* **Implementation:** v0.2.0 Phase 3 (82% coverage)

**Request Body:**

| Field | Type | Required |
| - | - | - |
| `protocol` | string | Yes |
| `bandwidth_mbps` | number | No |

**Response:** `200 OK`

```json theme={null}
{
  "valid": true,
  "protocol": "dante",
  "requirements": {
    "bandwidth_mbps": 100,
    "latency_ms": 5,
    "jitter_tolerance_ms": 1
  },
  "current_capacity": {
    "bandwidth_mbps": 1000,
    "estimated_latency_ms": 2
  },
  "warnings": [],
  "recommendations": [
    "Enable PTP (Precision Time Protocol) for clock synchronization",
    "Use dedicated VLAN for Dante traffic"
  ]
}
```

***

### Smart Queues (WAN fq\_codel)

Smart Queues are not a separate API resource. They are three fields on the WAN
network record served by the Local API's `rest/networkconf` collection:

| Field | Type | Units | Description |
| - | - | - | - |
| `wan_smartq_enabled` | boolean | — | Whether the fq\_codel shaper is on |
| `wan_smartq_down_rate` | number | **kbps** | Shaped download rate |
| `wan_smartq_up_rate` | number | **kbps** | Shaped upload rate |

**Units:** the controller stores both rates in **kbps**, even though the UniFi UI
displays them in Mbps. The MCP tools take and return **Mbps** and convert on
both read and write. Writing a Mbps-scale value straight to the field shapes the
line to about a thousandth of the intended rate (verified live: writing `840`
capped a \~940 Mbps line at 0.84 Mbps).

**WAN selection:** both tools accept an optional `wan_network_id` (the WAN
record's `_id`). If it is omitted, they use the first `networkconf` record with
`purpose: "wan"`.

### Get Smart Queue Status ✅

Read the Smart Queue configuration of a WAN.

* **Method:** `GET`
* **Endpoint:** `/api/s/{site}/rest/networkconf` (filtered to `purpose: "wan"`)
* **MCP Tool:** `get_smart_queue_status(site_id, wan_network_id=None)`

**Tool Response:**

```json theme={null}
{
  "wan_network_id": "5f0c...a1",
  "wan_name": "Primary (WAN1)",
  "enabled": true,
  "download_mbps": 900.0,
  "upload_mbps": 40.0
}
```

`download_mbps` and `upload_mbps` are `null` if the controller has no rate
stored.

***

### Configure Smart Queue ✅

Enable, retune, or disable Smart Queues on a WAN.

* **Method:** `PUT`
* **Endpoint:** `/api/s/{site}/rest/networkconf/{networkId}`
* **MCP Tool:** `configure_smart_queue(site_id, enabled=True, download_mbps=None, upload_mbps=None, wan_network_id=None, confirm=False, dry_run=False)`
* **Requires:** `confirm=true`
* **Supports:** `dry_run=true`

**Tool Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `site_id` | string | Yes | Site identifier |
| `enabled` | boolean | No | Turn the shaper on or off (default: `true`) |
| `download_mbps` | number | When enabling | Shaped download rate, 1–100000 Mbps |
| `upload_mbps` | number | When enabling | Shaped upload rate, 1–100000 Mbps |
| `wan_network_id` | string | No | WAN `networkconf` `_id` (default: primary WAN) |

To disable, call with `enabled=false`; the rates can be omitted.

**Request Body sent to the controller** (for `download_mbps=900, upload_mbps=40`):

```json theme={null}
{
  "wan_smartq_enabled": true,
  "wan_smartq_down_rate": 900000,
  "wan_smartq_up_rate": 40000
}
```

Rate fields are only included when the matching argument is given.

**Tool Response:** Same shape as `get_smart_queue_status`. The values are read
back from the controller after the write, so they show what was stored rather
than what was requested. With `dry_run=true`, the tool returns
`{"dry_run": true, "wan_network_id": ..., "payload": {...}}` and sends nothing.

**Warning:** Applying the change reprovisions the gateway, which can briefly
interrupt WAN traffic.

**Performance Note:** Smart Queues work best on connections below \~300 Mbps.
Above that, gateway CPU overhead may limit throughput.

***

### List Traffic Routes ✅

List UniFi **Traffic Routes** (policy-based routing rules, e.g. sending selected clients or domains through a VPN client network).

* **Method:** `GET`
* **Endpoint:** `/proxy/network/v2/api/site/{site}/trafficroutes` (local gateway only)
* **MCP Tool:** `list_traffic_routes(site_id, limit=100, offset=0)`
* **Note:** Earlier versions read `/api/s/{site}/rest/routing`, which serves static routes, so this tool always returned `[]` (issue #171). An unexpected response shape now raises an error instead of being reported as an empty list.

**Response:** `200 OK`, a bare JSON array (keys verbatim, values illustrative)

```json theme={null}
[
  {
    "_id": "route-001",
    "description": "Laptop via VPN",
    "enabled": true,
    "matching_target": "INTERNET",
    "network_id": "vpn-client-network-id",
    "next_hop": "",
    "kill_switch_enabled": true,
    "domains": [],
    "ip_addresses": [],
    "ip_ranges": [],
    "regions": [],
    "target_devices": [
      { "network_id": "lan-network-id", "type": "NETWORK" },
      { "client_mac": "aa:bb:cc:dd:ee:ff", "type": "CLIENT" }
    ]
  }
]
```

`matching_target` is one of `INTERNET`, `DOMAIN`, `IP` or `REGION`; the matching `domains`, `ip_addresses`, `ip_ranges` or `regions` list holds the criteria. `network_id` is the interface traffic egresses through.

### Create / Update / Delete Traffic Route ❌ (removed)

`create_traffic_route`, `update_traffic_route` and `delete_traffic_route` were removed (issue #171). They posted a document (`action`, `match_criteria`, `dscp_marking`, `priority`, ...) matching no UniFi resource to `rest/routing`. They will return once the v2 write path (`POST /trafficroutes`, `PUT` / `DELETE /trafficroutes/{id}`) has been verified against real hardware.

***

### DSCP Marking Reference

Common DSCP values for traffic classification (RFC 4594):

| DSCP | Binary | Decimal | Traffic Class | Use Case |
| - | - | - | - | - |
| EF | 101110 | 46 | Expedited Forwarding | Voice, real-time interactive |
| AF41 | 100010 | 34 | Assured Forwarding 4-1 | High-quality video conferencing |
| AF31 | 011010 | 26 | Assured Forwarding 3-1 | Streaming media, broadcast video |
| AF21 | 010010 | 18 | Assured Forwarding 2-1 | Bulk data, email |
| CS1 | 001000 | 8 | Class Selector 1 | Background/scavenger traffic |
| DF | 000000 | 0 | Default/Best Effort | Standard internet traffic |

**Assured Forwarding Classes:**

* **AF4x** (32-34): High priority, low drop precedence
* **AF3x** (26-28): Medium priority
* **AF2x** (18-20): Normal priority
* **AF1x** (10-12): Low priority

**Class Selectors (Backward Compatible):**

* **CS7** (56): Network control
* **CS6** (48): Internetwork control
* **CS5** (40): Voice/video
* **CS4** (32): Real-time interactive
* **CS3** (24): Broadcast video
* **CS2** (16): High-throughput data
* **CS1** (8): Low-priority data

***

## Backup and Restore

Comprehensive backup and restore operations for disaster recovery, configuration migration, and system maintenance.

### Overview

UniFi's Backup and Restore system provides critical disaster recovery capabilities:

* **Backup Creation**: Create network or system backups on-demand or on schedule
* **Backup Management**: List, download, validate, and delete backup files
* **Restore Operations**: Restore from backups with automatic pre-restore safety backups
* **Automated Scheduling**: Configure daily, weekly, or monthly automated backups
* **Operation Monitoring**: Track backup and restore progress in real-time
* **Cloud Sync**: Optionally sync backups to UniFi Cloud (requires account)

**Backup Types:**

* **Network Backups** (under 10 MB): Network settings, device configurations, WiFi networks, firewall rules (fastest, recommended for frequent backups)
* **System Backups** (10-100+ MB): Complete OS, application, and device configurations (comprehensive, recommended for major changes)

**Best Practices:**

* Always create a pre-restore backup before restoring (enabled by default)
* Schedule automated daily network backups for production environments
* Keep at least 7-30 days of backup retention
* Download critical backups to external storage before major changes
* Test backup validation before restore operations
* Monitor controller connectivity during restore (controller may restart)

### Trigger Backup ✅

Create a new backup of the specified type.

* **Method:** `POST`
* **Endpoint:** `/api/cmd/backup`
* **MCP Tool:** `trigger_backup()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)
* **Requires:** `confirm=true`
* **Supports:** `dry_run=true`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `backup_type` | string | Yes | "network" or "system" |
| `retention_days` | number | No | Days to retain (default: 30, -1 for indefinite) |

**Example Request:**

```json theme={null}
{
  "backup_type": "network",
  "retention_days": 30
}
```

**Response:** `200 OK`

```json theme={null}
{
  "backup_id": "backup_20260124_123456",
  "filename": "backup_2026-01-24_12-34-56.unf",
  "download_url": "/data/backup/backup_2026-01-24_12-34-56.unf",
  "backup_type": "network",
  "created_at": "2026-01-24T12:34:56Z",
  "retention_days": 30,
  "status": "completed"
}
```

**Note**: Network backups complete in under 30 seconds, system backups may take 1-3 minutes.

**Note (verified live, issue #281)**: on a UniFi OS console the `cmd/backup`
response carries a `url` naming the console's own `/dl/` tree, not the
`/data/backup/` path shown above:

```json theme={null}
{"meta": {"rc": "ok"}, "data": [{"url": "/dl/backup/10.6.109.unf"}]}
```

The backup file is served from `/proxy/network/dl/backup/{filename}`, and
an automatic backup from `/proxy/network/dl/autobackup/{filename}`. A
manual backup is named for the version it was taken from (`10.6.109.unf`),
not the `backup_YYYY-MM-DD_HH-MM-SS.unf` pattern shown above. The
`/proxy/network/data/backup/{filename}` path answers 404 for both.

***

### List Backups ✅

Retrieve metadata for all available backup files.

* **Method:** `GET`
* **Endpoint:** `/api/backup/list-backups`
* **MCP Tool:** `list_backups()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)

**Response:** `200 OK`

```json theme={null}
[
  {
    "filename": "autobackup_10.6.109_20261101_0630_1793514600049.unf",
    "time": 1793514600049,
    "size": 113808,
    "version": "10.6.109",
    "cat": null,
    "datetime": "2026-11-01 06:30"
  }
]
```

**Note (verified live)**: this is the shape a UniFi OS console answers
with. The entries carry no per-item URL, so the download path is built
from the filename — see [Download Backup](#download-backup).

***

### Get Backup Details ✅

Retrieve detailed information about a specific backup.

* **Method:** `GET`
* **Endpoint:** `/api/backup/details/{filename}`
* **MCP Tool:** `get_backup_details()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)

**Path Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `backup_filename` | string | Backup filename (e.g., "backup\_2026-01-24.unf") |

**Response:** `200 OK`

***

### Download Backup ✅

Download a backup file to local storage.

* **Method:** `GET`
* **Endpoint:** `/proxy/network/dl/autobackup/{filename}` (automatic backup) or `/proxy/network/dl/backup/{filename}` (manual backup)
* **MCP Tool:** `download_backup()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)

**Note (verified live, issue #281)**: a UniFi OS console serves backup
files from its `/dl/` tree, one directory per kind. The filename goes in
the path verbatim, and the directory follows the kind of backup:

| Backup | Path |
| - | - |
| Automatic (`autobackup_*.unf`) | `/proxy/network/dl/autobackup/{filename}` |
| Manual (`<version>.unf`, e.g. `10.6.109.unf`) | `/proxy/network/dl/backup/{filename}` |

The `/api/backup/download/{filename}` route below is the legacy Network
Application Server surface, not the console's; on a console it does not
answer. The console's own `cmd/backup` response names the same tree
(`{"url": "/dl/backup/10.6.109.unf"}`).

**Parameters:**

| Parameter | Type | Required | Description |
| - | - | - | - |
| `backup_filename` | string | Yes | Backup filename (a single path component; separators and `..` are rejected) |
| `output_path` | string | Yes | Filename to save under. Only the filename is used — any directory component is ignored and the file is written inside `UNIFI_BACKUP_DOWNLOAD_DIR` (default: the current working directory) |
| `verify_checksum` | boolean | No | Calculate SHA256 checksum (default: true) |

**Example Usage:**

```python theme={null}
result = await download_backup(
    site_id="default",
    backup_filename="autobackup_10.6.109_20261101_0630_1793514600049.unf",
    output_path="unifi_backup.unf",
    settings=settings
)
print(f"Downloaded: {result['size_bytes']} bytes")
print(f"Checksum: {result['checksum']}")
```

***

### Delete Backup ✅

Permanently delete a backup file from controller storage.

* **Method:** `POST`
* **Endpoint:** `/proxy/network/api/s/{site}/cmd/backup` with `{"cmd": "delete-backup", "filename": "..."}` (local) — `/ea/sites/{site}/backups/{filename}` (cloud)
* **MCP Tool:** `delete_backup()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)
* **Requires:** `confirm=true`
* **Supports:** `dry_run=true`

**Warning**: This operation cannot be undone. Ensure backup is downloaded or unnecessary before deletion.

**Verified live** on a UniFi OS console (Network 10.6.109): the command is recognised — a wrong payload key answers `400 api.err.Invalid`, an unknown filename answers `404 api.err.NotFound` — and the server reports the backup it cannot find. The route the tool used before, `DELETE /proxy/network/api/backup/delete-backup/{filename}`, answers `401 api.err.NoSiteContext` on a console: it needs a site context it never carried. A console-level manual backup is not in the Network application's backup manager, so the console's own backup API (`/api/backup/*`, which answers `401` to the Network API key) is the only surface that reaches it.

***

### Restore Backup ✅

Restore the controller from a backup file (DESTRUCTIVE).

* **Method:** `POST`
* **Endpoint:** `/api/backup/restore`
* **MCP Tool:** `restore_backup()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)
* **Requires:** `confirm=true`
* **Supports:** `dry_run=true`

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `backup_filename` | string | Yes | Backup file to restore from |
| `create_pre_restore_backup` | boolean | No | Create safety backup first (default: true) |

**Safety Features:**

* Automatic pre-restore backup creation (recommended)
* Mandatory confirmation flag
* Rollback capability via pre-restore backup
* Audit logging

**Example Request:**

```json theme={null}
{
  "backup_filename": "backup_2026-01-24.unf",
  "create_pre_restore_backup": true
}
```

**Response:** `200 OK`

```json theme={null}
{
  "backup_filename": "backup_2026-01-24.unf",
  "status": "restore_initiated",
  "pre_restore_backup_id": "backup_20260124_140000_preRestore",
  "can_rollback": true,
  "restore_time": "2026-01-24T14:00:00Z",
  "warning": "Controller may restart. Devices may temporarily disconnect."
}
```

**Critical Warning**: Restore operations will:

1. Restore all configuration from the backup
2. Overwrite current settings
3. Cause controller restart (2-5 minutes)
4. Temporarily disconnect devices

***

### Validate Backup ✅

Validate a backup file before restore.

* **Method:** `POST`
* **Endpoint:** `/api/backup/validate`
* **MCP Tool:** `validate_backup()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)

**Response:** `200 OK`

```json theme={null}
{
  "backup_id": "backup_20260124_123456",
  "backup_filename": "backup_2026-01-24.unf",
  "is_valid": true,
  "checksum_valid": true,
  "format_valid": true,
  "version_compatible": true,
  "backup_version": "10.6.106",
  "warnings": [],
  "errors": [],
  "size_bytes": 8456192,
  "validated_at": "2026-01-24T14:00:00Z"
}
```

***

### Get Backup Status ✅

Monitor the progress of an ongoing or completed backup operation.

* **Method:** `GET`
* **Endpoint:** `/api/backup/status/{operationId}`
* **MCP Tool:** `get_backup_status()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)

**Path Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `operation_id` | string | Backup operation identifier (from trigger\_backup) |

**Response:** `200 OK`

```json theme={null}
{
  "operation_id": "op_backup_abc123",
  "status": "completed",
  "progress_percent": 100,
  "current_step": "Finalizing backup",
  "started_at": "2026-01-24T12:34:00Z",
  "completed_at": "2026-01-24T12:35:30Z",
  "backup_metadata": {
    "id": "backup-123",
    "filename": "backup_20260124.unf"
  },
  "error_message": null
}
```

**Status Values:** `pending`, `in_progress`, `completed`, `failed`

**Note**: Most backups complete quickly. This tool is primarily useful for large system backups.

***

### Get Restore Status ✅

Monitor the progress of an ongoing or completed restore operation.

* **Method:** `GET`
* **Endpoint:** `/api/restore/status/{operationId}`
* **MCP Tool:** `get_restore_status()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)

**Path Parameters:**

| Parameter | Type | Description |
| - | - | - |
| `operation_id` | string | Restore operation identifier (from restore\_backup) |

**Response:** `200 OK`

```json theme={null}
{
  "operation_id": "op_restore_xyz789",
  "backup_id": "backup_20260124_123456",
  "status": "in_progress",
  "progress_percent": 45,
  "current_step": "Restoring device configurations",
  "started_at": "2026-01-24T14:00:00Z",
  "completed_at": null,
  "pre_restore_backup_id": "backup_20260124_140000_preRestore",
  "can_rollback": true,
  "error_message": null,
  "rollback_reason": null
}
```

**Status Values:** `pending`, `in_progress`, `completed`, `failed`, `rolled_back`

**Note**: Expect connection errors during restore as controller restarts. Monitor controller connectivity to determine completion.

***

### Schedule Backups ✅

Configure automated backup schedule for recurring backups.

* **Method:** `POST`
* **Endpoint:** `/api/backup/schedule`
* **MCP Tool:** `schedule_backups()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)
* **Requires:** `confirm=true`
* **Supports:** `dry_run=true`

**Request Body:**

| Field | Type | Required | Constraints |
| - | - | - | - |
| `backup_type` | string | Yes | "network" or "system" |
| `frequency` | string | Yes | "daily", "weekly", or "monthly" |
| `time_of_day` | string | Yes | HH:MM format (24-hour) |
| `enabled` | boolean | No | Default: true |
| `retention_days` | number | No | 1-365 (default: 30) |
| `max_backups` | number | No | 1-100 (default: 10) |
| `day_of_week` | number | No | 0-6 (0=Monday, required if weekly) |
| `day_of_month` | number | No | 1-31 (required if monthly) |
| `cloud_backup_enabled` | boolean | No | Sync to cloud (default: false) |

**Example Request (Daily):**

```json theme={null}
{
  "backup_type": "network",
  "frequency": "daily",
  "time_of_day": "03:00",
  "retention_days": 30,
  "max_backups": 10,
  "enabled": true
}
```

**Example Request (Weekly):**

```json theme={null}
{
  "backup_type": "system",
  "frequency": "weekly",
  "time_of_day": "02:00",
  "day_of_week": 6,
  "retention_days": 90,
  "max_backups": 12,
  "cloud_backup_enabled": true,
  "enabled": true
}
```

**Response:** `201 Created`

```json theme={null}
{
  "schedule_id": "schedule_daily_network",
  "site_id": "default",
  "enabled": true,
  "backup_type": "network",
  "frequency": "daily",
  "time_of_day": "03:00",
  "retention_days": 30,
  "max_backups": 10,
  "cloud_backup_enabled": false,
  "configured_at": "2026-01-24T14:30:00Z",
  "next_run": "2026-01-25T03:00:00Z"
}
```

**Scheduling Recommendations:**

* **Daily network backups**: Production environments (3 AM recommended)
* **Weekly system backups**: Most use cases (Sunday 2 AM recommended)
* **Monthly backups**: Only for static environments

***

### Get Backup Schedule ✅

Retrieve the configured automated backup schedule for a site.

* **Method:** `GET`
* **Endpoint:** `/api/backup/schedule`
* **MCP Tool:** `get_backup_schedule()`
* **Implementation:** v0.2.0 Phase 4 (86% coverage)

**Response (Configured):** `200 OK`

```json theme={null}
{
  "configured": true,
  "schedule_id": "schedule_daily_network",
  "enabled": true,
  "backup_type": "network",
  "frequency": "daily",
  "time_of_day": "03:00",
  "retention_days": 30,
  "max_backups": 10,
  "cloud_backup_enabled": true,
  "last_run": "2026-01-24T03:00:00Z",
  "last_backup_id": "backup-123",
  "next_run": "2026-01-25T03:00:00Z"
}
```

**Response (Not Configured):** `200 OK`

```json theme={null}
{
  "configured": false,
  "message": "No automated backup schedule configured for this site",
  "recommendation": "Use schedule_backups to configure automated backups"
}
```

***

## Site Manager API

**Implementation:** v0.2.0 Phase 5 (\~60% complete)
**Coverage:** 92.95% (33 tests passing)
**Status:** Multi-site aggregation complete, OAuth/SSO pending

The Site Manager API provides centralized management and monitoring capabilities across multiple UniFi sites. These tools enable comprehensive oversight of distributed network deployments through unified health metrics, performance comparisons, inventory management, and cross-site search functionality.

**⚠️ Configuration Required:**

```bash theme={null}
export UNIFI_SITE_MANAGER_ENABLED=true
export UNIFI_API_KEY=<your-site-manager-api-key>
export UNIFI_API_TYPE=cloud-ea  # or cloud-v1
```

### Overview

The Site Manager API consists of 8 tools organized into three categories:

**Basic Aggregation:**

* List all sites with aggregated statistics
* Get internet health metrics
* Get site health summaries
* List Vantage Points

**Advanced Analytics:**

* Get site inventory (comprehensive resource breakdown)
* Compare site performance (rankings and metrics)
* Get cross-site statistics

**Search & Discovery:**

* Search across sites (devices, clients, networks)

***

### Example Prompts for Site Manager

```
"Show me all my sites and their current health status"
"Which site has the best uptime and performance?"
"Find all Ubiquiti access points across all my locations"
"Give me a complete inventory of devices at the downtown office"
"Compare performance metrics between all my branch offices"
"Search for the device with MAC address aa:bb:cc:dd:ee:ff across all sites"
"Show me sites with degraded internet connectivity"
"Which site has the most devices offline right now?"
```

***

### List All Sites Aggregated ✅

List all managed sites with aggregated statistics from the Site Manager API.

* **Method:** `GET`
* **Endpoint:** `/v1/sites`
* **MCP Tool:** `list_all_sites_aggregated()`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

**Request:** No parameters required.

**Response:** `200 OK`

```json theme={null}
[
  {
    "site_id": "site-abc123",
    "name": "Main Office",
    "devices": 25,
    "clients": 150,
    "status": "healthy",
    "uptime_percentage": 99.9
  },
  {
    "site_id": "site-def456",
    "name": "Branch Office",
    "devices": 10,
    "clients": 50,
    "status": "degraded",
    "uptime_percentage": 95.0
  }
]
```

***

### Get Internet Health ✅

Get internet connectivity health metrics across sites or for a specific site.

* **Method:** `GET`
* **Endpoint:** `/v1/internet/health` or `/v1/sites/{siteId}/internet/health`
* **MCP Tool:** `get_internet_health(site_id=None)`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `site_id` | string | No | Site identifier (None for aggregate) |

**Response (Aggregate):** `200 OK`

```json theme={null}
{
  "site_id": null,
  "latency_ms": 25.5,
  "packet_loss_percent": 0.1,
  "jitter_ms": 2.3,
  "bandwidth_up_mbps": 100.0,
  "bandwidth_down_mbps": 500.0,
  "status": "healthy",
  "last_tested": "2026-01-24T12:00:00Z"
}
```

**Response (Specific Site):** `200 OK`

```json theme={null}
{
  "site_id": "site-abc123",
  "latency_ms": 15.0,
  "packet_loss_percent": 0.0,
  "jitter_ms": 1.0,
  "bandwidth_up_mbps": 50.0,
  "bandwidth_down_mbps": 200.0,
  "status": "healthy",
  "last_tested": "2026-01-24T12:00:00Z"
}
```

***

### Get Site Health Summary ✅

Get health summary for all sites or a specific site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/health` or `/v1/sites/{siteId}/health`
* **MCP Tool:** `get_site_health_summary(site_id=None)`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `site_id` | string | No | Site identifier (None for all sites) |

**Response (All Sites):** `200 OK`

```json theme={null}
[
  {
    "site_id": "site-abc123",
    "site_name": "Main Office",
    "status": "healthy",
    "devices_online": 25,
    "devices_total": 25,
    "clients_active": 150,
    "uptime_percentage": 99.9,
    "last_updated": "2026-01-24T12:00:00Z"
  },
  {
    "site_id": "site-def456",
    "site_name": "Branch Office",
    "status": "degraded",
    "devices_online": 8,
    "devices_total": 10,
    "clients_active": 50,
    "uptime_percentage": 95.0,
    "last_updated": "2026-01-24T12:00:00Z"
  }
]
```

***

### Get Cross-Site Statistics ✅

Get aggregated statistics across all managed sites.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/statistics`
* **MCP Tool:** `get_cross_site_statistics()`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

**Request:** No parameters required.

**Response:** `200 OK`

```json theme={null}
{
  "total_sites": 5,
  "sites_healthy": 3,
  "sites_degraded": 1,
  "sites_down": 1,
  "total_devices": 75,
  "devices_online": 68,
  "total_clients": 350,
  "total_bandwidth_up_mbps": 500.0,
  "total_bandwidth_down_mbps": 2500.0,
  "site_summaries": [
    {
      "site_id": "site-abc123",
      "site_name": "Main Office",
      "status": "healthy",
      "devices_online": 25,
      "devices_total": 25,
      "clients_active": 150,
      "uptime_percentage": 99.9,
      "last_updated": "2026-01-24T12:00:00Z"
    }
  ]
}
```

***

### List Vantage Points ✅

List all Vantage Points for network monitoring and testing.

* **Method:** `GET`
* **Endpoint:** `/v1/vantage-points`
* **MCP Tool:** `list_vantage_points()`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

**Request:** No parameters required.

**Response:** `200 OK`

```json theme={null}
[
  {
    "vantage_point_id": "vp-123",
    "name": "New York Office",
    "location": "New York, NY",
    "latitude": 40.7128,
    "longitude": -74.0060,
    "status": "active",
    "site_ids": ["site-abc123", "site-def456"]
  },
  {
    "vantage_point_id": "vp-456",
    "name": "London Office",
    "location": "London, UK",
    "latitude": 51.5074,
    "longitude": -0.1278,
    "status": "active",
    "site_ids": ["site-ghi789"]
  }
]
```

***

### Get Site Inventory ✅ 🆕

Get comprehensive inventory for a site or all sites.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/inventory` or `/v1/sites/inventory`
* **MCP Tool:** `get_site_inventory(site_id=None)`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

Provides detailed resource breakdown including device counts by type, networks, SSIDs, VPN tunnels, and firewall rules.

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `site_id` | string | No | Site identifier (None for all sites) |

**Response (Specific Site):** `200 OK`

```json theme={null}
{
  "site_id": "site-abc123",
  "site_name": "Main Office",
  "device_count": 25,
  "device_types": {
    "uap": 15,
    "usw": 8,
    "ugw": 2
  },
  "client_count": 150,
  "network_count": 8,
  "ssid_count": 5,
  "uplink_count": 2,
  "vpn_tunnel_count": 4,
  "firewall_rule_count": 45,
  "last_updated": "2026-01-24T12:00:00Z"
}
```

**Response (All Sites):** `200 OK`

Returns an array of inventory objects for each site.

***

### Compare Site Performance ✅ 🆕

Compare performance metrics across all sites with rankings.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/performance/compare`
* **MCP Tool:** `compare_site_performance()`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

Analyzes uptime, latency, bandwidth, and health status to identify best and worst performing sites.

**Request:** No parameters required.

**Response:** `200 OK`

```json theme={null}
{
  "total_sites": 3,
  "best_performing_site": {
    "site_id": "site-abc123",
    "site_name": "Main Office",
    "avg_latency_ms": 10.0,
    "avg_bandwidth_up_mbps": 100.0,
    "avg_bandwidth_down_mbps": 500.0,
    "uptime_percentage": 99.9,
    "device_online_percentage": 100.0,
    "client_count": 150,
    "health_status": "healthy"
  },
  "worst_performing_site": {
    "site_id": "site-ghi789",
    "site_name": "Remote Office",
    "avg_latency_ms": 150.0,
    "avg_bandwidth_up_mbps": 20.0,
    "avg_bandwidth_down_mbps": 100.0,
    "uptime_percentage": 80.0,
    "device_online_percentage": 50.0,
    "client_count": 20,
    "health_status": "degraded"
  },
  "average_uptime": 91.63,
  "average_latency_ms": 61.67,
  "site_metrics": [
    {
      "site_id": "site-abc123",
      "site_name": "Main Office",
      "avg_latency_ms": 10.0,
      "uptime_percentage": 99.9,
      "health_status": "healthy"
    },
    {
      "site_id": "site-def456",
      "site_name": "Branch Office",
      "avg_latency_ms": 25.0,
      "uptime_percentage": 95.0,
      "health_status": "healthy"
    },
    {
      "site_id": "site-ghi789",
      "site_name": "Remote Office",
      "avg_latency_ms": 150.0,
      "uptime_percentage": 80.0,
      "health_status": "degraded"
    }
  ]
}
```

**Use Cases:**

* Identify sites needing infrastructure upgrades
* Compare performance across geographic regions
* Track improvement over time
* SLA compliance monitoring

***

### Search Across Sites ✅ 🆕

Search for devices, clients, or networks across all managed sites.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/search`
* **MCP Tool:** `search_across_sites(query, search_type='all')`
* **Implementation:** v0.2.0 Phase 5 (93% coverage)

Useful for locating resources in multi-site deployments. Supports search by name, MAC address, or IP address.

**Request Body:**

| Field | Type | Required | Description |
| - | - | - | - |
| `query` | string | Yes | Search query (name, MAC, IP) |
| `search_type` | string | No | "device", "client", "network", or "all" (default: "all") |

**Example Request:**

```json theme={null}
{
  "query": "ap-living",
  "search_type": "device"
}
```

**Response:** `200 OK`

```json theme={null}
{
  "total_results": 2,
  "search_query": "ap-living",
  "result_type": "device",
  "results": [
    {
      "type": "device",
      "site_id": "site-abc123",
      "site_name": "Main Office",
      "resource": {
        "name": "AP-Living-Room",
        "mac": "aa:bb:cc:dd:ee:01",
        "type": "uap",
        "model": "U6-Pro",
        "ip": "192.168.2.10",
        "status": "online"
      }
    },
    {
      "type": "device",
      "site_id": "site-def456",
      "site_name": "Branch Office",
      "resource": {
        "name": "AP-Living-Area",
        "mac": "aa:bb:cc:dd:ee:02",
        "type": "uap",
        "model": "U6-Lite",
        "ip": "192.168.2.10",
        "status": "online"
      }
    }
  ]
}
```

**Search Types:**

* `device` - Search devices by name or MAC address
* `client` - Search clients by name, MAC, or IP address
* `network` - Search networks by name
* `all` - Search all resource types

**Use Cases:**

* Locate specific device across multiple locations
* Find all instances of a client device
* Identify which site has a particular resource
* MAC address tracking for security investigations

***

## Supporting Resources

Contains read-only reference endpoints used to retrieve supporting data such as WAN interfaces, DPI categories, country codes, RADIUS profiles, and device tags.

### List WAN Interfaces

Returns available WAN interface definitions for a given site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/wans`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |

**Response:** `200 OK`

### List Site-To-Site VPN Tunnels ✅

Retrieve a paginated list of all site-to-site VPN tunnels on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/vpn/site-to-site-tunnels`
* **MCP Tool:** `list_vpn_tunnels()`
* **Implementation:** Batch 2 (100% coverage)

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### List VPN Servers ✅

Retrieve a paginated list of all VPN servers on a site.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/vpn/servers`
* **MCP Tool:** `list_vpn_servers()`
* **Implementation:** Batch 2 (100% coverage)

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### List Radius Profiles ✅

Returns available RADIUS authentication profiles.

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/radius/profiles`
* **MCP Tool:** `list_radius_profiles()`
* **Implementation:** Batch 3 (100% coverage)

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### List Device Tags ✅

Returns all device tags defined within a site (used for WiFi Broadcast assignments).

* **Method:** `GET`
* **Endpoint:** `/v1/sites/{siteId}/device-tags`
* **MCP Tool:** `list_device_tags()`
* **Implementation:** Batch 3 (100% coverage)

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### MAC Tags (legacy, writable)

The Integration API only lists device tags. Tags are created and edited on the
local gateway's legacy REST collection, where each tag is a name plus a
`member_table` of device MAC addresses.

* **Endpoint:** `/api/s/{site}/rest/tag` (`GET`, `POST`) and `/api/s/{site}/rest/tag/{tagId}` (`GET`, `PUT`, `DELETE`)
* **Body:** `{"name": "Lobby APs", "member_table": ["aa:bb:cc:dd:ee:01"]}`
* **MCP Tools:** `list_mac_tags()`, `get_mac_tag()`, `create_mac_tag()`, `update_mac_tag()`, `delete_mac_tag()`
* **API mode:** local only
* **Verification:** unit-tested against mocked responses; not yet exercised on live hardware. Writes re-read the tag when the controller does not echo it, and report any member difference as a warning.

### List DPI Categories

Returns predefined Deep Packet Inspection (DPI) categories used for traffic identification and filtering.

* **Method:** `GET`
* **Endpoint:** `/v1/dpi/categories`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### List DPI Applications

Lists DPI-recognized applications grouped under categories.

* **Method:** `GET`
* **Endpoint:** `/v1/dpi/applications`

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

### List Countries ✅

Returns ISO-standard country codes and names.

* **Method:** `GET`
* **Endpoint:** `/v1/countries`
* **MCP Tool:** `list_countries()` (enhanced with pagination)
* **Implementation:** Batch 3 (100% coverage)

**Query Parameters:**

| Parameter | Type | Default |
| - | - | - |
| `offset` | number | 0 |
| `limit` | number | 25 |
| `filter` | string | - |

**Response:** `200 OK`

***

## Common Response Format (Paginated Lists)

All list endpoints return a standard paginated response:

```json theme={null}
{
  "offset": 0,
  "limit": 25,
  "count": 10,
  "totalCount": 1000,
  "data": [...]
}
```

| Field | Description |
| - | - |
| `offset` | Current pagination offset |
| `limit` | Maximum items per page |
| `count` | Items in current response |
| `totalCount` | Total items available |
| `data` | Array of result objects |

***

## Notes

* All timestamps use ISO 8601 format
* All endpoints require valid API key authentication via `X-API-KEY` header
* Rate limiting applies per API key
* Mutating operations should implement confirmation flags in MCP server implementations
* The API is under active development; check changelog for updates

***

**Documentation Version:** v10.0.160
**Last Updated:** January 23, 2026
**Source:** UniFi Network API v10.0.160 (Merged Update)

## Site Manager API - New Endpoints

*Added: 2026-01-24*

### Version Control

Endpoints combined into Ansible Modules for customized workflows.

**Reference:** [Version Control](https://developer.ui.com/site-manager/v1.0.0/versioncontrol)

***

### List Hosts

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L "https://api.ui.com/v1/hosts?pageSize=10&nextToken=602232A870250000000006C514FF00000000073DD8DB000000006369FDA2%3A1467082514" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [List Hosts](https://developer.ui.com/site-manager/v1.0.0/listhosts)

***

### Get Host by ID

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/hosts/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get Host by ID](https://developer.ui.com/site-manager/v1.0.0/gethostbyid)

***

### List Sites

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L "https://api.ui.com/v1/sites?pageSize=10&nextToken=602232A870250000000006C514FF00000000073DD8DB000000006369FDA2%3A1467082514" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [List Sites](https://developer.ui.com/site-manager/v1.0.0/listsites)

***

### Get ISP Metrics

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/isp-metrics/{type}?beginTimestamp=2024-06-30T13%3A35%3A00Z&endTimestamp=2024-06-30T15%3A35%3A00Z&duration={duration}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get ISP Metrics](https://developer.ui.com/site-manager/v1.0.0/getispmetrics)

***

## Network API - New Endpoints

*Added: 2026-01-24*

### Connector - POST

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"action\": \"AUTHORIZE_GUEST_ACCESS\"}"
```

**Reference:** [Connector - POST](https://developer.ui.com/network/v10.6.106/connectorpost)

***

### Connector - GET

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Connector - GET](https://developer.ui.com/network/v10.6.106/connectorget)

***

### Connector - PUT

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PUT "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"Updated Firewall Zone\"}"
```

**Reference:** [Connector - PUT](https://developer.ui.com/network/v10.6.106/connectorput)

***

### Connector - DELETE

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X DELETE "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Connector - DELETE](https://developer.ui.com/network/v10.6.106/connectordelete)

***

### Connector - PATCH

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"Updated Viewer Name\"}"
```

**Reference:** [Connector - PATCH](https://developer.ui.com/network/v10.6.106/connectorpatch)

***

## Protect API - New Endpoints

*Added: 2026-01-24*

### Protect Phase 3 implemented surfaces

These tools are currently wired for local Protect integration via the
`/proxy/protect/integration/v1/...` path family and are available in the
dedicated `protect` profile.

| Surface | Endpoint(s) | MCP tools / resources | Notes |
| - | - | - | - |
| Cameras | `/proxy/protect/integration/v1/cameras`, `/proxy/protect/integration/v1/cameras/{id}` | `protect://cameras`, `protect://cameras/{camera_id}`, `list_protect_cameras`, `get_protect_camera` | Implemented |
| NVRs | `/proxy/protect/integration/v1/nvrs`, `/proxy/protect/integration/v1/nvrs/{id}` | `protect://nvrs`, `protect://nvrs/{nvr_id}`, `list_protect_nvrs`, `get_protect_nvr` | Implemented |
| Devices | `/proxy/protect/integration/v1/devices`, `/proxy/protect/integration/v1/devices/{id}` | `list_protect_devices`, `get_protect_device`, `update_protect_device` | Generic Protect device inventory and updates |
| Lights | `/proxy/protect/integration/v1/lights`, `/proxy/protect/integration/v1/lights/{id}` | `list_protect_lights`, `get_protect_light`, `update_protect_light` | Implemented |
| Sensors | `/proxy/protect/integration/v1/sensors`, `/proxy/protect/integration/v1/sensors/{id}` | `list_protect_sensors`, `get_protect_sensor`, `update_protect_sensor` | Implemented |
| Chimes | `/proxy/protect/integration/v1/chimes`, `/proxy/protect/integration/v1/chimes/{id}` | `list_protect_chimes`, `get_protect_chime`, `update_protect_chime` | Implemented |
| Device subscriptions | `/proxy/protect/integration/v1/subscribe/devices` | `list_protect_device_updates`, `get_protect_subscribe_devices`, `get_protect_device_updates` | Read-only subscription feed |
| Protect metadata | `/proxy/protect/integration/v1/meta/info` | `get_protect_meta_info` | Implemented |
| Viewers | `/proxy/protect/integration/v1/viewers`, `/proxy/protect/integration/v1/viewers/{id}` | `list_protect_viewers`, `get_protect_viewer`, `update_protect_viewer` | Implemented |
| Live views | `/proxy/protect/integration/v1/liveviews`, `/proxy/protect/integration/v1/liveviews/{id}` | `list_protect_live_views`, `get_protect_live_view`, `create_protect_live_view`, `update_protect_live_view` | Implemented |
| Events | `/proxy/protect/integration/v1/subscribe/events` | `list_protect_events`, `get_protect_subscribe_events`, `get_protect_event_messages` | Read-only event feed |
| Alarm webhooks | `/proxy/protect/integration/v1/alarm-manager/webhook/{id}` | `send_protect_alarm_webhook` | Implemented |

Snapshot helpers, media streams, talkback, and PTZ endpoints are still planned and should not be treated as live MCP tools yet.

### Connector - POST

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"action\": \"AUTHORIZE_GUEST_ACCESS\"}"
```

**Reference:** [Connector - POST](https://developer.ui.com/protect/v7.3.68/connectorpost)

***

### Connector - GET

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Connector - GET](https://developer.ui.com/protect/v7.3.68/connectorget)

***

### Connector - PUT

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PUT "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"Updated Firewall Zone\"}"
```

**Reference:** [Connector - PUT](https://developer.ui.com/protect/v7.3.68/connectorput)

***

### Connector - DELETE

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X DELETE "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Connector - DELETE](https://developer.ui.com/protect/v7.3.68/connectordelete)

***

### Connector - PATCH

* **Method:** `GET`
* **Endpoint:** `requests`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{id}/*path" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"Updated Viewer Name\"}"
```

**Reference:** [Connector - PATCH](https://developer.ui.com/protect/v7.3.68/connectorpatch)

***

### Query ISP Metrics

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/isp-metrics/{type}/query" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"sites\": [    {      \"beginTimestamp\": \"2024-06-30T13:35:00Z\",      \"hostId\": \"900A6F00301100000000074A6BA90000000007A3387E0000000063EC9853:123456789\",      \"endTimestamp\": \"2024-06-30T15:35:00Z\",      \"siteId\": \"661900ae6aec8f548d49fd54\"    }  ]}"
```

**Reference:** [Query ISP Metrics](https://developer.ui.com/site-manager/v1.0.0/queryispmetrics)

***

### List SD-WAN Configs

**Implementation reconciliation (2026-11-08, `311fce7`):** The official Site Manager v1.0.0 OpenAPI at [https://developer.ui.com/site-manager/v1.0.0/openapi.json](https://developer.ui.com/site-manager/v1.0.0/openapi.json) defines GET `/v1/sd-wan-configs`, GET `/v1/sd-wan-configs/{id}`, and GET `/v1/sd-wan-configs/{id}/status` against `https://api.ui.com`. The repository client formerly used `/v1/sdwan/configs`, while this document already had the official paths. The list returns `{data: [{id, name, type}], httpStatusCode, traceId}` and declares no pagination. Detail includes settings/hubs/spokes; status includes generation/application and tunnel records, not a single fabricated deployment health. This is config/status read coverage only, not typed destination/performance policy support or policy authoring. Local mocks do not prove account-level interoperability.

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L "https://api.ui.com/v1/sd-wan-configs" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [List SD-WAN Configs](https://developer.ui.com/site-manager/v1.0.0/listsdwanconfigs)

***

### Get SD-WAN Config by ID

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/sd-wan-configs/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get SD-WAN Config by ID](https://developer.ui.com/site-manager/v1.0.0/getsdwanconfigbyid)

***

### Get SD-WAN Config Status

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/sd-wan-configs/{id}/status" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get SD-WAN Config Status](https://developer.ui.com/site-manager/v1.0.0/getsdwanconfigstatus)

***

### Adopt Devices

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/network/integration/v1/sites/{siteId}/devices" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"macAddress\": \"string\",  \"ignoreDeviceLimit\": true}"
```

**Reference:** [Adopt Devices](https://developer.ui.com/network/v10.6.106/adoptdevice)

***

### List DPI Application Categories

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/network/integration/v1/dpi/categories?offset={offset}&limit={limit}&filter={filter}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [List DPI Application Categories](https://developer.ui.com/network/v10.6.106/getdpiapplicationcategories)

***

### Quick Start

* **Method:** `GET`
* **Endpoint:** `register`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
pip install httpx urllib3
```

**Reference:** [Quick Start](https://developer.ui.com/network/v10.6.106/quick_start)

***

### Get application information

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/meta/info" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get application information](https://developer.ui.com/protect/v7.3.68/get-v1metainfo)

***

### Get viewer details

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/viewers/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get viewer details](https://developer.ui.com/protect/v7.3.68/get-v1viewersid)

***

### Patch viewer settings

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/viewers/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"string\",  \"liveview\": \"string\"}"
```

**Reference:** [Patch viewer settings](https://developer.ui.com/protect/v7.3.68/patch-v1viewersid)

***

### Get all viewers

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/viewers" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get all viewers](https://developer.ui.com/protect/v7.3.68/get-v1viewers)

***

### Get live view details

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/liveviews/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get live view details](https://developer.ui.com/protect/v7.3.68/get-v1liveviewsid)

***

### Patch live view configuration

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/liveviews/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"id\": \"string\",  \"modelKey\": \"string\",  \"name\": \"string\",  \"isDefault\": true,  \"isGlobal\": true,  \"owner\": \"string\",  \"layout\": 0,  \"slots\": [    {      \"cameras\": [        \"string\"      ],      \"cycleMode\": \"motion\",      \"cycleInterval\": 0    }  ]}"
```

**Reference:** [Patch live view configuration](https://developer.ui.com/protect/v7.3.68/patch-v1liveviewsid)

***

### Get all live views

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/liveviews" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get all live views](https://developer.ui.com/protect/v7.3.68/get-v1liveviews)

***

### Create live view

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/liveviews" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"id\": \"string\",  \"modelKey\": \"string\",  \"name\": \"string\",  \"isDefault\": true,  \"isGlobal\": true,  \"owner\": \"string\",  \"layout\": 0,  \"slots\": [    {      \"cameras\": [        \"string\"      ],      \"cycleMode\": \"motion\",      \"cycleInterval\": 0    }  ]}"
```

**Reference:** [Create live view](https://developer.ui.com/protect/v7.3.68/post-v1liveviews)

***

### Get update messages about devices

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/subscribe/devices" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get update messages about devices](https://developer.ui.com/protect/v7.3.68/get-v1subscribedevices)

***

### Get Protect event messages

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/subscribe/events" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get Protect event messages](https://developer.ui.com/protect/v7.3.68/get-v1subscribeevents)

***

### Start a camera PTZ patrol

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X POST "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/ptz/patrol/start/{slot}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Start a camera PTZ patrol](https://developer.ui.com/protect/v7.3.68/post-v1camerasidptzpatrolstartslot)

***

### Stop active camera PTZ patrol

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X POST "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/ptz/patrol/stop" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Stop active camera PTZ patrol](https://developer.ui.com/protect/v7.3.68/post-v1camerasidptzpatrolstop)

***

### Move PTZ camera to preset

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X POST "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/ptz/goto/{slot}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Move PTZ camera to preset](https://developer.ui.com/protect/v7.3.68/post-v1camerasidptzgotoslot)

***

### Send a webhook to the alarm manager

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X POST "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/alarm-manager/webhook/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Send a webhook to the alarm manager](https://developer.ui.com/protect/v7.3.68/post-v1alarm-managerwebhookid)

***

### Get light details

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/lights/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get light details](https://developer.ui.com/protect/v7.3.68/get-v1lightsid)

***

### Patch light settings

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/lights/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"string\",  \"isLightForceEnabled\": true,  \"lightModeSettings\": {    \"mode\": \"string\",    \"enableAt\": \"string\"  },  \"lightDeviceSettings\": {    \"isIndicatorEnabled\": true,    \"pirDuration\": 0,    \"pirSensitivity\": 0,    \"ledLevel\": 0  }}"
```

**Reference:** [Patch light settings](https://developer.ui.com/protect/v7.3.68/patch-v1lightsid)

***

### Get all lights

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/lights" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get all lights](https://developer.ui.com/protect/v7.3.68/get-v1lights)

***

### Get camera details

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get camera details](https://developer.ui.com/protect/v7.3.68/get-v1camerasid)

***

### Patch camera settings

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"string\",  \"osdSettings\": {    \"isNameEnabled\": true,    \"isDateEnabled\": true,    \"isLogoEnabled\": true,    \"isDebugEnabled\": true,    \"overlayLocation\": \"topLeft\"  },  \"ledSettings\": {    \"isEnabled\": true,    \"welcomeLed\": true,    \"floodLed\": true  },  \"lcdMessage\": {    \"type\": \"string\"  },  \"videoMode\": \"default\",  \"smartDetectSettings\": {    \"objectTypes\": [      \"person\"    ],    \"audioTypes\": [      \"alrmSmoke\"    ]  }}"
```

**Reference:** [Patch camera settings](https://developer.ui.com/protect/v7.3.68/patch-v1camerasid)

***

### Get all cameras

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get all cameras](https://developer.ui.com/protect/v7.3.68/get-v1cameras)

***

### Create RTSPS streams for camera

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/rtsps-stream" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"qualities\": [    \"high\"  ]}"
```

**Reference:** [Create RTSPS streams for camera](https://developer.ui.com/protect/v7.3.68/post-v1camerasidrtsps-stream)

***

### Delete camera RTSPS stream

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X DELETE "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/rtsps-stream?qualities={qualities}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Delete camera RTSPS stream](https://developer.ui.com/protect/v7.3.68/delete-v1camerasidrtsps-stream)

***

### Get RTSPS streams for camera

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/rtsps-stream" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get RTSPS streams for camera](https://developer.ui.com/protect/v7.3.68/get-v1camerasidrtsps-stream)

***

### Get camera snapshot

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/snapshot?highQuality={highQuality}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get camera snapshot](https://developer.ui.com/protect/v7.3.68/get-v1camerasidsnapshot)

***

### Permanently disable camera microphone

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X POST "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/disable-mic-permanently" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Permanently disable camera microphone](https://developer.ui.com/protect/v7.3.68/post-v1camerasiddisable-mic-permanently)

***

### Create talkback session for camera

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X POST "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/cameras/{id}/talkback-session" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Create talkback session for camera](https://developer.ui.com/protect/v7.3.68/post-v1camerasidtalkback-session)

***

### Get sensor details

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/sensors/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get sensor details](https://developer.ui.com/protect/v7.3.68/get-v1sensorsid)

***

### Patch sensor settings

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/sensors/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"string\",  \"lightSettings\": {    \"isEnabled\": true,    \"margin\": 0  },  \"humiditySettings\": {    \"isEnabled\": true,    \"margin\": 0  },  \"temperatureSettings\": {    \"isEnabled\": true,    \"margin\": 0  },  \"motionSettings\": {    \"isEnabled\": true,    \"sensitivity\": 0  },  \"alarmSettings\": {    \"isEnabled\": true  }}"
```

**Reference:** [Patch sensor settings](https://developer.ui.com/protect/v7.3.68/patch-v1sensorsid)

***

### Get all sensors

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/sensors" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get all sensors](https://developer.ui.com/protect/v7.3.68/get-v1sensors)

***

### Get NVR details

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/nvrs" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get NVR details](https://developer.ui.com/protect/v7.3.68/get-v1nvrs)

***

### Upload device asset file

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X POST "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/files/{fileType}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Upload device asset file](https://developer.ui.com/protect/v7.3.68/post-v1filesfiletype)

***

### Get device asset files

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/files/{fileType}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get device asset files](https://developer.ui.com/protect/v7.3.68/get-v1filesfiletype)

***

### Get chime details

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/chimes/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get chime details](https://developer.ui.com/protect/v7.3.68/get-v1chimesid)

***

### Patch chime settings

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g -X PATCH "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/chimes/{id}" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>" \-H "Content-Type: application/json" \-d "{  \"name\": \"string\",  \"cameraIds\": [    \"string\"  ],  \"ringSettings\": [    {      \"cameraId\": \"string\",      \"repeatTimes\": 0,      \"ringtoneId\": \"string\",      \"volume\": 0    }  ]}"
```

**Reference:** [Patch chime settings](https://developer.ui.com/protect/v7.3.68/patch-v1chimesid)

***

### Get all chimes

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
curl -L -g "https://api.ui.com/v1/connector/consoles/{consoleId}/proxy/protect/integration/v1/chimes" \-H "Accept: application/json" \-H "X-API-Key: <X-API-Key>"
```

**Reference:** [Get all chimes](https://developer.ui.com/protect/v7.3.68/get-v1chimes)

***

### Quick Start

* **Method:** `GET`
* **Endpoint:** `register`

Endpoints combined into Ansible Modules for customized workflows.

**Example:**

```json theme={null}
pip install httpx urllib3
```

**Reference:** [Quick Start](https://developer.ui.com/protect/v7.3.68/quick_start)

***

### Protect v7.3.68 — implemented (Phase 5a, 2026-09-27)

> Verified against the canonical spec snapshot `scripts/protect-api-spec-v7.3.68.json` (audit 2026-09-26). These 39 operations shipped in Protect v7 and are now implemented as MCP tools across 10 modules (sirens, alarm/arm-profiles, speakers, fobs, relays, bridges, link stations, alarm hubs, users, POS). **Mock-tested only — verify against live Protect hardware before relying on write paths** (same caveat as the F1–F3 Integration API findings: mocked tests assert the code's assumptions, not controller behavior). All writes require `confirm=True` and support `dry_run`.

**Arm profiles / alarm control (7)**

* `GET /v1/arm-profiles` — list arm profiles
* `POST /v1/arm-profiles` — create arm profile
* `PATCH /v1/arm-profiles/{id}` — update arm profile
* `DELETE /v1/arm-profiles/{id}` — delete arm profile
* `PATCH /v1/arm-profiles/settings` — set current arm profile
* `POST /v1/arm-profiles/enable` — enable alarm
* `POST /v1/arm-profiles/disable` — disable alarm

**Sirens (6)**

* `GET /v1/sirens`, `GET /v1/sirens/{id}` — list / details
* `PATCH /v1/sirens/{id}` — update settings
* `POST /v1/sirens/{id}/play`, `POST /v1/sirens/{id}/stop` — control
* `POST /v1/sirens/{id}/test-sound`

**Speakers (4)**

* `GET /v1/speakers`, `GET /v1/speakers/{id}`, `PATCH /v1/speakers/{id}`
* `POST /v1/speakers/{id}/test-sound`

**Fobs (3)** — `GET /v1/fobs`, `GET /v1/fobs/{id}`, `PATCH /v1/fobs/{id}`

**Relays (4)**

* `GET /v1/relays`, `GET /v1/relays/{id}`, `PATCH /v1/relays/{id}`
* `POST /v1/relays/{id}/outputs/{outputId}/activate`

**Bridges (3)** — `GET /v1/bridges`, `GET /v1/bridges/{id}`, `PATCH /v1/bridges/{id}`

**Link stations (3)** — `GET /v1/link-stations`, `GET /v1/link-stations/{id}`, `PATCH /v1/link-stations/{id}`

**Alarm hubs (4)**

* `GET /v1/alarm-hubs`, `GET /v1/alarm-hubs/{id}`, `PATCH /v1/alarm-hubs/{id}`
* `POST /v1/alarm-hubs/{id}/outputs/{outputId}/trigger`

**Users (4)**

* `GET /v1/users`, `GET /v1/users/{id}` — Protect users
* `GET /v1/ulp-users`, `GET /v1/ulp-users/{id}` — UniFi Identity users

**Point of sale (1)**

* `POST /v1/pos/cameras/{id}/transactions` — ingest POS transaction

All proxy through the Cloud Connector under `/v1/connector/consoles/{consoleId}/proxy/protect/integration`. Write operations (arm profile CRUD, alarm enable/disable, siren/speaker/relay/alarm-hub triggers and patches, POS ingestion) ship behind `UNIFI_READ_ONLY` (mutating tools are not registered in read-only mode), `confirm=True`, `dry_run` preview, and are covered by mocked unit tests. Tool names map as: `list_protect_arm_profiles` / `get_protect_arm_profile` / `create_protect_arm_profile` / `update_protect_arm_profile` / `delete_protect_arm_profile` / `set_current_protect_arm_profile` / `enable_protect_alarm` / `disable_protect_alarm`, `list_protect_sirens` / `get_protect_siren` / `update_protect_siren` / `play_protect_siren` / `stop_protect_siren` / `test_protect_siren_sound`, `list_protect_speakers` / `get_protect_speaker` / `update_protect_speaker` / `test_protect_speaker_sound`, `list_protect_fobs` / `get_protect_fob` / `update_protect_fob`, `list_protect_relays` / `get_protect_relay` / `update_protect_relay` / `activate_protect_relay_output`, `list_protect_bridges` / `get_protect_bridge` / `update_protect_bridge`, `list_protect_link_stations` / `get_protect_link_station` / `update_protect_link_station`, `list_protect_alarm_hubs` / `get_protect_alarm_hub` / `update_protect_alarm_hub` / `trigger_protect_alarm_hub_output`, `list_protect_users` / `get_protect_user`, `list_protect_ulp_users` / `get_protect_ulp_user`, and `ingest_pos_transaction`.

### Phase 6 — Mobility, InnerSpace, Carrier Fabric (implemented 2026-09-27)

> Verified against the canonical spec snapshots `scripts/mobility-api-spec-v1.0.0.json`,
> `scripts/innerspace-api-spec-v1.3.23.json`, and `scripts/carrier-fabric-api-spec-v1.0.0.json`.
> All 25 operations implemented. **Mock-tested only — verify against live Ubiquiti cloud
> access (Mobility/Carrier require a UniFi API key with cloud scope; InnerSpace requires a
> console with the InnerSpace integration).**

**Mobility v1.0.0 (8)** — cloud API on `api.ui.com/v1/mobility`, same API-key transport as
Site Manager (tools reuse `SiteManagerClient`; require `UNIFI_SITE_MANAGER_ENABLED=true`):

* `GET /v1/mobility/workspaces` → `list_mobility_workspaces`
* `GET /v1/mobility/workspaces/{id}/admins` → `list_mobility_workspace_admins`
* `GET /v1/mobility/workspaces/{id}/devices` (limit 1–200, offset) → `list_mobility_devices`
* `GET /v1/mobility/workspaces/{id}/devices/{id}` → `get_mobility_device`
* `PUT  /v1/mobility/workspaces/{id}/devices/{id}` (name 1–32) → `update_mobility_device`
* `GET /v1/mobility/workspaces/{id}/devices/{id}/clients` → `list_mobility_device_clients`
* `PUT  /v1/mobility/workspaces/{id}/devices/{id}/network` (snake\_case DHCP body:
  `host_address`, `dhcp_mode` dhcp|none, `dhcp_range_start/stop`, `dhcp_lease_time`)
  → `update_mobility_device_network`
* `PUT  /v1/mobility/workspaces/{id}/devices/{id}/wireless` (`ssid`, `password` required)
  → `update_mobility_device_wireless`

**InnerSpace v1.3.23 (6, read-only)** — Cloud Connector proxy
(`/v1/connector/consoles/{consoleId}/proxy/innerspace/integration/...`), `console_id`
parameter per tool (from `list_hosts`), no writes:

* `GET v1/access_points` → `list_innerspace_access_points`
* `GET v1/floor_plans` → `list_innerspace_floor_plans`
* `GET v1/inventory` → `list_innerspace_inventory`
* `GET v1/project` → `get_innerspace_project`
* `GET v1/switches` (optional `siteId` query) → `list_innerspace_switches`
* `GET v1/assets/{planId}/{filename}` → `download_innerspace_asset`

**Carrier Fabric v1.0.0 (11)** — cloud API on `api.ui.com/v1/carrier`, highest blast radius
(subscriber lifecycle); all writes confirm-gated with dry-run:

* `GET /v1/carrier/service-plans` → `list_carrier_service_plans`
* `GET /v1/carrier/service-plans/{id}` → `get_carrier_service_plan`
* `GET /v1/carrier/subscribers` (limit/offset/`planId`/`suspended`) → `list_carrier_subscribers`
* `POST /v1/carrier/subscribers` (`subscriberNumber` required 1–32; optional camelCase
  `name`, `email`, `notes`, `serviceAddress`, `planId`, `hostId`, `metadata`)
  → `create_carrier_subscriber`
* `GET /v1/carrier/subscribers/{id}` → `get_carrier_subscriber`
* `PATCH /v1/carrier/subscribers/{id}` (only provided fields; spec semantics: absent =
  unchanged, explicit null = clears — this tool only sends provided fields)
  → `update_carrier_subscriber`
* `PUT /v1/carrier/subscribers/{id}/host` (`hostId`) → `attach_carrier_subscriber_host`
* `DELETE /v1/carrier/subscribers/{id}/host` → `detach_carrier_subscriber_host`
* `PUT /v1/carrier/subscribers/{id}/plan` (`planId`) → `assign_carrier_subscriber_plan`
* `POST /v1/carrier/subscribers/{id}/resume` → `resume_carrier_subscriber`
* `POST /v1/carrier/subscribers/{id}/suspend` (optional `reason`) → `suspend_carrier_subscriber`

New tool exposure profiles `mobility`, `innerspace`, `carrier` (via `UNIFI_PROFILE`).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.