Node.js SDK¶
@raclip/sdk is the official Node.js SDK. It's a thin, typed wrapper around the HTTP API — every SDK call corresponds to a documented endpoint.
Install¶
Requires Node.js 18+. No runtime dependencies — uses the built-in fetch API.
Authenticate¶
Pass an API key explicitly, or set RACLIP_API_KEY in your environment:
import { Client } from '@raclip/sdk'
// Reads RACLIP_API_KEY from the environment
const client = new Client()
// Or pass explicitly
const client = new Client({ apiKey: 'raclip_prod_…' })
The SDK never sends your org_id on the wire — the gateway derives it from the key.
Quickstart¶
import { Client } from '@raclip/sdk'
const client = new Client()
const devices = await client.devices.list()
console.log(`${devices.total} devices in this org`)
for (const device of devices.devices) {
console.log(device.device_id, device.status, device.last_seen)
}
if (devices.devices.length > 0) {
const deviceId = devices.devices[0].device_id
const calls = await client.calls.list(deviceId, { per_page: 5 })
for (const call of calls.calls) {
console.log(call.call_id, call.duration_seconds, 'sec')
console.log(' download:', call.download_url)
}
}
The client supports Symbol.asyncDispose — use await using in environments with TypeScript 5.2+:
Download a recording¶
download_url on a call response is a short-lived URL. You can fetch it with anything that speaks HTTP:
Or use the SDK's streaming helper, which avoids leaking your Authorization header on the redirect:
dest accepts a file path (string) or any Node.js Writable stream.
Error handling¶
Every non-2xx response converts to a typed error so you can catch the cases you care about:
import {
Client,
AuthenticationError,
NotFoundError,
RateLimitError,
} from '@raclip/sdk'
const client = new Client()
try {
const call = await client.calls.get('device-id', 'call-id')
} catch (err) {
if (err instanceof NotFoundError) {
console.log('call is gone')
} else if (err instanceof RateLimitError) {
console.log(`slow down; retry after ${err.retryAfter}s`)
} else if (err instanceof AuthenticationError) {
console.log('check your API key')
}
}
Hierarchy: RaclipError → AuthenticationError, PermissionError, NotFoundError, ValidationError, RateLimitError, APIError, APIConnectionError.
Client¶
Client is the entry point. All methods are async. Auto-reads RACLIP_API_KEY from the environment if apiKey is omitted.
Constructor¶
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
process.env.RACLIP_API_KEY |
API key. Throws AuthenticationError if absent. |
baseUrl |
string |
production URL | Override the API base URL. |
timeout |
number |
30 |
Request timeout in seconds. |
Properties¶
| Property | Type | Description |
|---|---|---|
baseUrl |
string |
Resolved base URL (read-only). |
devices |
DevicesResource |
Device operations. |
calls |
CallsResource |
Call operations. |
Methods¶
close()¶
No-op for the fetch-based transport. Exists for API parity. Use await using or call explicitly for clarity.
Resources¶
client.devices and client.calls expose all API operations. Every method returns a Promise.
Devices¶
devices.list(params?)¶
List all devices in the org.
| Param | Type | Default |
|---|---|---|
status |
string \| null |
null |
page |
number |
1 |
per_page |
number |
50 |
devices.get(deviceId)¶
Fetch a single device by ID.
devices.status(deviceId)¶
Lightweight online/offline check for a device.
devices.stats()¶
Org-wide device statistics.
Calls¶
calls.list(deviceId, params?)¶
List calls for a device.
| Param | Type | Default |
|---|---|---|
page |
number |
1 |
per_page |
number |
50 |
days_back |
number |
30 |
include_urls |
boolean |
true |
calls.get(deviceId, callId, params?)¶
Fetch a single call. Pass { download: true } to include download_url.
calls.latest(deviceId, params?)¶
Fetch the most recent call for a device.
calls.statistics(deviceId, params?)¶
Aggregate statistics for a device's calls. days_back defaults to 30.
calls.info(deviceId, callId)¶
Raw call metadata object.
calls.download(deviceId, callId, dest)¶
Stream the recording to dest. dest is a file path string or a Node.js Writable. Returns dest.
Models¶
Every API response is parsed into a typed TypeScript interface.
Device¶
interface Device {
device_id: string
org_id: string | null
hardware_id: string
mac_address: string
serial_number: string | null
firmware_version: string
device_model: string
unit_id: string | null
location_id: string | null
employee_id: string | null
custom_fields: Record<string, unknown> | null
status: string
last_seen: Date | null
last_registration: Date
assigned_at: Date | null
created_at: Date
}
DeviceListResponse¶
DeviceStats¶
interface DeviceStats {
org_id: string
total_devices: number
assigned_devices: number
unassigned_devices: number
online_devices: number
offline_devices: number
recent_registrations_7d: number
device_status_breakdown: Record<string, number>
assignment_breakdown: DeviceAssignmentBreakdown
}
interface DeviceAssignmentBreakdown {
assigned_to_unit: number
assigned_to_location: number
assigned_to_employee: number
}
DeviceStatusSnapshot¶
interface DeviceStatusSnapshot {
status: string
last_seen: Date | null
is_online: boolean | undefined
}
Call¶
interface Call {
call_id: string
device_id: string | null
duration_seconds: number
file_size_bytes: number
storage_format: string
bitrate: string
created_at: Date
download_url: string | null
s3_path: string | null
start_timestamp: Date | null
end_timestamp: Date | null
call_sequence: number | null
}
CallListResponse¶
interface CallListResponse {
device_id: string
calls: Call[]
total: number
page: number
per_page: number
}
CallStatistics¶
interface CallStatistics {
total_calls: number
total_duration_seconds: number
total_size_bytes: number
avg_duration_seconds: number
first_call: Date | null
latest_call: Date | null
}
Exceptions¶
Every non-2xx response throws a typed error in the RaclipError tree:
RaclipError
├── APIConnectionError # network failure, DNS, TLS, etc.
├── APIError # 5xx from the gateway
├── AuthenticationError # 401
├── PermissionError # 403
├── NotFoundError # 404
├── ValidationError # 400 / 422
└── RateLimitError # 429 — exposes .retryAfter
All errors extend RaclipError and expose:
| Property | Type | Description |
|---|---|---|
message |
string |
Human-readable error message. |
statusCode |
number \| undefined |
HTTP status code, if available. |
responseBody |
unknown |
Raw response body from the API. |
detail |
string |
Extracted detail field from the response body, or falls back to message. |
RateLimitError additionally exposes:
| Property | Type | Description |
|---|---|---|
retryAfter |
number \| null |
Seconds to wait before retrying, if provided by the server. |