REST API Reference

Every feature in the Videre UI is accessible via HTTP REST and WebSocket — suitable for scripting, automation pipelines, and headless integration.

Base URL & Format

Base URL: http://localhost:8080 (configurable with --port)

Content-Type: All POST request bodies are application/json. All JSON responses use Content-Type: application/json.

WebSocket URLs: ws://localhost:8080/stream and ws://localhost:8080/events

Authentication

There is no authentication. The server binds to localhost by default. If you need remote access, use SSH port forwarding — see Remote Access via SSH.

Security warning: Binding to 0.0.0.0 with --host 0.0.0.0 exposes all endpoints to your network with no access control. Use SSH port forwarding for secure remote access.

Error Format

All errors return a JSON object with an error field and an appropriate HTTP status code.

json
{"error": "No device is open"}
StatusMeaning
400Bad request — missing or invalid parameters
404Resource not found
409Conflict — operation not allowed in current state (e.g. format change while streaming)
500Internal server error

Device Management

GET /api/devices

List all available V4L2 camera devices.

bash
$ curl http://localhost:8080/api/devices
FieldTypeDescription
pathstringDevice node path
namestringHuman-readable device name
driverstringKernel driver name
busInfostringBus location identifier

POST /api/device/open

Open a camera device for use.

bash
$ curl -X POST http://localhost:8080/api/device/open -d '{"path": "/dev/video0"}'
Request fieldTypeRequiredDescription
pathstringYesDevice node path (e.g. /dev/video0)
Response fieldTypeDescription
okboolSuccess flag
namestringDevice name
pathstringDevice node path
widthintCurrent frame width in pixels
heightintCurrent frame height in pixels
pixelFormatstringActive pixel format FourCC

POST /api/device/close

Close the currently open camera device. No request body required.

bash
$ curl -X POST http://localhost:8080/api/device/close

GET /api/device/info

Get information about the currently open device.

bash
$ curl http://localhost:8080/api/device/info
FieldTypeDescription
namestringDevice name
pathstringDevice node path
widthintCurrent frame width
heightintCurrent frame height
pixelFormatstringActive pixel format FourCC
streamingboolWhether the device is currently streaming

GET /api/device/formats

Enumerate all pixel formats and available resolutions for the open device.

bash
$ curl http://localhost:8080/api/device/formats
FieldTypeDescription
fourccstringFour-character pixel format code
descriptionstringHuman-readable format name
sizeTypestring"discrete", "stepwise", or "continuous"
sizesarrayList of {width, height} objects (discrete only)
stepwiseobject|nullMin/max/step bounds (stepwise/continuous only)
frameRatesobjectMap of "WxH" to array of supported FPS values

GET /api/device/framerate

Get the current frame rate setting.

bash
$ curl http://localhost:8080/api/device/framerate
FieldTypeDescription
fpsfloatCurrent frame rate
supportedboolWhether the device supports frame rate control
minFpsfloatMinimum supported FPS
maxFpsfloatMaximum supported FPS

POST /api/device/framerate

Set the frame rate.

bash
$ curl -X POST http://localhost:8080/api/device/framerate -d '{"fps": 30.0}'

Response: {"ok": true, "actualFps": 30.0} — the driver may clamp or round the requested value.

POST /api/device/format

Set the pixel format. Returns 409 if called while streaming.

bash
$ curl -X POST http://localhost:8080/api/device/format -d '{"format": "MJPG"}'

POST /api/device/framesize

Set the frame resolution. Returns 409 if called while streaming.

bash
$ curl -X POST http://localhost:8080/api/device/framesize -d '{"width": 1920, "height": 1080}'

GET /api/device/crop

Get hardware crop support and current crop region.

bash
$ curl http://localhost:8080/api/device/crop
FieldTypeDescription
supportedboolWhether the device supports hardware cropping
boundsobject|nullMaximum crop region (sensor bounds)
currentobject|nullCurrently active crop region

POST /api/device/crop

Apply a hardware crop region.

bash
$ curl -X POST http://localhost:8080/api/device/crop -d '{"left": 0, "top": 0, "width": 640, "height": 480}'

POST /api/device/crop/reset

Reset the crop region to the full sensor area. No request body required.

