Based on analysis of API response examples, here are features that could be added.
Status key: Done = shipped, Partial = some coverage, Open = not started.
Status: Done (sysinfo.go)
Status: Open
Data: WAN interface names, states (ACTIVE/BACKUP), network groups (WAN, WAN2).
Use case: WAN failover monitoring.
Implementation: GetWANStatus(site *Site) (*WANStatus, error)
Status: Done (firewall_policies.go)
Status: Partial (PDU/UPS come from /stat/device; this endpoint is a lightweight selector format)
Data: Device MAC, image URL, label, site ID — for UI selection lists, not full stats.
Implementation: GetUPSDeviceList(site *Site) ([]*UPSDeviceSelector, error)
Status: Partial (basic Network struct exists; many fields missing)
Missing fields: WAN failover (wan_load_balance_type, wan_failover_priority), IPv6 (ipv6_enabled, dhcpdv6_*), VPN (vpn_type, sdwan_remote_site_id), DHCP advanced (dhcpd_ntp_enabled, dhcpd_wins_enabled), misc (firewall_zone_id, mdns_enabled) — domain_name is already present as DomainName.
Implementation: Extend Network struct in-place (additive fields, no breakage).
Status: Open
Data: Port forward rules — source/destination ports, protocols, enabled flag.
Implementation: GetPortForwards(site *Site) ([]*PortForward, error)
Status: Open
Data: Certificate chain, status, valid-from/to dates, issuer, fingerprint.
Use case: Certificate expiration monitoring.
Implementation: GetSSLCertificate(site *Site) (*SSLCertificate, error)
The controller exposes a formally supported REST API at /proxy/network/integration/v1/ (available since Network 9.3.43, spec at /proxy/network/api-docs/integration.json). It requires X-API-Key auth and uses UUID site IDs (not the legacy short name "default"). The library currently reads from none of these endpoints.
This API has 44 paths (source: /proxy/network/api-docs/integration.json on 10.3.58). Of those, 36 are GET operations; the remainder are write-only (POST/PUT/DELETE/PATCH). The 36 GETs collapse into 17 features (B0–B16) because list and single-item endpoints for the same resource are grouped together. Write operations are excluded — the library is read-only by design.
Status: Open
Problem: Integration/v1 per-site endpoints use a UUID siteId from GET /v1/sites, not the legacy Site.Name short name. These are different identifiers.
Solution: New type and getter:
// IntegrationSite holds identity fields from GET /v1/sites.
// InternalReference matches legacy Site.Name for cross-lookup.
type IntegrationSite struct {
ID string `json:"id"` // UUID — pass to all integration/v1 calls
InternalReference string `json:"internalReference"` // equals legacy Site.Name ("default")
Name string `json:"name"`
}
func (u *Unifi) GetIntegrationSites() ([]*IntegrationSite, error)Callers who already have []*Site from GetSites() join on site.Name == integrationSite.InternalReference to get the UUID. All per-site integration/v1 getters take *IntegrationSite.
Files: new integration_sites.go; path constant APIIntegrationSitesPath in types.go; add to UnifiClient interface; add to mocks/.
Status: Open
Data: uptimeSec, cpuUtilizationPct, memoryUtilizationPct, loadAverage{1,5,15}Min, lastHeartbeatAt, nextHeartbeatAt, per-radio txRetriesPct/frequencyGHz, per-uplink txRateBps/rxRateBps.
Use case: Per-device CPU/memory/uptime metrics — currently only available embedded in the large legacy device payload. This is a clean dedicated stats endpoint.
Implementation:
GetIntegrationDeviceStats(site *IntegrationSite, deviceID string) (*IntegrationDeviceStats, error)
// Convenience bulk getter: enumerates device IDs via GET /v1/sites/{siteId}/devices first.
GetAllIntegrationDeviceStats(site *IntegrationSite) ([]*IntegrationDeviceStats, error)Files: integration_devices.go
Status: Open
Data: id, name, enabled, network (VLAN reference), securityConfiguration (type: WPA2/WPA3/open, PSK, RADIUS profile ref), broadcastingDeviceFilter. Single-broadcast getter at /{wifiBroadcastId}.
Use case: SSID inventory — the library has no WiFi broadcast / SSID data today.
Implementation: GetWifiBroadcasts(site *IntegrationSite) ([]*WifiBroadcast, error)
Files: wifi_broadcasts.go
Status: Open
Data: id, name, networkIds (list of network UUIDs in the zone), metadata (origin: system/user).
Use case: The existing GetFirewallPolicies() returns policies that reference zone IDs — without zone data, those IDs are opaque. This completes the firewall picture.
Implementation: GetFirewallZones(site *IntegrationSite) ([]*FirewallZone, error)
Files: firewall_zones.go
Status: Open
Data: id, enabled, name, description, action (ALLOW/BLOCK), enforcingDeviceFilter, index, sourceFilter. Single-rule getter at /{aclRuleId}. Ordering at /ordering.
Use case: Network access-control visibility; currently no ACL data in the library.
Implementation: GetACLRules(site *IntegrationSite) ([]*ACLRule, error)
Files: acl_rules.go
Status: Open
Data: id, name, enabled, vlanId, management (gateway/switch-managed/unmanaged), dhcpGuarding. More structured than the legacy /rest/networkconf response. Single-network getter at /{networkId}; references at /{networkId}/references.
Use case: Clean network inventory; complements the legacy GetNetworks() which remains for backward compat.
Implementation: GetIntegrationNetworks(site *IntegrationSite) ([]*IntegrationNetwork, error)
Files: integration_networks.go
Status: Open
Data: id, name. Lightweight list of WAN interface identifiers.
Use case: Enumerate WAN interfaces to drive the existing v2 WAN enriched/SLA calls by interface ID.
Implementation: GetIntegrationWANs(site *IntegrationSite) ([]*IntegrationWAN, error)
Files: extend wan.go or new integration_wans.go
Status: Open
Data:
GET /v1/sites/{siteId}/vpn/servers→id,name,enabled,type(L2TP/OpenVPN/WireGuard/UID)GET /v1/sites/{siteId}/vpn/site-to-site-tunnels→id,name,type(IPSec/OpenVPN/WireGuard),metadata
Use case: VPN infrastructure visibility; complements the existing GetMagicSiteToSiteVPN() (v2 API).
Implementation:
GetVPNServers(site *IntegrationSite) ([]*VPNServer, error)
GetSiteToSiteTunnels(site *IntegrationSite) ([]*SiteToSiteTunnel, error)Files: vpn_servers.go (or extend vpn.go)
Status: Open
Data:
GET /v1/sites/{siteId}/switching/lags→id,type(local/global),members(device ID + port indexes),metadataGET /v1/sites/{siteId}/switching/mc-lag-domains→id,name,peers(role + device ID + link ports),lags,metadataGET /v1/sites/{siteId}/switching/switch-stacks→id,name,members(device IDs),lags,metadata
Use case: Switching topology not available via any current endpoint. Required for understanding LAG/MLAG/stack relationships between switches.
Implementation:
GetLAGs(site *IntegrationSite) ([]*LAG, error)
GetMCLAGDomains(site *IntegrationSite) ([]*MCLAGDomain, error)
GetSwitchStacks(site *IntegrationSite) ([]*SwitchStack, error)Files: switching.go
Status: Open
Data: id, enabled, type (forward-domain/block/allow/etc.), domain. Single-policy getter at /{dnsPolicyId}.
Use case: DNS filtering / split-horizon visibility.
Implementation: GetDNSPolicies(site *IntegrationSite) ([]*DNSPolicy, error)
Files: dns_policies.go
Status: Open
Data: id, name, metadata. Reference data used by WiFi enterprise security configs.
Implementation: GetRADIUSProfiles(site *IntegrationSite) ([]*RADIUSProfile, error)
Files: radius_profiles.go
Status: Open
Data: id, name, type (IPv4/IPv6/port). Used as references in firewall policy traffic filters.
Implementation: GetTrafficMatchingLists(site *IntegrationSite) ([]*TrafficMatchingList, error)
Files: traffic_matching_lists.go
Status: Open
Data: id, code, name, authorizedGuestLimit, authorizedGuestCount, activatedAt, expiresAt, timeLimitMinutes, dataUsageLimitMBytes, rate limits.
Use case: Guest portal monitoring — voucher usage, expiry, capacity.
Implementation: GetHotspotVouchers(site *IntegrationSite) ([]*HotspotVoucher, error)
Files: hotspot_vouchers.go
Status: Open
Data: id, name for each application and category. Reference tables that decode the integer IDs in existing DPI stat responses.
Implementation:
GetDPIApplications() ([]*DPIApplication, error)
GetDPICategories() ([]*DPICategory, error)Files: extend dpi.go
Status: Open
Data: macAddress, ipAddress, model, state, supported, firmwareVersion, firmwareUpdatable, features.
Use case: Adoption queue monitoring — see what devices are waiting to be adopted.
Implementation: GetPendingDevices() ([]*PendingDevice, error)
Files: extend devices.go or new pending_devices.go
Status: Open
Data: applicationVersion string.
Use case: Lightweight version check; complements GetServerData() which populates ServerStatus, after which u.ServerStatus.MajorVersion() returns the numeric major version (promoted to u.MajorVersion() via embedding, but requires GetServerData() to have been called first).
Implementation: GetIntegrationInfo() (*IntegrationInfo, error)
Files: integration_sites.go (same file as B0, trivially small)
Status: Open
Data: code, name per country.
Use case: Reference data for geo-based firewall policy filters (region filter). Low priority.
Implementation: GetCountries() ([]*Country, error)
Files: countries.go
- B0 —
GetIntegrationSites()+IntegrationSitetype
- B1 — Device statistics (CPU/mem/uptime)
- B2 — WiFi broadcasts (SSID inventory)
- B3 — Firewall zones (completes firewall policy context)
- B4 — ACL rules
- B5 — Networks (integration/v1)
- B6 — WAN interfaces
- B7 — VPN servers + site-to-site tunnels
- B8 — Switching topology (LAGs, MC-LAGs, stacks)
- B9 — DNS policies
- B10 — RADIUS profiles
- B11 — Traffic matching lists
- B12 — Hotspot vouchers
- B13 — DPI app/category catalogue
- B14 — Pending devices
- B15 — Application info
- B16 — Countries
- Auth: Integration/v1 requires
X-API-Key— cookie auth returns 401. Every B-phase getter must guard with an early return whenu.APIKey == ""(a new sentinelErrAPIKeyRequiredshould be added). ThesetHeadershelper already sends the key when present; no transport changes needed. - Pagination: Integration/v1 list responses use
{offset, limit, count, totalCount, data}— a different envelope from the legacy{meta, data}thatGetDatais shaped for. Paginated getters must useGetJSON+ a shared integration-pagination helper that loops untiloffset+count >= totalCount, rather thanGetData. - Global vs. per-site: Endpoints without a
{siteId}segment (B13–B16) take no site parameter. Don't add*IntegrationSiteto these getters. - Path constants: All integration/v1 path constants go in
types.gounder a new// Integration/v1 API pathscomment block, following the same naming convention (APIIntegration*Path). - Interface: Every new getter must be added to
UnifiClientintypes.goand implemented inmocks/. - Write operations excluded: POST/PUT/DELETE/PATCH are out of scope — the library is read-only by design.
- Availability gate: Integration/v1 requires Network 9.3.43+. Callers should check
u.ServerStatus.MajorVersion() >= 9(afterGetServerData()) before calling integration/v1 getters, or handleErrEndpointNotFoundgracefully if the endpoint is absent on older controllers.