Camera endpoints
Camera endpoints
All endpoints live under /api/v1/cameras. Read endpoints are open to every authenticated role; viewers are site-scoped (D78). Write endpoints require Operator or above (D81). Manual triggers rate-limit to one call per camera per 5 seconds (D49).
GET /api/v1/cameras
List cameras in the caller’s org.
Since: v1.0 Required role: viewer (site-scoped)
Query parameters
| Name | Type | Default | Constraints |
|---|---|---|---|
site_id | uuid | — | Filters to the given site |
gateway_id | uuid | — | Filters to cameras bound to a gateway |
status | enum | — | online, offline, pending, error, disabled |
type | enum | — | rtsp, onvif |
connection_mode | enum | — | gateway, direct |
cursor | string | null | Pagination cursor |
limit | int | 20 | 1-100 |
Response 200
{ "data": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Loading Dock East", "site_id": "b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b", "gateway_id": "8f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c", "connection_mode": "gateway", "type": "onvif", "status": "online", "active_tier": "main" } ], "next_cursor": null, "total": 1}Error responses
| Code | Body.error | Meaning |
|---|---|---|
| 401 | auth_required | Missing or invalid token |
| 403 | forbidden | Role insufficient |
| 429 | rate_limited | See /developer/rate-limits |
Examples
curl -H "Authorization: Bearer sk_live_abc123" \ "https://novavms.novalien.com/api/v1/cameras?site_id=b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b"const cameras = await novavms.cameras.list({ siteId: 'b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b',});cameras = client.cameras.list(site_id="b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b")POST /api/v1/cameras
Create a camera. Gateway-bound cameras validate ONVIF/RTSP credentials synchronously before returning; on failure the camera is rolled back and an error is returned. Direct-mode cameras register with go2rtc asynchronously.
Since: v1.0 Required role: operator
Request body
| Name | Type | Default | Constraints |
|---|---|---|---|
site_id | uuid | — | Required |
gateway_id | uuid | — | Required when connection_mode=gateway |
connection_mode | enum | gateway | gateway, direct |
name | string | — | 1-100 chars |
type | enum | — | rtsp, onvif |
rtsp_url | string | — | Required for type=rtsp |
rtsp_username | string | — | Optional |
rtsp_password | string | — | Optional |
host | string | — | Required for type=onvif |
port | int | 80 | ONVIF service port |
onvif_username | string | — | Required for type=onvif |
onvif_password | string | — | Required for type=onvif |
Response 201
{ "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Loading Dock East", "site_id": "b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b", "gateway_id": "8f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c", "connection_mode": "gateway", "type": "onvif", "status": "online", "created_at": "2026-04-21T14:05:00Z"}Error responses
| Code | Body.error | Meaning |
|---|---|---|
| 400 | validation_error | Missing field or gateway connection check failed |
| 403 | forbidden | Role insufficient |
| 404 | not_found | Site or gateway not in caller’s org |
Examples
curl -X POST https://novavms.novalien.com/api/v1/cameras \ -H "Authorization: Bearer sk_live_abc123" \ -H "Content-Type: application/json" \ -d '{"site_id":"b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b","gateway_id":"8f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c","connection_mode":"gateway","name":"Loading Dock East","type":"onvif","host":"10.0.0.63","port":2020,"onvif_username":"admin","onvif_password":"s3cret"}'const cam = await novavms.cameras.create({ siteId: 'b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b', gatewayId: '8f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c', connectionMode: 'gateway', name: 'Loading Dock East', type: 'onvif', host: '10.0.0.63', port: 2020, onvifUsername: 'admin', onvifPassword: 's3cret',});cam = client.cameras.create( site_id="b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b", gateway_id="8f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c", connection_mode="gateway", name="Loading Dock East", type="onvif", host="10.0.0.63", port=2020, onvif_username="admin", onvif_password="s3cret",)GET /api/v1/cameras/{id}
Return a single camera.
Since: v1.0 Required role: viewer (site-scoped)
Response 200
{ "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Loading Dock East", "site_id": "b5e9f3a1-2c4d-4e6f-8a1b-3c5d7e9f1a2b", "gateway_id": "8f1a2b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c", "connection_mode": "gateway", "type": "onvif", "status": "online", "stream_transport": "tcp", "active_tier": "main", "created_at": "2026-04-21T14:05:00Z"}Error responses
| Code | Body.error | Meaning |
|---|---|---|
| 401 | auth_required | Missing or invalid token |
| 403 | forbidden | Viewer outside site scope |
| 404 | not_found | Camera not in caller’s org |
Examples
curl -H "Authorization: Bearer sk_live_abc123" \ https://novavms.novalien.com/api/v1/cameras/550e8400-e29b-41d4-a716-446655440000const cam = await novavms.cameras.get('550e8400-e29b-41d4-a716-446655440000');cam = client.cameras.get("550e8400-e29b-41d4-a716-446655440000")PATCH /api/v1/cameras/{id}
Update camera metadata or credentials.
Since: v1.0 Required role: operator
Request body
| Name | Type | Default | Constraints |
|---|---|---|---|
name | string | — | 1-100 chars |
site_id | uuid | — | Must exist in caller’s org |
rtsp_url | string | — | Triggers revalidation |
rtsp_username | string | — | Triggers revalidation |
rtsp_password | string | — | Triggers revalidation |
onvif_username | string | — | Triggers revalidation |
onvif_password | string | — | Triggers revalidation |
Response 200
Returns the updated camera object — same shape as GET /api/v1/cameras/{id}.
Error responses
| Code | Body.error | Meaning |
|---|---|---|
| 400 | validation_error | Credential change failed revalidation |
| 403 | forbidden | Role insufficient |
| 404 | not_found | Camera not in caller’s org |
Examples
curl -X PATCH https://novavms.novalien.com/api/v1/cameras/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer sk_live_abc123" \ -H "Content-Type: application/json" \ -d '{"name":"Loading Dock East (Rev 2)"}'await novavms.cameras.update('550e8400-e29b-41d4-a716-446655440000', { name: 'Loading Dock East (Rev 2)',});client.cameras.update( "550e8400-e29b-41d4-a716-446655440000", name="Loading Dock East (Rev 2)",)DELETE /api/v1/cameras/{id}
Soft-delete the camera. Events and recordings are preserved; the camera stops accepting streams.
Since: v1.0 Required role: operator
Response 204
Empty body.
Error responses
| Code | Body.error | Meaning |
|---|---|---|
| 403 | forbidden | Role insufficient |
| 404 | not_found | Camera not in caller’s org |
Examples
curl -X DELETE https://novavms.novalien.com/api/v1/cameras/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer sk_live_abc123"await novavms.cameras.delete('550e8400-e29b-41d4-a716-446655440000');client.cameras.delete("550e8400-e29b-41d4-a716-446655440000")POST /api/v1/cameras/{id}/trigger
Manually record a clip (“Record Clip” button, D49). One trigger per camera per 5 seconds.
Since: v1.2 Required role: operator
Request body
| Name | Type | Default | Constraints |
|---|---|---|---|
duration_sec | int | 15 | 5-60 |
note | string | — | Up to 500 chars; stored on the event |
Response 202
{ "event_id": "c1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f", "started_at": "2026-04-21T14:10:00Z", "expected_clip_duration_sec": 15}Error responses
| Code | Body.error | Meaning |
|---|---|---|
| 400 | ai_unavailable | Camera is not online |
| 403 | forbidden | Role insufficient |
| 404 | not_found | Camera not in caller’s org |
| 429 | rate_limited | Retry-After header set to 5 seconds |
Examples
curl -X POST https://novavms.novalien.com/api/v1/cameras/550e8400-e29b-41d4-a716-446655440000/trigger \ -H "Authorization: Bearer sk_live_abc123" \ -H "Content-Type: application/json" \ -d '{"duration_sec":30,"note":"Manager requested walkthrough"}'const ev = await novavms.cameras.triggerRecording( '550e8400-e29b-41d4-a716-446655440000', { durationSec: 30, note: 'Manager requested walkthrough' },);ev = client.cameras.trigger_recording( "550e8400-e29b-41d4-a716-446655440000", duration_sec=30, note="Manager requested walkthrough",)