@aybouzaglou/unifi-client
v0.1.0
Published
Type-safe TypeScript client for the UniFi Site Manager API and UniFi Network API.
Maintainers
Readme
@aybouzaglou/unifi-client
Type-safe TypeScript client for the official UniFi Site Manager API and UniFi Network API.
- Types generated from Ubiquiti's official OpenAPI specs.
- Site Manager and Network APIs in one package.
- Dual ESM/CJS builds with
.d.tsdeclarations. - Platform
fetchby default; optionalundicidispatcher support for self-signed local-console TLS. - Typed error hierarchy with status, code, request id, URL, and retry metadata.
list()for one page,listAll()for async-iterable pagination.
Install
pnpm add @aybouzaglou/unifi-client
# or
npm install @aybouzaglou/unifi-client
# or
yarn add @aybouzaglou/unifi-clientRequires Node >=18.17 or another runtime with global fetch.
For local UniFi consoles with self-signed certificates, install the optional TLS helper dependency and set allowInsecureTLS: true:
pnpm add undiciAPI Keys
| API | Key location |
| --- | --- |
| Site Manager | Sign in at unifi.ui.com, then Settings -> API. |
| Network | Open the Network app on the console, then Settings -> Control Plane -> Integrations. |
Both APIs authenticate with X-API-Key; the client sets the header for you.
Quick Start
import { UnifiClient } from "@aybouzaglou/unifi-client";
const unifi = new UnifiClient({
siteManager: { apiKey: process.env.UNIFI_SM_KEY! },
network: {
host: "192.168.1.1",
apiKey: process.env.UNIFI_NET_KEY!,
allowInsecureTLS: true,
},
});
const { data: hosts } = await unifi.siteManager.hosts.list();
const siteId = await unifi.network.sites.findId("default");
if (!siteId) throw new Error("Default site not found");
const clients = await unifi.network.clients.listAll(siteId).collect(100);
console.log(hosts, clients);Standalone imports are available when you only need one API:
import { SiteManagerClient } from "@aybouzaglou/unifi-client/site-manager";
import { NetworkClient } from "@aybouzaglou/unifi-client/network";Pagination
Every list endpoint has two shapes:
list(...)returns one page.listAll(...)returns aPaginator<T>.
const page = await unifi.network.clients.list(siteId, { limit: 50 });
console.log(page.data, page.totalCount);
const all = unifi.network.clients.listAll(siteId);
for await (const client of all) {
console.log(client.id);
}
for await (const pageItems of unifi.network.clients.listAll(siteId).pages()) {
console.log(pageItems.length);
}
const first200 = await unifi.network.clients.listAll(siteId).collect(200);
const first = await unifi.network.clients.listAll(siteId).first();Errors
All client errors extend UnifiError.
| Class | When |
| --- | --- |
| UnifiAuthError | HTTP 401 or 403 |
| UnifiNotFoundError | HTTP 404 |
| UnifiValidationError | HTTP 400 or 422 |
| UnifiConflictError | HTTP 409 |
| UnifiRateLimitError | HTTP 429, with retryAfterMs |
| UnifiServerError | HTTP 5xx |
| UnifiConnectionError | Transport failure |
| UnifiTimeoutError | Request timeout |
| UnifiConfigError | Client misconfiguration |
import {
UnifiAuthError,
UnifiRateLimitError,
isUnifiError,
} from "@aybouzaglou/unifi-client";
try {
await unifi.network.devices.list(siteId);
} catch (err) {
if (err instanceof UnifiRateLimitError) {
await new Promise((resolve) => setTimeout(resolve, err.retryAfterMs ?? 1000));
} else if (err instanceof UnifiAuthError) {
console.error("Bad or expired API key");
} else if (isUnifiError(err)) {
console.error(`UniFi error ${err.status} (${err.code ?? "unknown"}): ${err.url}`);
} else {
throw err;
}
}Local Network TLS
Local UniFi consoles commonly serve the Network integration API over HTTPS with a self-signed certificate. Node rejects that certificate by default.
import { NetworkClient } from "@aybouzaglou/unifi-client/network";
const net = new NetworkClient({
host: "192.168.1.1",
apiKey: process.env.UNIFI_NET_KEY!,
allowInsecureTLS: true,
});Only use allowInsecureTLS for consoles you control on trusted networks. For a stricter setup, pass your own undici dispatcher or custom fetch implementation with pinned trust.
import { Agent } from "undici";
import { NetworkClient } from "@aybouzaglou/unifi-client/network";
const dispatcher = new Agent({
connect: { ca: myConsoleCaPem },
});
const net = new NetworkClient({
host: "unifi.example.com",
apiKey: process.env.UNIFI_NET_KEY!,
dispatcher,
});Cloud Connector Proxy
When you do not have a LAN path to a console, route Network API calls through UniFi's Cloud Connector Proxy:
import { UnifiClient } from "@aybouzaglou/unifi-client";
const unifi = new UnifiClient({
siteManager: { apiKey: process.env.UNIFI_CLOUD_KEY! },
});
const { data: hosts } = await unifi.siteManager.hosts.list();
const remote = unifi.connector(hosts[0]!.id!);
const siteId = await remote.sites.findId("default");
if (!siteId) throw new Error("Default site not found");
const clients = await remote.clients.listAll(siteId).collect(100);Connector Proxy mode uses your Site Manager key, not a per-console Network key. The target console must support UniFi's connector proxy route.
Per-request Options
Most methods accept a final options object:
await unifi.network.devices.list(
siteId,
{ limit: 100 },
{
signal: controller.signal,
timeoutMs: 5_000,
headers: { "X-Trace": "abc" },
maxRetries: 2,
},
);Retries apply to transient transport errors, timeouts, HTTP 429, and HTTP 5xx responses. Retry-After is honored when the server sends it.
API Surface
See API-SURFACE.md for the method map. The generated OpenAPI types are exported as:
import type {
NetworkOperations,
SiteManagerOperations,
} from "@aybouzaglou/unifi-client";Versioned Specs
The bundled specs in openapi/ are the source for generated types:
- Site Manager API
v1.0.0 - Network API
v10.3.58
Regenerate types after replacing either JSON file:
pnpm run generateDevelopment
pnpm install
pnpm run verify
npm pack --dry-runpnpm run verify runs typecheck, example typecheck, tests, coverage, and build.
