# LightNVR API Documentation This document describes the REST API endpoints provided by LightNVR. ## API Overview LightNVR provides a RESTful API that allows you to interact with the system programmatically. The API is accessible via HTTP and returns JSON responses using the cJSON library. The API is served by the libuv + llhttp web server. ## Authentication If authentication is enabled in the configuration file, endpoints that require authentication accept one of three mechanisms. Authentication and role-based access checks are enforced per-endpoint. Where authentication is required, all three mechanisms resolve to the same `user_t`, so pick whichever fits the caller. ### 1. Session cookie (interactive UI, scripts that log in once) Obtain a session by calling the login endpoint, then include the session cookie on subsequent requests. ```bash curl -c cookies.txt -X POST -H "Content-Type: application/json" \ -d '{"username":"admin","password":"yourpassword"}' \ http://your-lightnvr-ip:8080/api/auth/login curl -b cookies.txt http://your-lightnvr-ip:8080/api/streams ``` ### 2. API key (automation, long-lived integrations) Every user has an `api_key` field. Pass it via either header: ```bash # Preferred curl -H "X-API-Key: " http://your-lightnvr-ip:8080/api/streams # Also accepted curl -H "Authorization: Bearer " http://your-lightnvr-ip:8080/api/streams ``` For automation (Home Assistant, NodeRED, cron jobs, etc.), create a dedicated user with the `USER_ROLE_API` role and use that user's `api_key`. Keep admin keys out of automation configs. ### 3. HTTP Basic Auth Also supported as a fallback for tools that only understand basic auth. ### Roles Role-based access is enforced per-endpoint. The table below is a high-level summary of the intended access model: | Role | Can read | Can write | Can administer | |----------|:--------:|:---------:|:--------------:| | `ADMIN` | yes | yes | yes | | `USER` | yes | yes | no | | `API` | yes | yes | no | | `VIEWER` | yes | typically no | no | Write authorization is endpoint-specific. Some write endpoints (including [`POST /api/motion/trigger`](#trigger-motion-event)) may reject `VIEWER` with `403`, but callers should rely on each endpoint's documented or implemented access checks rather than assuming all write endpoints enforce the same role restriction. ## API Endpoints ### Streams #### List Streams ``` GET /api/streams ``` Returns a list of all configured streams. **Response:** ```json { "streams": [ { "id": 0, "name": "Front Door", "url": "rtsp://192.168.1.100:554/stream1", "enabled": true, "streaming_enabled": true, "width": 1920, "height": 1080, "fps": 15, "codec": "h264", "priority": 10, "record": true, "segment_duration": 900, "protocol": 0, "record_audio": true, "detection_based_recording": 0, "detection_model": "", "detection_threshold": 0.5, "detection_interval": 10, "pre_detection_buffer": 0, "post_detection_buffer": 3, "detection_api_url": "", "is_onvif": false, "onvif_username": "", "onvif_password": "", "onvif_profile": "", "ptz_enabled": false, "backchannel_enabled": false, "buffer_strategy": "auto", "retention_days": 30, "status": "connected" } ] } ``` #### Get Stream ``` GET /api/streams/{name} ``` Returns information about a specific stream by name. #### Get Full Stream ``` GET /api/streams/{name}/full ``` Returns complete stream information including all configuration fields. #### Add Stream ``` POST /api/streams ``` Adds a new stream. All fields from the stream schema are accepted. #### Update Stream ``` PUT /api/streams/{name} ``` Updates an existing stream. #### Delete Stream ``` DELETE /api/streams/{name} ``` Deletes a stream. #### Test Stream ``` POST /api/streams/test ``` Tests connectivity to a stream URL. #### Refresh Stream ``` POST /api/streams/{name}/refresh ``` Forces a stream reconnection. ### Stream Retention #### Get Stream Retention ``` GET /api/streams/{name}/retention ``` Returns retention settings for a specific stream. #### Update Stream Retention ``` PUT /api/streams/{name}/retention ``` Updates retention settings for a specific stream. ### Detection Zones #### List Zones ``` GET /api/streams/{name}/zones ``` Returns detection zones for a stream. #### Create/Update Zones ``` POST /api/streams/{name}/zones ``` Creates or updates detection zones for a stream. #### Delete Zones ``` DELETE /api/streams/{name}/zones ``` Deletes detection zones for a stream. ### PTZ (Pan-Tilt-Zoom) #### Get PTZ Capabilities ``` GET /api/streams/{name}/ptz/capabilities ``` Returns PTZ capabilities for a stream's camera. #### PTZ Move ``` POST /api/streams/{name}/ptz/move ``` Starts continuous PTZ movement. #### PTZ Stop ``` POST /api/streams/{name}/ptz/stop ``` Stops PTZ movement. #### PTZ Absolute Move ``` POST /api/streams/{name}/ptz/absolute ``` Moves to an absolute PTZ position. #### PTZ Relative Move ``` POST /api/streams/{name}/ptz/relative ``` Performs a relative PTZ movement. #### PTZ Home ``` POST /api/streams/{name}/ptz/home ``` Moves to the home position. #### PTZ Set Home ``` POST /api/streams/{name}/ptz/set-home ``` Sets the current position as home. #### PTZ Presets ``` GET /api/streams/{name}/ptz/presets ``` Lists PTZ presets. ``` POST /api/streams/{name}/ptz/goto-preset ``` Moves to a PTZ preset. ``` PUT /api/streams/{name}/ptz/preset ``` Creates or updates a PTZ preset. ### Motion #### Trigger Motion Event ``` POST /api/motion/trigger ``` Drives the same motion-recording path that ONVIF events normally drive. Useful for cameras whose ONVIF event stream is unreliable or missing — the caller (Home Assistant, NodeRED, a shell script, a PIR sensor bridge) can post a motion event and the target stream's detection-based recording pipeline (pre-buffer → recording → post-buffer) handles the rest. The target stream must have `detection_based_recording` enabled; otherwise the unified detection thread is not running and there is nothing for the trigger to drive (409 Conflict). **Authentication:** See [Authentication](#authentication). For automation use a dedicated `USER_ROLE_API` user and its `api_key`; `USER_ROLE_VIEWER` is rejected with 403. **Request body:** | Field | Type | Required | Notes | |---------------|---------|----------|---------------------------------------------------------| | `stream` | string | yes | Stream name, as shown in the streams list. | | `action` | string | yes | One of `start`, `stop`, `pulse`. | | `duration_ms` | integer | no | Only valid with `pulse`. Default 2000, max 600000 (10m).| **Actions:** - `start` — motion began. Equivalent to an ONVIF motion-start event. Recording begins (after the pre-buffer window) and continues until a corresponding `stop` arrives, at which point the UDT transitions into the post-buffer hold and then closes the recording. - `stop` — motion ended. Mirror of `start`. - `pulse` — convenience: fires `start`, waits `duration_ms`, then fires `stop`. One request produces one complete motion event. Ideal for motion sensors that only report a single edge (e.g. a Home Assistant automation that fires when a PIR sensor goes active but does not send a separate "cleared" webhook). **Response:** `202 Accepted` ```json { "success": true, "stream": "Front Door", "action": "pulse", "duration_ms": 5000 } ``` **Errors:** - `400` — missing/invalid JSON, missing `stream`/`action`, bad `duration_ms`. - `401` — auth enabled and caller is not authenticated. - `403` — caller is `USER_ROLE_VIEWER`. - `404` — `stream` does not match a configured stream. - `409` — stream does not have `detection_based_recording` enabled. **Examples:** Start/stop (matches how an ONVIF sensor would report): ```bash curl -X POST http://lightnvr:8080/api/motion/trigger \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{"stream":"Front Door","action":"start"}' # ...later, when motion clears: curl -X POST http://lightnvr:8080/api/motion/trigger \ -H "X-API-Key: " -H "Content-Type: application/json" \ -d '{"stream":"Front Door","action":"stop"}' ``` One-shot pulse (Home Assistant rest_command with a PIR sensor): ```yaml rest_command: lightnvr_motion: url: "http://lightnvr:8080/api/motion/trigger" method: POST headers: X-API-Key: !secret lightnvr_api_key content_type: "application/json" payload: '{"stream":"{{ stream }}","action":"pulse","duration_ms":{{ duration | default(5000) }}}' ``` Cross-stream linking (`motion_trigger_source` in stream config) is honoured: an API-driven motion event on one stream will also drive recording on any stream that lists it as a trigger source, same as an ONVIF-driven event. ### Recordings #### List Recordings ``` GET /api/recordings ``` Returns a list of recordings. Supports query parameters for filtering by stream name, date range, and pagination. #### Get Recording ``` GET /api/recordings/{id} ``` Returns information about a specific recording. #### Delete Recording ``` DELETE /api/recordings/{id} ``` Deletes a recording. #### Play Recording ``` GET /api/recordings/play/{id} ``` Streams a recording for playback. #### Download Recording ``` GET /api/recordings/download/{id} ``` Downloads a recording file. #### Protect Recording ``` PUT /api/recordings/{id}/protect ``` Toggles protection status on a recording (protected recordings are exempt from auto-deletion). #### Set Recording Retention ``` PUT /api/recordings/{id}/retention ``` Sets a per-recording retention override. #### Batch Delete Recordings ``` POST /api/recordings/batch-delete ``` Deletes multiple recordings at once. Returns a job ID for progress tracking. #### Batch Delete Progress ``` GET /api/recordings/batch-delete/progress/{job_id} ``` Returns progress for a batch delete operation. #### Batch Protect Recordings ``` POST /api/recordings/batch-protect ``` Protects or unprotects multiple recordings at once. #### Get Protected Recordings ``` GET /api/recordings/protected ``` Returns all protected recordings. #### Recording File Check ``` GET /api/recordings/files/check ``` Checks if a recording file exists on disk. #### Delete Recording File ``` DELETE /api/recordings/files ``` Deletes a recording file from disk. #### Sync Recordings ``` POST /api/recordings/sync ``` Synchronizes the recordings database with files on disk. ### Timeline #### Get Timeline Segments ``` GET /api/timeline/segments ``` Returns recording segments for the timeline view. Supports query parameters for stream name and date range. #### Get Timeline Manifest ``` GET /api/timeline/manifest ``` Returns a manifest of available timeline data. #### Timeline Playback ``` GET /api/timeline/play ``` Streams video for timeline playback at a specified point in time. ### System #### Get System Information ``` GET /api/system GET /api/system/info ``` Returns system information including version, uptime, CPU/memory/storage usage, and stream counts. The response also includes a `versions.items` array summarizing runtime-detected software versions such as the base OS, LightNVR, optional services, and linked libraries. #### Get System Status ``` GET /api/system/status ``` Returns system health status. #### Get System Logs ``` GET /api/system/logs ``` Returns recent system log entries. #### Clear System Logs ``` POST /api/system/logs/clear ``` Clears the system log file. #### Restart System ``` POST /api/system/restart ``` Restarts the LightNVR service. #### Shutdown System ``` POST /api/system/shutdown ``` Shuts down the LightNVR service. #### System Backup ``` POST /api/system/backup ``` Creates a backup of the database. #### Get Settings ``` GET /api/settings ``` Returns system configuration settings. #### Update Settings ``` POST /api/settings ``` Updates system configuration settings. ### Health #### Health Check ``` GET /api/health ``` Returns basic health status. #### HLS Health Check ``` GET /api/health/hls ``` Returns HLS streaming subsystem health. ### ICE Servers #### Get ICE Servers ``` GET /api/ice-servers ``` Returns WebRTC ICE server configuration (STUN/TURN servers). ### Authentication #### Login ``` POST /api/auth/login ``` Authenticates a user and creates a session. **Request Body:** ```json { "username": "admin", "password": "yourpassword" } ``` #### Login with TOTP ``` POST /api/auth/login/totp ``` Completes login with a TOTP code (for users with MFA enabled). **Request Body:** ```json { "token": "pending_session_token", "totp_code": "123456" } ``` #### Logout ``` POST /api/auth/logout GET /logout ``` Destroys the current session. #### Verify Session ``` GET /api/auth/verify ``` Verifies that the current session is valid. ### User Management #### List Users ``` GET /api/auth/users ``` Returns all users (admin only). #### Create User ``` POST /api/auth/users ``` Creates a new user. #### Get User ``` GET /api/auth/users/{id} ``` Returns a specific user. #### Update User ``` PUT /api/auth/users/{id} ``` Updates a user. #### Delete User ``` DELETE /api/auth/users/{id} ``` Deletes a user. #### Generate API Key ``` POST /api/auth/users/{id}/api-key ``` Generates an API key for a user. #### Change Password ``` PUT /api/auth/users/{id}/password ``` Changes a user's password. #### Password Lock ``` PUT /api/auth/users/{id}/password-lock ``` Locks or unlocks a user's password from being changed. ### TOTP/MFA #### Setup TOTP ``` POST /api/auth/users/{id}/totp/setup ``` Initiates TOTP setup, returns secret and QR code URI. #### Verify TOTP ``` POST /api/auth/users/{id}/totp/verify ``` Verifies a TOTP code during setup to confirm it works. #### Disable TOTP ``` POST /api/auth/users/{id}/totp/disable ``` Disables TOTP for a user. #### TOTP Status ``` GET /api/auth/users/{id}/totp/status ``` Returns whether TOTP is enabled for a user. ### ONVIF Discovery #### Discovery Status ``` GET /api/onvif/discovery/status ``` Returns ONVIF discovery service status. #### Discover Devices ``` POST /api/onvif/discovery/discover ``` Triggers an ONVIF device discovery scan. #### List Discovered Devices ``` GET /api/onvif/devices ``` Returns discovered ONVIF devices. #### Get Device Profiles ``` GET /api/onvif/device/profiles ``` Returns media profiles for an ONVIF device. #### Add Device as Stream ``` POST /api/onvif/device/add ``` Adds a discovered ONVIF device as a stream. #### Test ONVIF Connection ``` POST /api/onvif/device/test ``` Tests connectivity to an ONVIF device. ### Detection #### Get Detection Results ``` GET /api/detection/results/{stream_name} ``` Returns recent detection results for a stream. #### List Detection Models ``` GET /api/detection/models ``` Returns available detection models. ### Motion Recording #### Test Motion Event ``` POST /api/motion/test/{stream_name} ``` Triggers a test motion event for debugging. ### HLS Streaming #### Direct HLS Request ``` GET /hls/{stream_name}/{filename} ``` Serves HLS playlist (.m3u8) and segment (.ts) files for live streaming. ## Error Handling All API endpoints return appropriate HTTP status codes: - 200: Success - 400: Bad Request - 401: Unauthorized - 404: Not Found - 500: Internal Server Error Error responses include a JSON object with an error message: ```json { "error": "Stream not found" } ``` ## Examples ### Curl Examples Login and list streams: ```bash # Login curl -c cookies.txt -X POST -H "Content-Type: application/json" \ -d '{"username":"admin","password":"yourpassword"}' \ http://your-lightnvr-ip:8080/api/auth/login # List streams curl -b cookies.txt http://your-lightnvr-ip:8080/api/streams # Get system information curl -b cookies.txt http://your-lightnvr-ip:8080/api/system # Add a new stream curl -b cookies.txt -X POST -H "Content-Type: application/json" \ -d '{"name":"New Camera","url":"rtsp://192.168.1.103:554/stream1","enabled":true,"width":1280,"height":720,"fps":10,"codec":"h264","priority":5,"record":true}' \ http://your-lightnvr-ip:8080/api/streams # Trigger ONVIF discovery curl -b cookies.txt -X POST http://your-lightnvr-ip:8080/api/onvif/discovery/discover ```