default

Hikvision ISAPI: the alert stream and the documents a monitoring tool reads, from an NVR or a camera.

Examples

Print motion alerts with the channel's name

import { alertStream, inputProxyChannels, request, stream } from "@hertzg/hikvision-api";

const nvr = { baseUrl: "http://192.0.2.10", username: "admin", password: "hunter2" };
const names = new Map(
  (await request(nvr, inputProxyChannels)).map((channel) => [channel.id, channel.name]),
);

for await (const alert of await stream(nvr, alertStream, { signal: AbortSignal.timeout(60_000) })) {
  if (alert.eventType === "VMD" && alert.eventState === "active") {
    console.log(alert.at, names.get(alert.channel), "motion");
  }
}

Read a camera's motion grid

import { motionDetection, request } from "@hertzg/hikvision-api";

const camera = { baseUrl: "http://192.0.2.21", username: "admin", password: "hunter2" };
const motion = await request(camera, motionDetection({ channel: 1 }));

console.log(motion.grid?.map((row) => row.map((cell) => cell ? "#" : ".").join("")).join("\n"));

Every call carries the credentials to the resource's path

import { assertEquals } from "@std/assert";
import { resolvesNext, spy } from "@std/testing/mock";
import { deviceInfo, request } from "@hertzg/hikvision-api";

const fetch = spy(resolvesNext([
  new Response(
    "<DeviceInfo><model>DS-7608NI-Q2/8P</model>" +
      "<firmwareVersion>V4.75.207</firmwareVersion><deviceType>NVR</deviceType></DeviceInfo>",
  ),
]));
const nvr = { baseUrl: "http://192.0.2.10", username: "admin", password: "hunter2", fetch };

const info = await request(nvr, deviceInfo);

assertEquals(info.deviceType, "NVR");
assertEquals(fetch.calls[0].args[0], "http://192.0.2.10/ISAPI/System/deviceInfo");
const init = fetch.calls[0].args[1] as RequestInit;
assertEquals(new Headers(init.headers).get("authorization"), "Basic YWRtaW46aHVudGVyMg==");

Classes

c
IsapiError(failure: IsapiFailure)

A failed ISAPI request: a status outside 2xx, a failing <ResponseStatus> in the body, or both.

Functions

Type Aliases

T
Alert = { channel: number; eventType: string; eventState: string; eventDescription?: string; dateTime: string; at: string; activePostCount?: number; channelName?: string; ipAddress?: string; macAddress?: string; regions?: AlertRegion[]; }

One <EventNotificationAlert>, with the time it arrived.

T
AlertRegion = { id?: number; sensitivityLevel?: number; coordinates: Point[]; detectionTarget: string[]; targetRect?: TargetRect; }

A region reported with a smart event, from <DetectionRegionList>.

T
Device = { baseUrl: string; username: string; password: string; fetch?: globalThis.fetch; }

Where a device is and how to log in.

T
DeviceInfo = { deviceName?: string; deviceID?: string; model: string; serialNumber?: string; macAddress?: string; firmwareVersion: string; firmwareReleasedDate?: string; deviceType: string; }

The fields of <DeviceInfo>.

T
DeviceTime = { timeMode: string; localTime: string; timeZone: string; utcOffsetMinutes?: number; platformType?: string; }

The fields of <Time>.

  • localTime: string

    <localTime>: the device clock as ISO 8601 text, such as 2026-10-22T11:33:52+04:00. Some firmware leaves the offset out.

  • platformType: string

    <platformType>, such as EZVIZ, when timeMode is platform.

  • timeMode: string

    <timeMode>: where the clock comes from. NTP, manual, local, satellite or timecorrect; an NVR enrolled with a cloud platform reports platform.

  • timeZone: string

    <timeZone>: a POSIX TZ string such as CST-4:00:00.

  • utcOffsetMinutes: number

    The standard-time UTC offset of timeZone in minutes, ISO-style: CST-4:00:00 gives 240. Absent when timeZone does not parse.

T
FieldDetection = SmartRules

The fields of <FieldDetection>, whose type is FieldDetection.

T
FieldDetectionRegion = SmartRegion

One <FieldDetectionRegion>: a polygon that raises fielddetection.

T
InputProxyChannel = { id: number; name: string; proxyProtocol?: string; ipAddress?: string; managePortNo?: number; srcInputPort?: number; }

One <InputProxyChannel>: an IP camera as the NVR sees it.

