// Test script to probe UniFi API endpoints for response shapes import axios, { AxiosInstance } from "axios"; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; const controllerBaseUrl = "https://unifi.totaltech.net"; const site = "km9b1v8i"; const username = "admin"; const password = "Tt$Un1fiIZth3B3$t26"; class TestClient { private client: AxiosInstance; constructor(baseURL: string) { this.client = axios.create({ baseURL, validateStatus: (s) => s >= 200 && s < 400, }); } private persistSession(res: { headers: Record }): void { const raw = res.headers["set-cookie"]; if (raw) { const cookies = (Array.isArray(raw) ? raw : [raw]) as string[]; const cookieString = cookies.map((c) => c.split(";")[0]).join("; "); this.client.defaults.headers.common["Cookie"] = cookieString; } const csrf = res.headers["x-csrf-token"]; if (typeof csrf === "string") { this.client.defaults.headers.common["X-CSRF-Token"] = csrf; } } async login(): Promise { try { const res = await this.client.post("/api/auth/login", { username, password, }); console.log("Login OK (UniFi OS)", res.status); this.persistSession(res); } catch (e) { const res = await this.client.post("/api/login", { username, password }); console.log("Login OK (legacy)", res.status); this.persistSession(res); } } async tryGet(label: string, paths: string[]): Promise { for (const path of paths) { try { const res = await this.client.get(path); const data = res.data?.data ?? res.data; console.log(`\n=== ${label} (${path}) ===`); console.log(JSON.stringify(data, null, 2)); return data; } catch (e: any) { console.log(` Failed ${path}: ${e.response?.status ?? e.message}`); } } console.log(` Could not fetch ${label} from any path`); return null; } } async function main() { const client = new TestClient(controllerBaseUrl); await client.login(); // 1. WLAN Groups (AP groups in UniFi) await client.tryGet("WLAN Groups", [ `/proxy/network/api/s/${site}/rest/wlangroup`, `/api/s/${site}/rest/wlangroup`, ]); // 2. User Groups (bandwidth/speed limit profiles) await client.tryGet("User Groups (Speed Profiles)", [ `/proxy/network/api/s/${site}/rest/usergroup`, `/api/s/${site}/rest/usergroup`, ]); // 3. Devices - APs only (compact) const devices = await client.tryGet("Devices", [ `/proxy/network/api/s/${site}/stat/device`, ]); if (devices) { const aps = devices.filter((d: any) => d.type === "uap"); console.log(`\n=== APs (${aps.length}) - compact ===`); aps.forEach((ap: any) => { console.log( JSON.stringify({ _id: ap._id, name: ap.name, mac: ap.mac, model: ap.model, radio_table: ap.radio_table?.map((r: any) => ({ radio: r.radio, name: r.name, })), wlangroup_id_ng: ap.wlangroup_id_ng, wlangroup_id_na: ap.wlangroup_id_na, vap_table_count: ap.vap_table?.length, }), ); }); } // 4. One full WLAN to see private_preshared_keys structure const wlans = await client.tryGet("WLANs", [ `/proxy/network/api/s/${site}/rest/wlanconf`, ]); if (wlans) { // Log just the PPSK-related fields from each WLAN console.log("\n=== PPSK fields per WLAN ==="); wlans.forEach((w: any) => { console.log( JSON.stringify({ name: w.name, _id: w._id, private_preshared_keys_enabled: w.private_preshared_keys_enabled, private_preshared_keys: w.private_preshared_keys, ap_group_ids: w.ap_group_ids, ap_group_mode: w.ap_group_mode, wlan_band: w.wlan_band, wlan_bands: w.wlan_bands, usergroup_id: w.usergroup_id, }), ); }); } } main().catch((e) => console.error(e));