Reference
External Monitoring
Integration reference for the read-only monitoring API: create a token, authenticate, and every endpoint's request and response for Prometheus and dashboards.
What It Is
The Sendense Hub Appliance (SHA) exposes a read-only monitoring API so you can feed your own monitoring system - a Prometheus scraper, a NOC dashboard, or any tool that reads HTTP - with the health and metrics the appliance already tracks: protection-pattern and replication health, per-VM backup and SLA status, Enterprise Block Archive (EBA) repository capacity and backlog, and an overall summary. There is a set of JSON endpoints and a Prometheus/OpenMetrics endpoint for scraping.
You connect it with a dedicated monitoring token that is separate from any user sign-in, so an external system never needs a person's credentials. Monitoring reads never trigger repository scans or other work on the appliance - they report the latest known state, and if a data source is briefly unavailable the endpoint returns a warning rather than failing.
This page is the integration reference: how to create a token, how to authenticate, and the request and response shape of every endpoint, grouped by the kind of data they return.
Base URL And Conventions
All endpoints are served over HTTPS on the appliance's normal interface - the same host and port as the web interface - under /api/v1/.
- Token-management endpoints are under /api/v1/settings/monitoring/.
- Monitoring data endpoints are under /api/v1/monitoring/.
- Most data endpoints accept an optional window query parameter - a duration such as 24h - which defaults to 24h and is capped at 2160h (90 days).
- Health-bearing responses carry a status of ok, warning, or critical, a generated_at timestamp, and a warnings array explaining any degraded state.
Authentication
Present the monitoring token as a bearer credential on every data request. Use a dedicated monitoring token - do not reuse a user's login session or any of the appliance's internal service credentials. A token only reaches the endpoints whose scopes it holds; a request without the required scope is rejected. Signed-in users can also read the same projections when their role grants monitoring read access, but the token flow is the intended path for unattended external systems.
GET /api/v1/monitoring/summary HTTP/1.1
Host: your-appliance-host
Authorization: Bearer sdmon_<prefix>_<secret>Scopes
Each scope grants exactly one endpoint. Grant a token only the scopes its integration needs.
Token Management
Monitoring tokens are created and managed under Settings, External Monitoring in the appliance web interface, or through the token-management endpoints. These endpoints require a signed-in user session: reading requires settings read permission; creating, rotating, and revoking require settings write permission. Monitoring tokens themselves cannot call these endpoints.
A token carries a name, one or more scopes, an optional IP allow-list of CIDR ranges it may connect from, and an optional expiry. GET /api/v1/settings/monitoring/tokens lists integrations without their secrets. POST /api/v1/settings/monitoring/tokens creates one. POST .../{id}/rotate issues a new secret and invalidates the old one. POST .../{id}/revoke disables a token permanently and returns { "success": true }.
{
"name": "NOC Prometheus",
"description": "Primary external monitoring poller",
"scopes": ["monitoring.summary.read", "monitoring.prometheus.read"],
"allowed_cidrs": ["10.0.0.0/8"],
"expires_at": "2026-10-04T12:00:00Z"
}{
"token": {
"id": "uuid",
"name": "NOC Prometheus",
"token_prefix": "9df4e0a5c7a81234",
"scopes": ["monitoring.summary.read", "monitoring.prometheus.read"],
"allowed_cidrs": ["10.0.0.0/8"],
"status": "active",
"created_at": "2026-07-06T12:00:00Z",
"secret": "sdmon_9df4e0a5c7a81234_<secret>"
}
}Copy the secret when it is shown
The full token (sdmon_<prefix>_<secret>) is returned only on create and rotate, in the response's secret field. The appliance stores only a one-way hash. If you lose it, rotate the token to issue a new secret - there is no way to read the existing one back.
Summary Endpoint
GET /api/v1/monitoring/summary - required scope monitoring.summary.read. Optional window (default 24h). Returns overall health across protection, pipeline, and secondary-copy activity. It does not expose per-VM lists or VM names. If a non-critical source is unavailable the endpoint still returns 200 OK with status: warning; if the appliance database is unreachable it returns status: critical.
{
"status": "ok",
"generated_at": "2026-07-06T12:05:00Z",
"window": "24h",
"sections": {
"overall": { "status": "ok", "message": "monitoring projection available" },
"database": { "status": "ok" },
"protection": { "status": "ok" },
"pipeline": { "status": "ok" },
"secondary_copy": { "status": "ok" }
},
"protection": {
"total_patterns": 4,
"active_patterns": 4,
"success_rate_percentage": 98.5,
"missed_sla_vms_24h": 0,
"avg_speed_mbps": 125.4,
"bytes_transferred_24h": 123456789
},
"backup_activity_24h": { "total": 20, "success": 19, "failed": 1, "success_rate": 95 },
"pipeline": {
"exceptions_24h": { "total": 0 },
"start_failures_24h": { "total": 0 },
"success_rate_trend": []
},
"secondary_copy": {
"success_rate_percentage": 100,
"active_transfers": 0,
"pending_queue": 0,
"success_rate_trend": []
},
"warnings": []
}Protection Patterns Endpoint
GET /api/v1/monitoring/protection-patterns - required scope monitoring.protection.read. Optional window (default 24h). Reports current protection-pattern health: per-pattern backup runs, SLA compliance, and incident counts, plus estate totals. It does not return VM names. SLA windows are counted only once a terminal result exists; pending and active windows are excluded from the denominator.
{
"status": "ok",
"generated_at": "2026-07-06T12:05:00Z",
"window": "24h",
"totals": {
"patterns": 4,
"enabled_patterns": 4,
"protected_vms": 42,
"backup_runs": 126,
"successful_backup_runs": 124,
"failed_backup_runs": 2,
"success_rate_percentage": 98.41,
"missed_sla_windows": 1,
"bytes_transferred": 9876543210,
"avg_speed_mbps": 730.5,
"incidents": 3
},
"patterns": [
{
"pattern_id": "pattern-prod",
"name": "Production",
"enabled": true,
"primary_backend": "eba",
"status": "critical",
"protected_vms": 30,
"backup_runs": {
"total": 90, "success": 88, "failed": 2, "running": 0,
"pending": 0, "warning": 0, "cancelled": 0,
"success_rate_percentage": 97.77
},
"sla": {
"windows": 90, "met": 89, "missed": 1,
"compliance_percentage": 98.88,
"last_missed_at": "2026-07-06T10:15:00Z"
},
"incidents": {
"backup_failures": 2, "missed_sla_windows": 1,
"execution_failures": 0, "total": 3
},
"bytes_transferred": 1234567890,
"avg_speed_mbps": 650.2,
"last_successful_at": "2026-07-06T11:00:00Z",
"last_failed_at": "2026-07-06T10:10:00Z"
}
],
"warnings": []
}Virtual Machines Endpoint
GET /api/v1/monitoring/vms - required scope monitoring.vm.read. Reports SLA, backup counts by retention boundary, and the latest validation-evidence state per protected VM. Evidence values are status-only; raw evidence bodies, screenshots, and paths are never exposed.
- window - optional duration; defaults to 24h.
- include_names - optional boolean. To receive VM names the token must also hold monitoring.vm_names.read; otherwise the appliance returns 403 Forbidden. When names are omitted, vm_name is absent and names_included is false.
{
"status": "ok",
"generated_at": "2026-07-06T12:05:00Z",
"window": "24h",
"names_included": true,
"totals": {
"vms": 42, "protected_vms": 42, "missed_sla_vms": 1,
"failed_backup_vms": 1, "evidence_issue_vms": 0,
"validation_issue_vms": 0, "bytes_transferred": 9876543210
},
"vms": [
{
"vm_context_id": "vm-ctx-1",
"vm_name": "app01",
"pattern_id": "pattern-prod",
"pattern_name": "Production",
"status": "ok",
"protection_enabled": true,
"pattern_enabled": true,
"sla": { "windows": 3, "met": 3, "missed": 0, "compliance_percentage": 100 },
"backups": {
"runs": { "total": 3, "success": 3, "failed": 0, "success_rate_percentage": 100 },
"boundaries": { "base": 0, "hourly": 3, "daily": 1, "weekly": 0, "monthly": 0, "yearly": 0, "unknown": 0 },
"bytes_transferred": 123456789,
"last_successful_at": "2026-07-06T11:00:00Z"
},
"evidence": {
"validation_enabled": true,
"mount_evidence_enabled": true,
"boot_evidence_enabled": true,
"validation_status": "passed",
"mount_status": "passed",
"boot_status": "passed",
"last_validation_at": "2026-07-06T11:05:00Z",
"last_mount_evidence_at": "2026-07-06T11:06:00Z",
"last_boot_evidence_at": "2026-07-06T11:07:00Z"
}
}
],
"warnings": []
}Replication Endpoint
GET /api/v1/monitoring/replication - required scope monitoring.replication.read. Reports replication-pattern health and per-VM replication SLA. As with the VM endpoint, include_names=true requires monitoring.vm_names.read. On appliances without replication configured, the endpoint returns status: warning with a warnings entry rather than declaring replication healthy. Totals de-duplicate by VM and target, so historical assignment rows do not inflate counts.
{
"status": "ok",
"generated_at": "2026-07-06T12:05:00Z",
"window": "24h",
"names_included": false,
"totals": {
"patterns": 2, "enabled_patterns": 2, "protected_vms": 20, "targets": 20,
"sync_runs": 60, "successful_sync_runs": 60, "failed_sync_runs": 0,
"success_rate_percentage": 100, "missed_sla_vms": 0,
"bytes_transferred": 1234567890, "avg_speed_mbps": 420.5
},
"patterns": [
{
"pattern_id": "dr-prod",
"name": "Prod DR",
"enabled": true,
"status": "ok",
"sync_interval_minutes": 60,
"protected_vms": 20,
"targets": 20,
"sync_runs": { "total": 60, "success": 60, "failed": 0, "success_rate_percentage": 100 },
"sla": { "windows": 20, "met": 20, "missed": 0, "compliance_percentage": 100 },
"bytes_transferred": 1234567890,
"avg_speed_mbps": 420.5,
"last_successful_at": "2026-07-06T11:45:00Z"
}
],
"vms": [
{
"vm_context_id": "vm-ctx-1",
"pattern_id": "dr-prod",
"pattern_name": "Prod DR",
"target_id": "target-1",
"status": "ok",
"assignment_status": "active",
"target_status": "ready",
"sync_enabled": true,
"last_sync_at": "2026-07-06T11:45:00Z",
"next_sync_at": "2026-07-06T12:45:00Z",
"overdue_seconds": 0,
"consecutive_failures": 0,
"sync_runs": { "total": 3, "success": 3, "failed": 0, "success_rate_percentage": 100 },
"bytes_transferred": 123456789,
"avg_speed_mbps": 420.5,
"last_successful_at": "2026-07-06T11:45:00Z"
}
],
"warnings": []
}EBA Repositories Endpoint
GET /api/v1/monitoring/eba - required scope monitoring.eba.read. Reports EBA repository health, capacity and storage accounting, cache state, and the passive retention/deletion backlog. It is rollup-only: a monitoring poll never triggers a repository scan, mount probe, or queue refresh. Raw repository errors, paths, bucket names, credentials, and provider configuration are never exposed.
{
"status": "warning",
"generated_at": "2026-07-06T12:05:00Z",
"totals": {
"repositories": 2, "active_repositories": 2, "error_repositories": 0,
"manifest_count": 1200, "vm_count": 42, "block_count": 900000,
"logical_bytes": 45000000000000, "stored_bytes": 12000000000000,
"pending_delete_objects": 250, "failed_delete_objects": 0,
"pending_delete_bytes": 104857600, "expired_manifest_backlog": 8,
"cache_size_bytes": 2000000000000, "cache_used_bytes": 1500000000000,
"capacity_total_bytes": 50000000000000,
"capacity_used_bytes": 12000000000000,
"capacity_available_bytes": 38000000000000
},
"repositories": [
{
"repository_id": "eba-primary",
"name": "Primary EBA",
"health": "warning",
"repository_status": "active",
"storage_mode": "local",
"storage_class": "ssd_cached",
"capability_status": "supported",
"capacity": {
"total_bytes": 50000000000000, "used_bytes": 12000000000000,
"available_bytes": 38000000000000, "logical_bytes": 45000000000000,
"stored_bytes": 12000000000000
},
"cache": {
"state": "attached", "size_bytes": 2000000000000,
"used_bytes": 1500000000000, "dirty_bytes": 100000000,
"sampled_at": "2026-07-06T12:04:00Z"
},
"backlog": {
"pending_delete_objects": 250, "failed_delete_objects": 0,
"pending_delete_bytes": 104857600, "expired_manifest_backlog": 8
},
"rollup": {
"manifest_count": 1200, "vm_count": 42, "block_count": 900000,
"latest_backup_at": "2026-07-06T11:00:00Z",
"stats_stale": false, "rebuild_status": "complete",
"stats_updated_at": "2026-07-06T12:00:00Z"
}
}
],
"warnings": []
}Prometheus And OpenMetrics
GET /api/v1/monitoring/metrics - required scope monitoring.prometheus.read. Optional window (default 24h). Returns aggregate metrics in Prometheus/OpenMetrics text format (text/plain; version=0.0.4). Point a Prometheus-compatible scraper at it with a token that holds monitoring.prometheus.read.
The output is deliberately aggregate-only. Metric families include sendense_monitoring_summary_*, sendense_monitoring_protection_*, sendense_monitoring_vm_*, sendense_monitoring_eba_*, and sendense_monitoring_replication_*, plus sendense_external_monitoring_up, sendense_external_monitoring_status_code{surface} (0=ok, 1=warning, 2=critical, 3=unknown), and sendense_external_monitoring_scrape_timestamp_seconds. Labels are limited to a small fixed set such as surface, state, and backup boundary.
scrape_configs:
- job_name: sendense
metrics_path: /api/v1/monitoring/metrics
scheme: https
authorization:
type: Bearer
credentials: sdmon_<prefix>_<secret>
static_configs:
- targets: ["your-appliance-host"]# HELP sendense_external_monitoring_up Monitoring endpoint reachable
sendense_external_monitoring_up 1
# HELP sendense_external_monitoring_status_code Surface status (0=ok,1=warning,2=critical,3=unknown)
sendense_external_monitoring_status_code{surface="protection"} 0
sendense_external_monitoring_status_code{surface="eba"} 1
sendense_external_monitoring_scrape_timestamp_seconds 1.7833344e+09
sendense_monitoring_protection_success_rate_percent 98.41
sendense_monitoring_protection_protected_vms 42
sendense_monitoring_vm_missed_sla 1
sendense_monitoring_eba_capacity_used_bytes 12000000000000
sendense_monitoring_replication_success_rate_percent 100VM Names Are Treated As Sensitive
VM names are inventory data, so they are never returned by default. To include them in the JSON VM or replication endpoints, the token must hold monitoring.vm_names.read and the request must set include_names=true; otherwise the appliance responds with 403 Forbidden. VM names are never emitted in the Prometheus output as labels or samples. When an external system needs to map metrics to named VMs, read the JSON VM endpoint with include_names=true and keep that mapping in the monitoring system.
IP Restrictions And Reverse Proxies
An IP allow-list is checked against the normalized address of the client that connected. With the appliance's bundled front-end proxy, the real client address is taken from the standard forwarding headers (X-Real-IP, then the first valid X-Forwarded-For) because the request reaches the application from the local proxy; if a request arrives from anywhere else, those headers are ignored and the direct connection address is used, so a client cannot spoof its source.
If you put your own reverse proxy in front of the appliance, either keep the bundled local proxy in the path or add your proxy's address to the token's allow-list. Do not add loopback addresses (127.0.0.1/32 or ::1/128) to a token unless the monitoring system genuinely connects from the appliance itself.
Related Docs