Skip to content

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

NameTypeDefaultConstraints
site_iduuidFilters to the given site
gateway_iduuidFilters to cameras bound to a gateway
statusenumonline, offline, pending, error, disabled
typeenumrtsp, onvif
connection_modeenumgateway, direct
cursorstringnullPagination cursor
limitint201-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

CodeBody.errorMeaning
401auth_requiredMissing or invalid token
403forbiddenRole insufficient
429rate_limitedSee /developer/rate-limits

Examples

Terminal window
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

NameTypeDefaultConstraints
site_iduuidRequired
gateway_iduuidRequired when connection_mode=gateway
connection_modeenumgatewaygateway, direct
namestring1-100 chars
typeenumrtsp, onvif
rtsp_urlstringRequired for type=rtsp
rtsp_usernamestringOptional
rtsp_passwordstringOptional
hoststringRequired for type=onvif
portint80ONVIF service port
onvif_usernamestringRequired for type=onvif
onvif_passwordstringRequired 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

CodeBody.errorMeaning
400validation_errorMissing field or gateway connection check failed
403forbiddenRole insufficient
404not_foundSite or gateway not in caller’s org

Examples

Terminal window
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

CodeBody.errorMeaning
401auth_requiredMissing or invalid token
403forbiddenViewer outside site scope
404not_foundCamera not in caller’s org

Examples

Terminal window
curl -H "Authorization: Bearer sk_live_abc123" \
https://novavms.novalien.com/api/v1/cameras/550e8400-e29b-41d4-a716-446655440000
const 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

NameTypeDefaultConstraints
namestring1-100 chars
site_iduuidMust exist in caller’s org
rtsp_urlstringTriggers revalidation
rtsp_usernamestringTriggers revalidation
rtsp_passwordstringTriggers revalidation
onvif_usernamestringTriggers revalidation
onvif_passwordstringTriggers revalidation

Response 200

Returns the updated camera object — same shape as GET /api/v1/cameras/{id}.

Error responses

CodeBody.errorMeaning
400validation_errorCredential change failed revalidation
403forbiddenRole insufficient
404not_foundCamera not in caller’s org

Examples

Terminal window
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

CodeBody.errorMeaning
403forbiddenRole insufficient
404not_foundCamera not in caller’s org

Examples

Terminal window
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

NameTypeDefaultConstraints
duration_secint155-60
notestringUp 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

CodeBody.errorMeaning
400ai_unavailableCamera is not online
403forbiddenRole insufficient
404not_foundCamera not in caller’s org
429rate_limitedRetry-After header set to 5 seconds

Examples

Terminal window
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",
)