Most operators use the web UI for daily work. This guide is for automation: scripting repetitive tasks, integrating with CI/CD pipelines, or building custom tooling on top of OpenWatch.
OpenWatch exposes 80+ REST endpoints under the /api prefix. All endpoints require JWT Bearer tokens unless noted otherwise.
For the full schema reference, see the Swagger UI at http://localhost:8000/api/docs (available when OPENWATCH_DEBUG=true).
Authentication
Log in
TOKEN=$(curl -s -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"yourpassword"}' | jq -r '.access_token')
Response includes access_token (1 hour) and refresh_token (7 days).
Refresh token
curl -s -X POST http://localhost:8000/api/auth/refresh \
-H "Authorization: Bearer $TOKEN"
Log out
curl -s -X POST http://localhost:8000/api/auth/logout \
-H "Authorization: Bearer $TOKEN"
All subsequent examples assume -H "Authorization: Bearer $TOKEN".
Hosts
| Method | Endpoint | Purpose |
|---|
| GET | /api/hosts/ | List all hosts |
| POST | /api/hosts/ | Add a host |
| GET | /api/hosts/{id} | Get host details |
| PUT | /api/hosts/{id} | Update host |
| DELETE | /api/hosts/{id} | Delete host |
| POST | /api/hosts/validate-credentials | Test SSH connectivity |
Add a host
curl -s -X POST http://localhost:8000/api/hosts/ \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"hostname": "rhel9-web01.example.com",
"ip_address": "10.0.1.50",
"port": 22,
"username": "openwatch",
"auth_method": "key",
"ssh_private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n..."
}'
Host groups
| Method | Endpoint | Purpose |
|---|
| GET | /api/host-groups/ | List groups |
| POST | /api/host-groups/ | Create group |
| PUT | /api/host-groups/{id} | Update group |
| DELETE | /api/host-groups/{id} | Delete group |
| POST | /api/host-groups/{id}/hosts | Assign hosts |
| POST | /api/host-groups/{id}/scan | Start group scan |
Scanning
Start a compliance scan
curl -s -X POST http://localhost:8000/api/scans/kensa/ \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"host_id": "550e8400-e29b-41d4-a716-446655440000",
"framework": "cis-rhel9-v2.0.0"
}'
Optional fields: framework, severity (list), category.
Scan endpoints
| Method | Endpoint | Purpose |
|---|
| GET | /api/scans/kensa/health | Engine health |
| GET | /api/scans/kensa/frameworks | Available frameworks |
| GET | /api/scans/kensa/compliance-state/{host_id} | Latest compliance state |
| GET | /api/scans/ | List all scans |
| GET | /api/scans/{scan_id} | Scan details |
| GET | /api/scans/{scan_id}/results | Scan results |
| GET | /api/scans/{scan_id}/failed-rules | Failed rules only |
| GET | /api/scans/{scan_id}/report/json | JSON report |
| GET | /api/scans/{scan_id}/report/csv | CSV report |
| GET | /api/scans/{scan_id}/report/html | HTML report |
Compliance posture
| Method | Endpoint | Purpose |
|---|
| GET | /api/compliance/posture?host_id={id} | Current posture |
| GET | /api/compliance/posture?host_id={id}&as_of=2026-01-15 | Historical posture |
| GET | /api/compliance/posture/history?host_id={id}&start_date=...&end_date=... | Posture over time |
| GET | /api/compliance/posture/drift?host_id={id}&start_date=...&end_date=... | Drift detection |
| POST | /api/compliance/posture/snapshot | Create manual snapshot |
Compliance exceptions
| Method | Endpoint | Purpose |
|---|
| GET | /api/compliance/exceptions | List exceptions |
| GET | /api/compliance/exceptions/summary | Exception statistics |
| POST | /api/compliance/exceptions | Request new exception |
| GET | /api/compliance/exceptions/{id} | Exception details |
| POST | /api/compliance/exceptions/{id}/approve | Approve (admin) |
| POST | /api/compliance/exceptions/{id}/reject | Reject (admin) |
| POST | /api/compliance/exceptions/{id}/revoke | Revoke (admin) |
| POST | /api/compliance/exceptions/check | Check if rule is excepted |
Create exception request
curl -s -X POST http://localhost:8000/api/compliance/exceptions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rule_id": "sshd-strong-ciphers",
"host_id": "550e8400-e29b-41d4-a716-446655440000",
"justification": "Legacy system requires weak cipher for 30 days",
"duration_days": 30
}'
Alerts
| Method | Endpoint | Purpose |
|---|
| GET | /api/compliance/alerts | List alerts |
| GET | /api/compliance/alerts/stats | Alert statistics |
| GET | /api/compliance/alerts/{id} | Alert details |
| POST | /api/compliance/alerts/{id}/acknowledge | Acknowledge |
| POST | /api/compliance/alerts/{id}/resolve | Resolve |
| GET | /api/compliance/alerts/thresholds | Get thresholds |
| PUT | /api/compliance/alerts/thresholds | Update thresholds |
Query parameters: status, severity, alert_type, host_id, page, per_page.
| Method | Endpoint | Purpose |
|---|
| POST | /api/compliance/remediation | Create remediation job |
| POST | /api/compliance/remediation/plan | Preview plan (dry-run) |
| POST | /api/compliance/remediation/check-rules | Check rule remediation support |
| GET | /api/compliance/remediation | List jobs |
| GET | /api/compliance/remediation/summary | Job statistics |
| GET | /api/compliance/remediation/{job_id} | Job details with results |
| GET | /api/compliance/remediation/{job_id}/results/{result_id}/steps | Step-level results |
| POST | /api/compliance/remediation/{job_id}/cancel | Cancel job |
| POST | /api/compliance/remediation/rollback | Rollback completed job |
curl -s -X POST http://localhost:8000/api/compliance/remediation \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"host_id": "550e8400-e29b-41d4-a716-446655440000",
"rule_ids": ["sshd-disable-root-login", "sshd-strong-ciphers"]
}'
Returns HTTP 202. The job executes asynchronously via Celery.
Audit and export
Saved queries
| Method | Endpoint | Purpose |
|---|
| GET | /api/compliance/audit/queries | List saved queries |
| POST | /api/compliance/audit/queries | Create saved query |
| GET | /api/compliance/audit/queries/{id} | Get query |
| PUT | /api/compliance/audit/queries/{id} | Update query |
| DELETE | /api/compliance/audit/queries/{id} | Delete query |
| POST | /api/compliance/audit/queries/preview | Preview results |
| POST | /api/compliance/audit/queries/{id}/execute | Execute saved query |
Exports
| Method | Endpoint | Purpose |
|---|
| GET | /api/compliance/audit/exports | List exports |
| POST | /api/compliance/audit/exports | Create export (json, csv, pdf) |
| GET | /api/compliance/audit/exports/{id} | Export details |
| GET | /api/compliance/audit/exports/{id}/download | Download file |
curl -s -X POST http://localhost:8000/api/compliance/audit/exports \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"query_id": "uuid-of-saved-query", "format": "csv"}'
Rules reference
| Method | Endpoint | Purpose |
|---|
| GET | /api/rules/reference | List rules (search, filter, paginate) |
| GET | /api/rules/reference/{rule_id} | Full rule details |
| GET | /api/rules/reference/stats | Rule statistics |
| GET | /api/rules/reference/frameworks | List frameworks |
| GET | /api/rules/reference/categories | List categories |
| GET | /api/rules/reference/variables | Configurable variables |
Query parameters: search, framework, category, severity, has_remediation, page, per_page.
Administration
User management
| Method | Endpoint | Purpose |
|---|
| GET | /api/users/ | List users |
| POST | /api/users/ | Create user (SUPER_ADMIN) |
| GET | /api/users/{id} | Get user |
| PUT | /api/users/{id} | Update user |
| DELETE | /api/users/{id} | Delete user |
SSH configuration
| Method | Endpoint | Purpose |
|---|
| GET | /api/ssh/settings/policy | Get SSH policy |
| POST | /api/ssh/settings/policy | Update SSH policy |
| GET | /api/ssh/settings/known-hosts | List known hosts |
| POST | /api/ssh/settings/known-hosts | Add known host |
| DELETE | /api/ssh/settings/known-hosts/{hostname} | Remove known host |
| GET | /api/ssh/settings/test-connectivity/{host_id} | Test connectivity |
System endpoints
| Method | Endpoint | Auth | Purpose |
|---|
| GET | /health | None | Application health |
| GET | /security-info | Admin | FIPS mode and encryption config |
| GET | /metrics | None | Prometheus metrics |
Error responses
| Code | Meaning |
|---|
| 400 | Bad request — invalid input or business rule violation |
| 401 | Unauthorized — missing or expired token |
| 402 | Payment required — OpenWatch+ license needed |
| 403 | Forbidden — insufficient role or permission |
| 404 | Not found |
| 422 | Validation error — field-level detail included |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Rate limits
- 100 requests per minute per authenticated user
- 1,000 requests per minute per source IP