cameras

Create Camera

post/cameras/{site_id}

Request

  • Base URL
    https://api.verdun.ai (the document declares no server; this is the origin it was published from)
  • URL
    https://api.verdun.ai/cameras/{site_id}
  • Auth
    HTTP bearer

Path parameters

site_idstring required

Request body

camera_labelstring required

The label of the camera.

camera_idstring required

The camera ID.

kvs_stream_namestring nullable

The KVS stream name. OMIT to have the server generate a unique one (recommended). Must be unique among live cameras account-wide and cannot be changed after creation.

ip_addressstring required

The IP address of the camera.

portstring required

The port of the camera.

usernamestring nullable

Camera account username. Required for every integration EXCEPT the cloud VMSs (Verkada, Turing), whose cameras have no local account.

passwordstring nullable

Camera account password. WRITE-ONLY — no endpoint ever returns it. Required for every integration EXCEPT the cloud VMSs (Verkada, Turing), whose cameras have no local account.

integration'RTSP' | 'Network Optix' | 'Axis' | 'Avigilon' | 'Milestone' | 'Verkada' | 'Turing' | 'Hikvision' | 'AvertX' required
adapter'generic_onvif' | 'hanwha_onvif'
brand'hanwha' | 'dahua'
model'ANV-L7012R'
metadata_format'onvif'
rtsp_urlstring required

Full RTSP URL including credentials. Stored in Secrets Manager; reads return it with the password replaced by 'REDACTED'. Characters that would make the credential ambiguous ('/', '?', '#' in a password) must be percent-encoded.

rag_contextstring nullable

Free-form scene context passed to the AI pipeline for this camera.

ingest_mode'continuous' | 'motion_clip'
motion_configobject nullable

Extensible motion settings with bounded known keys (timings, thresholds, detector geometry/rate and RTSP buffer mode); see app/services/motion_config_validation.py. Unknown keys are preserved.

analytics_provider'none' | 'deepalert'
analytics_configobject nullable

Opaque per-vendor analytics settings interpreted by the ingestor.

ii_enabledboolean

Incident intelligence on/off. When false the camera's motion events still record and alert in the UI, but clips are not sent to the AI pipeline for classification.

fire_watchboolean

Fire-screen gate (site-admin-only; default off since 2026-10-01). When true, motion that the analytics provider rejected is still screened for smoke/flame before being discarded. FIRE is not in any production prompt profile, so leave it off unless a camera specifically needs the screen.

agent_modeboolean nullable