bash
$ curl -X POST http://localhost:8080/api/device/crop/reset

Camera Controls

GET /api/device/controls

List all V4L2 controls exposed by the open device (brightness, contrast, exposure, etc.).

bash
$ curl http://localhost:8080/api/device/controls
FieldTypeDescription
idintV4L2 control ID
namestringHuman-readable control name
typestringint, bool, menu, intmenu, button, int64, string, bitmask
minimumintMinimum value
maximumintMaximum value
stepintValue step increment
defaultintDefault value
valueint|stringCurrent value
menuarrayMenu entries (only for menu and intmenu types)

POST /api/device/control

Set a V4L2 control value. The read-back value may differ from the requested value due to driver clamping or rounding.

bash
$ curl -X POST http://localhost:8080/api/device/control -d '{"id": 9963776, "value": 200}'
Request fieldTypeRequiredDescription
idintYesV4L2 control ID
valueint|stringYesNew value to set

ISP (Raspberry Pi)

These endpoints are only meaningful on Raspberry Pi 5 with an active PiSP ISP pipeline.

GET /api/isp/tuning-files

Lists available tuning files for a given sensor.

bash
$ curl 'http://localhost:8080/api/isp/tuning-files?sensor=imx477'

GET /api/isp/settings

Returns current ISP state. When PiSP ISP is active, fields include: available, ae, awb, awbGainR, awbGainB, blc, blcValue, lsc, dpc, denoise, sharpen, exposureUs, analogueGain, frameRate, tuningLoaded. Returns {"available":false} when ISP is not active.

POST /api/isp/settings

Updates ISP settings with a partial JSON patch.

bash
$ curl -X POST http://localhost:8080/api/isp/settings -d '{"ae":true,"awb":true,"denoise":true}'

Stream Control

POST /api/stream/start

Start capturing frames from the device. Frames become available on the /stream WebSocket.

bash
$ curl -X POST http://localhost:8080/api/stream/start

POST /api/stream/stop

Stop capturing frames. No request body required.

bash
$ curl -X POST http://localhost:8080/api/stream/stop

GET /api/stream/decimation

Get the current frame decimation (skip) settings.

bash
$ curl http://localhost:8080/api/stream/decimation
FieldTypeDescription
adaptiveboolWhether adaptive decimation is active
target_fpsfloatTarget display FPS (adaptive mode)
current_decimationintCurrent skip factor (1 = no skip, 2 = every 2nd frame, etc.)
device_fpsfloatMeasured device capture FPS

POST /api/stream/decimation

Configure frame decimation. Adaptive mode adjusts automatically; manual mode sets a fixed skip factor.

bash
$ curl -X POST http://localhost:8080/api/stream/decimation -d '{"adaptive": true, "target_fps": 30.0}'
$ curl -X POST http://localhost:8080/api/stream/decimation -d '{"decimation": 2}'

GET /api/status

Get pipeline statistics.

bash
$ curl http://localhost:8080/api/status
FieldTypeDescription
streamingboolWhether the pipeline is active
framesProcessedintTotal frames processed since stream start
framesDroppedintFrames dropped (ring buffer overflow or decimation)
deviceFpsfloatMeasured device FPS
nativeWidthintNative frame width from the device
nativeHeightintNative frame height from the device

WebSocket Endpoints

WS ws://localhost:8080/stream

Binary WebSocket delivering JPEG-encoded frames in real time.

Backpressure protocol: After receiving and processing each frame, the client must send an "ack" text message. The server will not send the next frame until it receives the ack — this prevents unbounded memory growth on slow clients.

OffsetSizeTypeField
04uint32_leFrame width
44uint32_leFrame height
84uint32_leFrame ID (low 32 bits)
124uint32_leFrame ID (high 32 bits)
16variablebytesJPEG image data
javascript
const ws = new WebSocket('ws://localhost:8080/stream');
ws.binaryType = 'arraybuffer';

ws.onmessage = (event) => {
  const data = new DataView(event.data);
  const width = data.getUint32(0, true);
  const height = data.getUint32(4, true);
  const jpeg = new Blob([new Uint8Array(event.data, 16)], {type: 'image/jpeg'});
  img.src = URL.createObjectURL(jpeg);
  ws.send('ack'); // required — triggers next frame
};

