API
The REST API and WebSocket.
API
This document describes the Vigil API. It covers the REST API, the WebSocket, and the MediaMTX hooks.
The API contract is in server/api/openapi.yaml. It is an OpenAPI 3.1 document. The base URL is /api/v1.
The contract drives two code generators. oapi-codegen generates the Go server stubs. openapi-typescript generates the TypeScript client types.
Authentication
The API uses session tokens. The security scheme is cookieAuth. The cookie name is nvr_session.
The backend accepts the session in three forms:
- The
nvr_sessioncookie. - The
Authorization: Bearerheader. - The
X-Session-Tokenheader.
The cookie takes precedence when more than one form is present.
A session expires after 30 days. The session token is required for most endpoints.
Authorization roles
The API has three roles:
admin: full access.operator: camera management and probing.viewer: read-only access.
The authorization rules are:
- User administration, settings writes, and Drive administration require
admin. - Camera create, update, delete, and probe require
operatororadmin. - Camera reads, live, snapshots, recordings, events, and system reads require any authenticated user.
The REST endpoints
System
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
The health of the service. |
| GET | /system/version |
The version and commit. |
| GET | /system/disk |
The disk usage. |
| GET | /system/status |
The system status. |
Authentication
| Method | Path | Purpose |
|---|---|---|
| GET | /auth/status |
If setup is required and the session is valid. |
| POST | /auth/setup |
Create the first administrator. |
| POST | /auth/login |
Log in. |
| POST | /auth/logout |
Log out. |
| GET | /auth/me |
The current user. |
Cameras
| Method | Path | Purpose |
|---|---|---|
| GET | /cameras |
List the cameras. |
| POST | /cameras |
Create a camera. |
| POST | /cameras/probe |
Probe a camera stream. |
| GET | /cameras/{id} |
Get a camera. |
| PATCH | /cameras/{id} |
Update a camera. |
| DELETE | /cameras/{id} |
Delete a camera. |
| POST | /cameras/{id}/live |
Get a live stream session. |
| GET | /cameras/{id}/snapshot |
Get a camera snapshot. |
| GET | /cameras/{id}/recordings |
List the recordings in a range. |
| POST | /cameras/{id}/playback |
Get a playback session. |
Events
| Method | Path | Purpose |
|---|---|---|
| GET | /events |
List the events. |
| POST | /events/{id}/acknowledge |
Acknowledge an event. |
Settings
| Method | Path | Purpose |
|---|---|---|
| GET | /settings |
Get the settings. |
| PATCH | /settings |
Update the settings. |
Google Drive storage
| Method | Path | Purpose |
|---|---|---|
| GET | /storage/gdrive/status |
Get the Drive status. |
| PUT | /storage/gdrive/configuration |
Set the Drive configuration. |
| POST | /storage/gdrive/connect |
Begin the OAuth connection. |
| GET | /storage/gdrive/callback |
The OAuth callback. |
| DELETE | /storage/gdrive/disconnect |
Disconnect Drive. |
| POST | /storage/gdrive/archive |
Run the archive now. |
Users
| Method | Path | Purpose |
|---|---|---|
| GET | /users |
List the users. |
| POST | /users |
Create a user. |
| DELETE | /users/{id} |
Delete a user. |
The live stream session
The live endpoint returns a live stream session. The session has:
cameraId: the camera ID.hlsUrl: the HLS URL.whepUrl: the WHEP URL.token: the short-lived stream token.expiresAt: the token expiry time.
The client appends the token to the HLS and WHEP URLs. The token expires after about 60 seconds. The client refreshes the session before the token expires.
The playback session
The playback endpoint returns a playback session. The session has:
cameraId: the camera ID.playbackUrl: the MediaMTX playback URL.token: the short-lived playback token.expiresAt: the token expiry time.
The playback request has a start time and an optional durationSec. The default duration is 60 seconds.
The WebSocket
The WebSocket is at GET /api/v1/ws. It is not in the OpenAPI contract. It is mounted directly in the entry point.
The WebSocket is server-push only. Commands go over the REST API. The server authenticates the request, upgrades the connection, and subscribes to the event bus.
The server sends JSON text frames. The frame shape is:
{
"type": "event",
"data": {}
}
The server writes with a five-second timeout. A reader goroutine drains incoming frames to detect disconnects.
The dashboard and mobile app do not use the WebSocket. They poll the REST API. Refer to the dashboard and mobile documents.
The MediaMTX hooks
The MediaMTX hooks are internal. They are not part of the public API.
The auth hook
POST /internal/mediamtx/auth
MediaMTX calls this hook to validate a stream request. The handler accepts the MediaMTX external-auth JSON. It validates the token from the password, the token field, or the token query string. It returns 200 on success and 401 on failure.
The segment-complete hook
POST /internal/mediamtx/segment-complete
MediaMTX calls this hook when a recording segment completes. The handler accepts JSON or form data. It tolerates varied field names. It indexes the segment in SQLite.
Error responses
Errors return a JSON object with an error string and an optional code. The HTTP status codes are standard:
400: bad request.401: unauthenticated.403: forbidden.404: not found.409: conflict.504: timeout.
The generated client
The TypeScript client is in packages/api-client. The gen script runs openapi-typescript on the contract. The output is src/generated/schema.ts.
The client wraps openapi-fetch. The createApiClient function creates a client for a base URL. It defaults credentials to include.
Refer to development for the code generation commands.