REST API (/api/v1/)
ChannelWatch ships a versioned REST API at /api/v1/. New integrations should target the versioned endpoints documented here.
Authentication
Section titled “Authentication”Fresh installs choose secure login or trusted-network no-auth before DVR setup. Secure login uses a cookie-backed session and CSRF token. Upgraded installations can still use the legacy shared X-API-Key compatibility path.
X-API-Key: <api-key>If trusted-network no-auth is configured, or CW_DISABLE_AUTH=true temporarily overrides the configured mode, the API is accessible without credentials.
DVR endpoints
Section titled “DVR endpoints”These endpoints return data scoped to configured DVRs. Use GET /api/v1/dvrs to discover valid DVR IDs.
List all DVRs
Section titled “List all DVRs”GET /api/v1/dvrsReturns configured, non-deleted DVR records. The current response model is a small list item shape:
[ { "id": "dvr_abc12345", "name": "Living Room", "host": "192.168.1.100", "port": 8089, "enabled": true }]The list response sticks to the small id/name/host/port/enabled shape shown above.
DVR details
Section titled “DVR details”GET /api/v1/dvrs/{dvr_id}Returns a richer DVRStatus payload for one DVR. The current fields include:
id,name,host,portconnectedversion,version_compatible,version_warningdisk_usage_percent,disk_total_gb,disk_free_gblibrary_shows,library_movies,library_episodesmonitoring_status,monitoring_ready,monitoring_reasonfreshness_status,last_freshness_at,last_event_at,freshness_age_seconds,stale_threshold_seconds
Example response:
{ "id": "dvr_abc12345", "name": "Living Room", "host": "192.168.1.100", "port": 8089, "connected": true, "version": "2025.06.15", "version_compatible": true, "version_warning": null, "disk_usage_percent": 42, "disk_total_gb": 2000.0, "disk_free_gb": 1160.0, "library_shows": 85, "library_movies": 120, "library_episodes": 940, "monitoring_status": "healthy", "monitoring_ready": true, "monitoring_reason": null, "freshness_status": "fresh", "last_freshness_at": "2026-04-21T07:00:00+00:00", "last_event_at": "2026-04-21T06:59:45+00:00", "freshness_age_seconds": 15.0, "stale_threshold_seconds": 300}Per-DVR streams
Section titled “Per-DVR streams”GET /api/v1/dvrs/{dvr_id}/streamsReturns an aggregate stream snapshot for one DVR. The current payload shape is:
dvr_id,dvr_nametotalwatching- array of objects withdevice,channel, andimagerecording- array of objects withtitleanduntilsubtitleimage
Example response:
{ "dvr_id": "dvr_abc12345", "dvr_name": "Living Room", "total": 2, "watching": [ { "device": "Apple TV", "channel": "ESPN", "image": "https://example.invalid/image.jpg" } ], "recording": [ { "title": "Evening News", "until": "7:30 PM" } ], "subtitle": "1 watching, 1 recording", "image": "https://example.invalid/image.jpg"}This endpoint is not a session-ID-oriented stream list.
Per-DVR system info
Section titled “Per-DVR system info”GET /api/v1/dvrs/{dvr_id}/system-infoReturns current DVR status plus storage and library summary fields:
dvr_id,dvr_name,host,portconnectedversion,version_compatible,version_warningdisk_usage_percent,disk_usage_gb,disk_total_gb,disk_free_gb,disk_severitylibrary_shows,library_movies,library_episodes
It does not expose raw storage-path details.
Per-DVR activity history
Section titled “Per-DVR activity history”GET /api/v1/dvrs/{dvr_id}/activity-historyReturns activity history for one DVR. The route also supports pagination and filtering query parameters such as offset, limit, type, search, and sort.
Per-DVR upcoming recordings
Section titled “Per-DVR upcoming recordings”GET /api/v1/dvrs/{dvr_id}/recordings/upcomingReturns upcoming recordings for one DVR.
Per-DVR health
Section titled “Per-DVR health”GET /api/v1/dvrs/{dvr_id}/healthReturns the current DvrHealthResponse snapshot for one DVR. The current response fields are:
dvr_id,dvr_name,host,portconnectedversion,version_compatible,version_warningdisk_status,disk_free_gb,disk_total_gblast_checked,last_event_atlast_freshness_at,last_freshness_source,freshness_age_seconds,freshness_statusmonitoring_status,monitoring_ready,monitoring_reasonsession_state_size,recent_alert_rate
Example response:
{ "dvr_id": "dvr_abc12345", "dvr_name": "Living Room", "host": "192.168.1.100", "port": 8089, "connected": true, "version": "2025.06.15", "version_compatible": true, "version_warning": null, "disk_status": "normal", "disk_free_gb": 1160.0, "disk_total_gb": 2000.0, "last_checked": "2026-04-21T07:05:00+00:00", "last_event_at": "2026-04-21T06:59:45+00:00", "last_freshness_at": "2026-04-21T07:05:00+00:00", "last_freshness_source": "watchdog", "freshness_age_seconds": 15.0, "freshness_status": "fresh", "monitoring_status": "healthy", "monitoring_ready": true, "monitoring_reason": null, "session_state_size": 3, "recent_alert_rate": 4.0}Discovery endpoint
Section titled “Discovery endpoint”POST /api/v1/discovery/scanTriggers an mDNS scan and returns the discovery helper response:
{ "servers": [ { "host": "192.168.1.120", "port": 8089, "display_name_suggestion": "Basement DVR" } ], "manual_add_available": true, "message": null}When nothing new is found, servers is empty and message contains the reason or operator guidance.
This route is not a generic anonymous scan endpoint. It uses the backend auth path and, when RBAC is enabled, requires at least the operator role.
Maintenance windows endpoint
Section titled “Maintenance windows endpoint”GET /api/v1/maintenance-windowsReturns advisory gaps between known recording jobs for each enabled DVR. The endpoint accepts:
minimum_minutesfrom1to1440, defaulting to60daysfrom1to31, defaulting to7start_hourfrom0to23end_hourfrom0to24; a value earlier thanstart_hourcreates an overnight rangeweekdaysas comma-separated local weekdays, where Monday is0and Sunday is6dvr_idto limit the result to one configured DVR
Each DVR result includes its status, the last verified schedule boundary, and any safe windows before that boundary. Unreachable, empty, malformed, or unobserved schedule periods are never reported as free time.
See Maintenance Windows for the Dashboard controls and safety limits.
Update Center endpoints
Section titled “Update Center endpoints”These routes power Settings > Updates. They require admin access when auth is enabled. If CW_DISABLE_AUTH=true, anyone who can reach the UI can use them.
GET /api/v1/update/statusPOST /api/v1/update/checkPOST /api/v1/update/applyGET /api/v1/update/jobs/{job_id}POST /api/v1/update/rollbackKey behaviors:
GET /api/v1/update/statusreturns the current app version, runtime ABI, last trusted manifest, last update job, rollback availability, and auth-disabled warning state.POST /api/v1/update/checkfetches the trusted public ChannelWatch update manifest.POST /api/v1/update/applyverifies the signed manifest, signed bundle, SHA256 digest, runtime ABI, settings schema, and bundle allowlist before activating a compatible app update.GET /api/v1/update/jobs/{job_id}returns the persisted last update operation when the ID matches.POST /api/v1/update/rollbackrestores the previous active bundle pointer, or falls back to the image app, then restarts ChannelWatch.
Image-required releases return a structured conflict instead of attempting an unsafe in-app update.
Auth and security endpoints
Section titled “Auth and security endpoints”The current backend exposes these auth and security routes:
POST /api/v1/auth/loginPOST /api/v1/auth/logoutGET /api/v1/auth/whoamiPOST /api/v1/auth/change-credentialsGET /api/v1/auth/setup-statusPOST /api/v1/auth/setupGET /api/v1/security/statusKey behaviors:
POST /api/v1/auth/loginreturns the authenticated username, role, and a CSRF token, and sets thechannelwatch_sessioncookie.POST /api/v1/auth/logoutinvalidates the current session and clears the cookie.GET /api/v1/auth/whoamireturns the current session identity when RBAC is enabled and the cookie is valid.POST /api/v1/auth/change-credentialslets the signed-in user change their own username or password.GET /api/v1/auth/setup-statusreports whether the fresh-install security choice is still required and listsrbacandnoneas available setup modes.POST /api/v1/auth/setupeither creates the first admin for secure login or persists the trusted-network no-auth choice.GET /api/v1/security/statusreports the current security mode, whether RBAC is enabled, whether the shared API key is configured, whether API-key fallback is active, whether session setup is still required, and whether stored per-DVR API keys are encrypted at rest.
The auth routes are auth-exempt so a first login or first-admin setup can happen without an existing session. They are still RBAC-aware: for example, POST /api/v1/auth/login returns 501 when RBAC is disabled.
Related pages
Section titled “Related pages”- Security modes - current auth and access behavior
- API Keys - create and manage API-key access
- Per-DVR Health - endpoint details for DVR health snapshots
- Health probes -
/api/healthand/healthz/*response semantics - Prometheus metrics - the current
/metricssurface - Maintenance Windows - advisory recording-schedule gaps and their limits
- Updating ChannelWatch - Update Center behavior and image-required releases