WS ws://localhost:8080/events

JSON WebSocket delivering server-to-client events. The client does not send messages on this socket. Each message is a JSON object with at minimum an event field. See Events Reference for all event types.

javascript
const events = new WebSocket('ws://localhost:8080/events');
events.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  console.log(msg.event, msg);
};

Saving Images

POST /api/save

Save the current frame to disk. Files are saved to ~/Pictures/videre/ (created automatically).

bash
$ curl -X POST http://localhost:8080/api/save -d '{"format": "tiff"}'
Request fieldTypeRequiredDescription
formatstringNo"jpeg" (default), "tiff", or "raw"
Source formatjpegtiff
MJPEGRaw JPEG passthroughNot supported
H264 / YUYV / NV12 / RGB24Encoded from RGB248-bit RGB TIFF
GREY (8-bit mono)Encoded from RGB248-bit grayscale TIFF
Y16 (16-bit mono)Encoded from RGB2416-bit grayscale TIFF (raw values)
Y12 (12-bit mono)Encoded from RGB2416-bit grayscale TIFF (values ×16)

Recording Video

POST /api/recording/start

bash
$ curl -X POST http://localhost:8080/api/recording/start -d '{"maxBytes": 524288000, "format": "avi"}'
FieldTypeRequiredDescription
maxBytesintNoMaximum file size in bytes (default: ~200 MB)
formatstringNo"avi" (MJPEG AVI, default) or "raw" (uncompressed DIB AVI)

POST /api/recording/stop

Stop the active recording. No request body required.

bash
$ curl -X POST http://localhost:8080/api/recording/stop

GET /api/recording/status

bash
$ curl http://localhost:8080/api/recording/status
FieldTypeDescription
recordingboolWhether recording is active
pathstringOutput file path
framesRecordedintTotal frames written
bytesWrittenintTotal bytes written
elapsedSecfloatElapsed recording time
maxBytesintFile size limit

Image Mode

Load a still image for offline analysis. RAW files (DNG, CR2, NEF, etc.) require a paid tier.

GET /api/image/info

Returns image-mode state. Fields: active, filename, width, height, cameraJpegAvailable, renderMode.

POST /api/image/load

Loads an image from raw request bytes. Supply an optional X-Filename header for format detection.

bash
$ curl -X POST http://localhost:8080/api/image/load -H 'X-Filename: photo.jpg' --data-binary @photo.jpg

POST /api/image/load-path

Loads an image from a filesystem path on the server.

bash
$ curl -X POST http://localhost:8080/api/image/load-path -d '{"path":"/home/user/shot.dng"}'

POST /api/image/unload

Exits image mode and returns to camera streaming.

POST /api/image/rendering

Switches render mode for RAW files. Values: "camera", "libraw", "filmic".

GET /api/image/filmic-params

Returns current filmic parameters (exposure, clarity).

POST /api/image/filmic-params

Updates filmic parameters.

bash
$ curl -X POST http://localhost:8080/api/image/filmic-params -d '{"exposure":0.65,"clarity":2.5}'

Image Processing

GET /api/processing/chain

Get the full filter/detector chain — all available filters, their parameters, enabled state, and order.

bash
$ curl http://localhost:8080/api/processing/chain
IDNameCategory
gaussian_blurGaussian Blurfilter
median_blurMedian Blurfilter
sharpenSharpenfilter
grayscaleGrayscalefilter
thresholdThresholdfilter
canny_edgesCanny Edge Detectionfilter
contour_detectorContour Detectordetector
circle_detectorCircle Detectordetector
blob_detectorBlob Detectordetector
barcode_detectorBarcode Detectordetector

Enabling any filter activates the MJPEG decompression path (frames are decoded to RGB24 for processing). When all filters are disabled, the pipeline returns to JPEG passthrough mode.

POST /api/processing/filter/enable

bash
$ curl -X POST http://localhost:8080/api/processing/filter/enable -d '{"id": "canny_edges", "enabled": true}'

POST /api/processing/filter/param

bash
$ curl -X POST http://localhost:8080/api/processing/filter/param -d '{"id": "canny_edges", "param": "threshold1", "value": 80}'
FieldTypeRequiredDescription
idstringYesFilter/detector ID
paramstringYesParameter name
valueint|floatYesNew value