T
InputProxyChannelStatus = { id: number; online: boolean; chanDetectResult?: string; url?: string; ipAddress?: string; proxyProtocol?: string; managePortNo?: number; srcInputPort?: number; connMode?: string; passwordStatus?: string; streamingProxyChannelIds?: number[]; }

One <InputProxyChannelStatus>: the NVR's view of one IP camera.

T
IsapiFailure = { url?: string; httpStatus?: number; status?: ResponseStatus; }

What an IsapiError knows about the failure.

T
LineDetection = { channel: number; enabled: boolean; normalizedScreenSize?: NormalizedScreenSize; lines: LineDetectionLine[]; }

The fields of <LineDetection>.

T
LineDetectionLine = SmartRule & { directionSensitivity?: string; }

One <LineItem>: a line whose crossing raises linedetection.

T
MotionDetection = { enabled: boolean; enableHighlight?: boolean; samplingIntervalFrames?: number; startTriggerTimeMs?: number; endTriggerTimeMs?: number; regionType?: "grid" | "roi" | "none" | "region" | (string & Record<never, never>); rows?: number; columns?: number; sensitivityLevel?: number; grid?: boolean[][]; regions?: MotionRegion[]; targetType?: string[]; }

The fields of <MotionDetection>.

T
MotionDetectionCapabilities = { regionTypes: string[]; rows?: number; columns?: number; sensitivityLevel?: { min?: number; max?: number; step?: number; }; targetTypes: string[]; regionEdges?: { min?: number; max?: number; }; }

What …/motionDetection/capabilities allows for a channel.

T
MotionDetectionTarget = { channel: number; proxy?: boolean; }

Which motion detection document to read.

  • channel: number

    The channel number, from 1.

  • proxy: boolean

    true reads the NVR's copy under /ISAPI/ContentMgmt/InputProxy, false (the default) the device's own video input.

T
MotionRegion = { id: number; coordinates: Point[]; }

One <Region> under <RegionList>: a drawn polygon.

T
NormalizedScreenSize = { width: number; height: number; }

<normalizedScreenSize>: the space the coordinates are drawn in.

T
Point = { x: number; y: number; }

A point in a device's normalized 1000 x 1000 screen space.

T
Resource<T> = { path: string; codec: Document<T>; }

One ISAPI resource: where it is and how to read it.

T
ResponseStatus = { requestURL?: string; statusCode: number; statusString?: string; subStatusCode?: string; }

The fields of a <ResponseStatus> document.

  • requestURL: string

    The path the device is answering about.

  • statusCode: number

    0 or 1 OK, 2 Device Busy, 3 Device Error, 4 Invalid Operation, 5 Invalid XML Format, 6 Invalid XML Content, 7 Reboot Required, 9 Additional Error. 7 can come on a 200 after a PUT.

  • statusString: string

    A short description, such as Invalid Operation.

  • subStatusCode: string

    The precise reason, such as notSupport, lowPrivilege or badAuthorization.

T
SmartRule = { id: number; enabled: boolean; sensitivityLevel?: number; coordinates: Point[]; detectionTarget: string[]; alarmConfidence?: string; }

What a region and a crossing line have in common.

T
SmartRules = { type: string; channel: number; enabled: boolean; normalizedScreenSize?: NormalizedScreenSize; humanMisinfoFilterEnabled?: boolean; vehicleMisinfoFilterEnabled?: boolean; regions: SmartRegion[]; }

The fields of a region rule document, such as <FieldDetection>.

T
SmartRuleType = Exclude<keyof SMART_RULE_TYPES, "LineDetection">

A region rule's path segment: every key of SMART_RULE_TYPES but LineDetection.

T
StreamOptions = { signal?: AbortSignal; }

Options for stream.

T
TargetRect = { x: number; y: number; width: number; height: number; }

Where a smart event saw its target, from <TargetRect>.

Variables

v
alertStream: Resource<Alert>

The alert stream: GET /ISAPI/Event/notification/alertStream, a multipart/mixed response that never ends, one <EventNotificationAlert> per part. Each alert is stamped with at, the time its part was decoded, which is the time it arrived.

v
deviceInfo: Resource<DeviceInfo>

The device info resource, /ISAPI/System/deviceInfo.

v
deviceTime: Resource<DeviceTime>

The device time resource, /ISAPI/System/time.

v
inputProxyChannels: Resource<InputProxyChannel[]>

The channel list resource, /ISAPI/ContentMgmt/InputProxy/channels.

v
inputProxyChannelStatus: Resource<InputProxyChannelStatus[]>

The channel status list resource, /ISAPI/ContentMgmt/InputProxy/channels/status.