TypeScript SDK
The @novavms/sdk package is a thin, typed wrapper over the NovaVMS REST API (v1). It targets Node.js 20+ and modern browsers. Types are generated from the OpenAPI spec — changes in the API surface show up as TypeScript errors at compile time.
Install
npm install @novavms/sdkSince v1.0. Requires TypeScript 5.0 or later if you consume the type definitions.
Initialize
import { createClient } from '@novavms/sdk';
const client = createClient({ apiKey: 'sk_live_abc123def456', baseUrl: 'https://api.novavms.io',});The apiKey is an org-scoped API key issued from the Admin console. Never ship it in browser bundles — use a server-side proxy instead.
Client options
| Option | Type | Default | Since | Description |
|---|---|---|---|---|
apiKey | string | — | v1.0 | Org-scoped API key. Required. |
baseUrl | string | https://api.novavms.io | v1.0 | Override for self-hosted deployments. |
timeoutMs | number | 10000 | v1.0 | Per-request timeout in milliseconds. |
maxRetries | number | 3 | v1.0 | Retries on 429 and 5xx with exponential backoff. |
fetch | typeof fetch | global fetch | v1.0 | Inject a custom fetch (for proxies, logging). |
userAgent | string | @novavms/sdk/<version> | v1.0 | Appended to the default User-Agent. |
Available methods
The client exposes one namespace per top-level resource:
| Namespace | Purpose |
|---|---|
client.cameras | List, get, create, update, delete cameras; fetch snapshots and live-view tokens. |
client.events | Query the event feed, fetch a single event, acknowledge, star, add notes. |
client.alerts | List alert history, acknowledge alerts, change status. |
client.rules | Create, read, update, delete alert rules; enable/disable. |
client.sites | Create, read, update, delete sites; manage site-scoped user access. |
client.users | Invite users, list members, change roles, revoke sessions. |
client.webhooks | Create, list, update, delete webhook definitions; test delivery. Secret rotation requires the Admin role. |
Each namespace exposes the same five-verb shape: list, get, create, update, remove, plus resource-specific verbs (for example cameras.trigger(), events.acknowledge()).
const { data: cameras } = await client.cameras.list({ siteId: '8f2b3a71-0c4e-4b5f-9d1a-2e7c3a4b5d6f' });const event = await client.events.get('3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f');await client.rules.update('9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d', { enabled: false });Error types
All errors inherit from NovaVMSError. Catch the base class for a catch-all or narrow to the subclass you care about.
| Class | Thrown when | Since |
|---|---|---|
NovaVMSError | Any API error. Includes status, code, requestId. | v1.0 |
AuthError | 401 or 403 — invalid key or missing scope. | v1.0 |
RateLimitError | 429 — exposes retryAfterMs. | v1.0 |
ValidationError | 400 — fieldErrors lists per-field messages. | v1.0 |
NotFoundError | 404 — resource does not exist in this org. | v1.0 |
import { RateLimitError, AuthError, NovaVMSError } from '@novavms/sdk';
try { await client.cameras.list();} catch (err) { if (err instanceof RateLimitError) { await new Promise((r) => setTimeout(r, err.retryAfterMs)); } else if (err instanceof AuthError) { throw new Error('API key is invalid or revoked'); } else if (err instanceof NovaVMSError) { console.error('NovaVMS API error', err.requestId, err.code, err.message); } else { throw err; }}Typed responses
Every response object is fully typed. The type definitions are generated from the OpenAPI spec shipped at /api/v1/openapi.yaml, so an SDK version always matches an API version — no hand-written types drift.
import type { Camera, Event, AlertRule } from '@novavms/sdk';
function render(camera: Camera): string { return `${camera.name} (${camera.status})`;}For the full list of types, see /developer/api/.
Pagination
List endpoints use opaque cursors. Two patterns:
Manual page-by-page
let cursor: string | undefined = undefined;do { const page = await client.events.list({ cursor, limit: 100 }); for (const event of page.data) { process(event); } cursor = page.nextCursor;} while (cursor);Auto-iteration helper
for await (const event of client.events.iterate({ limit: 100 })) { process(event);}iterate() fetches the next page only when the current one is exhausted. It stops when nextCursor is null. Since v1.0.
Related
- Make your first SDK call — end-to-end tutorial
- API keys — how to issue and scope keys (Admin role)
- Rate limits — per-key and per-org ceilings