Histogram

GET /api/histogram/config

Get histogram configuration constants (bin count, dimensions, etc.).

POST /api/histogram/enable

Enable per-frame histogram computation. No request body required.

POST /api/histogram/disable

Disable histogram computation. No request body required.

POST /api/histogram/analyze/start

Start a 5-second histogram analysis window. Statistics are accumulated across frames for more accurate results. No request body required.

POST /api/histogram/analyze/stop

Stop the analysis window early. No request body required.

ROI Analysis

POST /api/roi/stats

Compute statistics and line profiles for a region of interest on the current frame.

bash
$ curl -X POST http://localhost:8080/api/roi/stats -d '{"x":100,"y":100,"width":200,"height":200,"profileMode":"average"}'
Request fieldTypeRequiredDescription
xintYesROI left edge (pixels)
yintYesROI top edge (pixels)
widthintYesROI width (pixels)
heightintYesROI height (pixels)
profileModestringNo"single" (default) — centre row/column. "average" — averaged across full ROI.
Response fieldTypeDescription
x, y, w, hintActual clamped ROI coordinates
bitDepthintSource bit depth: 8, 12, or 16
monobooltrue for mono cameras (GREY/Y12/Y16); all channel arrays will be identical
r, g, b, lumaobjectPer-channel stats: min, max (uint16, native range), mean, std (float)
hProfileobjectHorizontal line profile — per-channel uint16 array at ROI centre row
vProfileobjectVertical line profile — per-channel uint16 array at ROI centre column

For GREY/Y12/Y16 sources, analysis runs at native bit depth. For Y12, values are 0–4095; for Y16, values are 0–65535. For all colour sources, bitDepth is always 8.

Overlay System

Overlays are drawn on the live viewport and can optionally be burned into snapshots and recordings (paid tiers).

GET /api/overlays

Returns the full overlay configuration. Fields: global, overlays.

GET /api/overlays/capabilities

Returns tier-gated overlay capabilities. Fields: recordingBurnIn, customAssetOverlay, measurementOverlays.

POST /api/overlays/global

Updates global overlay settings.

bash
$ curl -X POST http://localhost:8080/api/overlays/global -d '{"enabled":true,"overallOpacity":0.6}'

POST /api/overlays/create

Creates an overlay. Key fields: id, name, type, enabled, opacity, color, zIndex, position, lineThickness, visibleInPreview, includeInSnapshot, includeInRecording.

POST /api/overlays/update

Updates an existing overlay by id.

POST /api/overlays/delete

Deletes an overlay by id.

bash
$ curl -X POST http://localhost:8080/api/overlays/delete -d '{"id":"crosshair-1"}'

Diagnostics

GET /api/diagnostics

Full system diagnostics — host system info, detected hardware, and actionable recommendations.

bash
$ curl http://localhost:8080/api/diagnostics

GET /api/diagnostics/pipeline

Live pipeline timing data from a ring buffer of recent frames.

bash
$ curl http://localhost:8080/api/diagnostics/pipeline
Timing fieldDescription
captureMsV4L2 buffer dequeue time
h264DecodeMsH.264 frame decode (0.0 if not H.264)
formatConvertMsPixel format conversion to RGB24
filterChainMsAll enabled pixel filters (sequential)
detectorsMsAll enabled detectors (parallel)
histogramMsHistogram computation
downscaleMsResolution downscale (if applicable)
jpegEncodeMsJPEG encoding for WebSocket delivery
totalProcessingMsTotal pipeline time per frame

Settings

POST /api/settings

bash
$ curl -X POST http://localhost:8080/api/settings -d '{"closeOnBrowserDisconnect": false}'
FieldTypeDescription
closeOnBrowserDisconnectboolIf true, server shuts down when the browser disconnects (4s grace period). Default: true.

Usage Data

GET /api/telemetry/consent

Get the current usage data consent status.

bash
$ curl http://localhost:8080/api/telemetry/consent
FieldTypeDescription
requiredboolWhether consent is required before use
givenboolWhether the user has responded to the consent prompt
tierstringLicense tier: "community", "pro", "subscription", "source"