Agent mode at creation. Omit for the default: armed at a newly onboarded site or one with any armed camera, shadow at an all-shadow site. false = born in shadow (anyone may ask for it; e.g. a calibration period at an untuned site). true = born armed (site-admin-only; a non-admin's true falls back to the default) and requires ii_enabled, else 409.

monitoring_profile'security' | 'safety'

Example request

{
  "camera_label": "SD Sewing Company",
  "camera_id": "cam01",
  "kvs_stream_name": "dev-home-cam01",
  "ip_address": "192.0.0.1",
  "port": "554",
  "username": "admin",
  "password": "<PASSWORD>",
  "rtsp_url": "rtsp://admin:s3cret@10.0.0.1:554/stream1",
  "rag_context": "Loading dock, forklifts active until 22:00",
  "motion_config": {
    "debounce_seconds": 30,
    "post_roll_seconds": 5,
    "pre_roll_seconds": 5
  }
}

Response

Successful Response

idstring uuid required

The camera ID.

camera_labelstring required

The label of the camera.

camera_idstring required

The camera ID.

kvs_stream_namestring required

The KVS stream name.

ip_addressstring required

The IP address of the camera.

portstring required

The port of the camera.

usernamestring required

Camera account username (the password is never returned).

integration'RTSP' | 'Network Optix' | 'Axis' | 'Avigilon' | 'Milestone' | 'Verkada' | 'Turing' | 'Hikvision' | 'AvertX' required
adapter'generic_onvif' | 'hanwha_onvif'
brand'hanwha' | 'dahua'
model'ANV-L7012R'
metadata_format'onvif'
rtsp_urlstring nullable

The camera's RTSP URL with its password redacted. Never the working credentialed URL. See EditCameraRequest.rtsp_url for the write contract (blank or a REDACTED-bearing echo means keep).

rag_contextstring nullable

Free-form scene context passed to the AI pipeline for this camera.

ingest_mode'continuous' | 'motion_clip'
motion_configobject nullable

Extensible motion settings with bounded known keys (timings, thresholds, detector geometry/rate and RTSP buffer mode); see app/services/motion_config_validation.py. Unknown keys are preserved.

analytics_provider'none' | 'deepalert'
analytics_configobject nullable

Opaque per-vendor analytics settings interpreted by the ingestor.

ii_enabledboolean

Incident intelligence on/off; when false motion events still record and alert, but skip AI classification.

fire_watchboolean

Fire-screen gate; when true, analytics-rejected motion is still screened for smoke/flame before being discarded.

monitoring_profile'security' | 'safety'
live_view_onlyboolean

Live View only: the camera is connected for Live View with no AI and no alarms (its monitoring state is always off). The site-level flag on the camera's site has the same effect.

display_rotationinteger

Degrees counter-clockwise the recorded frame is turned for display (0 or 180). Set by an owner for an upside-down camera; clips are then stamped with a display-matrix tag and the camera's zones are stored in the rotated (upright) space.

agent_modeboolean

Agent mode on/off; when true the backend acts on AI recommendations (auto-dismiss / voice-down / escalate-upgrade) instead of holding every clip for human review.

agent_observation_minutesinteger

Post-voice-down observation window in minutes before an alert auto-dismisses (agent mode).

agent_incident_typesstring[] nullable

Incident types the agent may process at all on this camera; unselected types go to the human queue. Auto-dismiss is additionally bounded by the global safety allowlist.

incident_routingobject nullable

Per-camera incident routing: incident type -> 'ignore' (dropped and auto-dismissed as not monitored) | 'humans' (operator queue) | 'agent'. A type absent from the map routes to 'humans'; UNKNOWN is never present. Supersedes agent_incident_types, which is now derived from this and kept for one release. Typed as plain strings on the RESPONSE side, deliberately: the read path fails closed (a mode outside the enum reads as 'humans'), and response validation must not undo that by 500-ing on a stored value this build does not know - a hand edit, or a newer task's mode during a rolling deploy. The enum is enforced on the REQUEST model only.

detection_modestring nullable

DeepAlert Phase B routing mode (owner-only, written via PUT /cameras/{id}/detection-mode): 'legacy' | 'ii_gated'; null means legacy. Only meaningful when analytics_provider == 'deepalert'.

ptzboolean

Whether this camera is pan/tilt/zoom; when true the 'camera moved' health issue is suppressed.

integration_idstring uuid nullable

The cloud-VMS connection (site_integrations.id) this camera was onboarded from; null for NVR and direct-RTSP cameras.

external_device_idstring nullable

The VENDOR's own camera id within that connection; null unless integration_id is set.

integration_device_infoobject nullable

Snapshot of what the vendor reported about the device at import (name, model, site, codec); null unless integration_id is set.

live_view_untilstring date-time nullable

On-demand live view is active while now() < this timestamp (motion_clip cameras).

healthyboolean nullable

The healthy status of the camera.

last_healthcheck_atstring date-time nullable

The last healthcheck at of the camera.

map_xnumber nullable

Normalized floor-plan x position (0..1) on the site map.

map_ynumber nullable

Normalized floor-plan y position (0..1) on the site map.

map_latnumber nullable

Geographic latitude on the site map.

map_lngnumber nullable

Geographic longitude on the site map.

map_location_labelstring nullable

Operator-facing location prose shown on queue rows and mini-maps.

map_headingnumber nullable

Direction the device faces, degrees clockwise from map-up; null = not aimed.

Example response

{
  "camera_label": "SD Sewing Company",
  "camera_id": "cam01",
  "kvs_stream_name": "dev-home-cam01",
  "ip_address": "192.0.0.1",
  "port": "554",
  "username": "admin",
  "rtsp_url": "rtsp://admin:REDACTED@10.0.0.1:554/stream1",
  "rag_context": "Loading dock, forklifts active until 22:00",
  "motion_config": {
    "debounce_seconds": 30,
    "post_roll_seconds": 5,
    "pre_roll_seconds": 5
  },
  "incident_routing": {
    "FIRE": "ignore",
    "LOITERING": "agent",
    "NORMAL": "humans"
  },
  "detection_mode": "ii_gated",
  "external_device_id": "3a1b0f4c-1d2e-4f5a-9b8c-7d6e5f4a3b2c",
  "healthy": true,
  "map_x": 0.42,
  "map_y": 0.63,
  "map_lat": 42.0443,
  "map_lng": -87.9825,
  "map_location_label": "NE corner — loading dock",
  "map_heading": 225,
  "deepalert_threshold": {
    "effective": 25
  }
}

Changes

No recorded changes to this operation across all 2 revisions of this API.