POST /api/telemetry/consent

Accept or decline usage data consent.

bash
$ curl -X POST http://localhost:8080/api/telemetry/consent -d '{"accepted": true}'

POST /api/telemetry/feature

Record a feature usage event.

bash
$ curl -X POST http://localhost:8080/api/telemetry/feature -d '{"feature": "histogram"}'

Known feature identifiers: histogram, snapshot, recording, filter_enable, flip_h, flip_v, crop, zoom_fit, histogram_open, roi_open.

Licensing

Paid-tier endpoints. Only meaningful in Pro, Subscription, or Source builds.

GET /api/license/status

Returns current license state. Fields: ok, tier, state, hasActivationToken, hasLocalBinding, optionally licenseKey.

bash
$ curl http://localhost:8080/api/license/status

POST /api/license/activate

Activates a paid license on the current device.

bash
$ curl -X POST http://localhost:8080/api/license/activate -d '{"licenseKey":"VID-PRO-XXXX-XXXX-XXXX-XXXX"}'

Response fields: ok, state, tier, activationType, remainingCredits.

POST /api/license/local-bind

Stores a local single-device binding without consuming an activation credit.

POST /api/license/validate-current

Validates the cached activation token with the backend.

POST /api/license/revoke-current

Revokes the current device activation and frees the activation credit.

Events Reference

Events are delivered over the ws://localhost:8080/events WebSocket. Each message is a JSON object with an event field.

EventPayload fieldsDescription
deviceOpenedname, path, width, height, pixelFormatA camera was opened
deviceClosedThe active camera was closed
deviceErrorerrorA device error occurred
streamStartedStreaming began
streamStoppedStreaming ended
formatChangedwidth, height, pixelFormatPixel format or resolution changed
controlChangedid, valueA V4L2 control value changed
recordingStartedpathRecording began
recordingStoppedpath, framesRecorded, bytesWrittenRecording ended
recordingProgressframesRecorded, bytesWritten, elapsedSecPeriodic recording status
histogramAnalyzeStartedHistogram analysis window opened
histogramAnalyzeStoppedHistogram analysis window closed
processingConfigChangedFilter chain configuration changed
usageLimitReachedCommunity 1-hour limit reached; heartbeat verification starting
usageLimitVerifiedHeartbeat succeeded; usage verified
heartbeatFailedHeartbeat failed; app will shut down in 3 seconds
devicesChangedUSB hotplug detected; re-enumerate with GET /api/devices

Headless Usage

Videre can be operated entirely via REST without a browser — useful for scripting, testing, and embedded deployments.

bash — capture a single frame
$ videre --no-browser --port 9000 &
$ curl -s -X POST localhost:9000/api/device/open -d '{"path":"/dev/video0"}'
$ curl -s -X POST localhost:9000/api/device/framesize -d '{"width":1920,"height":1080}'
$ curl -s -X POST localhost:9000/api/stream/start
$ sleep 1
$ curl -s -X POST localhost:9000/api/save -d '{"format":"jpeg"}'
$ curl -s -X POST localhost:9000/api/stream/stop
$ curl -s -X POST localhost:9000/api/device/close
bash — record 10 seconds
$ curl -s -X POST localhost:8080/api/device/open -d '{"path":"/dev/video0"}'
$ curl -s -X POST localhost:8080/api/stream/start
$ curl -s -X POST localhost:8080/api/recording/start -d '{"format":"avi"}'
$ sleep 10
$ curl -s -X POST localhost:8080/api/recording/stop
$ curl -s -X POST localhost:8080/api/stream/stop
$ curl -s -X POST localhost:8080/api/device/close

Remote Access via SSH

Videre binds to localhost by default. To access it from another machine, use SSH port forwarding — both REST and WebSocket connections tunnel through SSH.

bash
# Forward port 8080 from the camera host to your local machine
$ ssh -L 8080:localhost:8080 user@camera-host

# Use a different local port
$ ssh -L 9000:localhost:8080 user@camera-host

# Persistent background tunnel
$ ssh -fNL 8080:localhost:8080 user@camera-host

# Two cameras on different ports
$ ssh -L 8080:localhost:8080 -L 8081:localhost:8081 user@camera-host