API Reference
The Proxima Console backend exposes a RESTful API under the /api/v1/ prefix. All endpoints return JSON and follow a consistent response envelope format.
The full API is documented with OpenAPI/Swagger and available as an interactive explorer at Swagger UI wherever debug endpoints are enabled. Use it to browse endpoints, view request/response schemas, and try API calls directly. Note that both /swagger/* and /metrics are served only when PROXIMA_ENABLE_DEBUG_ENDPOINTS=true; they return 404 in environments where debug endpoints are disabled.
Authentication
The API supports two authentication modes on all /api/v1/* routes:
- JWT Bearer token —
Authorization: Bearer <jwt>(user login sessions) - API Key header —
X-API-Key: <key>(service accounts)
Auth endpoints under /api/v1/auth/ have their own rate limit (5/min per IP). See the Authentication page for full details on login, MFA, password flows, and session management.
Public endpoints (no authentication required):
GET /healthzGET /readyzGET /metrics— only whenPROXIMA_ENABLE_DEBUG_ENDPOINTS=true(see note above)POST /api/v1/webhooks/{gitlab,github,argocd}/{token}— Webhook receivers (token-authenticated)POST /api/v1/alerts/webhook/alertmanager/{token}— Alertmanager receiver (token-authenticated)POST /api/v1/twilio/voice/twiml/{callID},/twilio/voice/gather,/twilio/voice/status— Twilio voice webhooks (authenticated byX-Twilio-Signature)
Request Limits
All endpoints that accept a JSON request body enforce a 1 MB size limit. Requests exceeding this limit receive a 413 Request Entity Too Large response. This is enforced globally via the DecodeJSON helper.
Slug Validation
Fields that represent URL-safe identifiers (e.g., client slug, environment slug) must match the following format:
- Lowercase alphanumeric characters and hyphens only
- 1–63 characters long
- Must start and end with an alphanumeric character
- Pattern:
^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$
Invalid slugs receive a 400 Bad Request response with a descriptive error message.
Response Format
Success (single resource)
{
"data": {
"id": "c5f8a2b0-1234-4abc-9def-567890abcdef",
"name": "Acme Corp",
"created_at": "2025-01-15T10:30:00Z"
}
}
Success (list)
{
"data": [
{ "id": "...", "name": "Acme Corp" },
{ "id": "...", "name": "Globex Inc" }
],
"meta": {
"total": 45,
"page": 1,
"per_page": 20
}
}
Error
{
"error": {
"code": "not_found",
"message": "Client with ID 'abc' not found",
"request_id": "a1b2c3d4-5678-49ab-cdef-0123456789ab"
}
}
Error Codes
| Code | HTTP Status | When |
|---|---|---|
bad_request | 400 | Invalid input, malformed JSON, validation failure |
unauthorized | 401 | Missing or invalid authentication token |
forbidden | 403 | Insufficient permissions for the requested operation |
mfa_enrollment_required | 403 | Account requires MFA enrollment before access is granted |
not_found | 404 | Requested entity does not exist |
conflict | 409 | Duplicate entry or conflicting state |
request_too_large | 413 | Request body exceeds the 1 MB limit |
internal_error | 500 | Unexpected server error |
Pagination
List endpoints support pagination via query parameters:
| Parameter | Default | Max | Description |
|---|---|---|---|
page | 1 | — | Page number (1-indexed) |
per_page | 20 | 100 | Items per page |
Example:
GET /api/v1/clients?page=2&per_page=50
Filtering and Sorting
List endpoints support filtering and sorting via query parameters:
| Parameter | Example | Description |
|---|---|---|
client_id | ?client_id=abc | Filter by client ID |
status | ?status=online | Filter by status |
sort | ?sort=hostname | Field to sort by |
order | ?order=asc | Sort direction (asc or desc) |
Date Format
All dates are returned in UTC using ISO 8601 format:
2025-01-15T10:30:00Z
Endpoints
Clients
List Clients
GET /api/v1/clients
Returns a paginated list of all clients.
Query Parameters: page, per_page, sort, order
Response: 200 OK
{
"data": [
{
"id": "c5f8a2b0-...",
"name": "Acme Corp",
"slug": "acme-corp",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
],
"meta": { "total": 5, "page": 1, "per_page": 20 }
}
Create Client
POST /api/v1/clients
Request Body:
{
"name": "Acme Corp",
"slug": "acme-corp"
}
Response: 201 Created
{
"data": {
"id": "c5f8a2b0-...",
"name": "Acme Corp",
"slug": "acme-corp",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
}
Get Client
GET /api/v1/clients/:id
Response: 200 OK
Returns a single client by ID.
Update Client
PUT /api/v1/clients/:id
Request Body:
{
"name": "Acme Corporation"
}
Response: 200 OK
Delete Client
DELETE /api/v1/clients/:id
Response: 204 No Content
Environments
List Environments for a Client
GET /api/v1/clients/:id/environments
Returns all environments belonging to the specified client.
Query Parameters: page, per_page
Response: 200 OK
Hosts
List Hosts for an Environment
GET /api/v1/environments/:id/hosts
Returns all hosts in the specified environment.
Query Parameters: page, per_page, status, sort, order
Response: 200 OK
Host Details
These endpoints return detailed inventory data collected by agents for a specific host.
Services
GET /api/v1/hosts/:id/services
Returns all services running on the host.
Packages
GET /api/v1/hosts/:id/packages
Returns all installed packages on the host.
Ports
GET /api/v1/hosts/:id/ports
Returns all open/listening ports on the host.
Network Interfaces
GET /api/v1/hosts/:id/interfaces
Returns all network interfaces on the host.
Users
GET /api/v1/hosts/:id/users
Returns all system users on the host.
Processes
GET /api/v1/hosts/:id/processes?page=1&per_page=50
Returns the current process list for the host, sorted by CPU usage (descending). Supports pagination via page and per_page query parameters.
Response: 200 OK — Paginated list of processes with PID, name, command, username, state, ppid, threads, cpu_percent, memory_percent, memory_rss_bytes, memory_vms_bytes, and started_at.
Process Metrics (Drill-Down)
GET /api/v1/hosts/:id/processes/:pid/metrics
Returns CPU, memory, RSS, and thread time-series data for a specific process. Only processes that are in the top 20 by CPU usage at collection time have historical metrics in VictoriaMetrics.
Query Parameters:
| Parameter | Required | Default | Description |
|---|---|---|---|
process_name | Yes | — | Process name (for disambiguation on PID reuse) |
start | No | 1 hour ago | Start time (RFC3339) |
end | No | now | End time (RFC3339) |
Response: 200 OK
{
"data": {
"cpu_usage": [{ "time": "...", "avg_value": 0.15, "min_value": 0.1, "max_value": 0.2, "sample_count": 1 }],
"memory_usage": [{ "time": "...", "avg_value": 0.05, "min_value": 0.04, "max_value": 0.06, "sample_count": 1 }],
"memory_rss": [{ "time": "...", "avg_value": 52428800, "min_value": 50000000, "max_value": 55000000, "sample_count": 1 }],
"threads": [{ "time": "...", "avg_value": 4, "min_value": 4, "max_value": 4, "sample_count": 1 }]
}
}
Container Metrics (Drill-Down)
GET /api/v1/hosts/:id/containers/:containerID/metrics
Returns CPU, memory, network, and block I/O time-series data for a specific Docker container. Gauge metrics are returned as-is; counter metrics (network, block I/O) are automatically converted to per-second rates.
Query Parameters:
| Parameter | Required | Default | Description |
|---|---|---|---|
start | No | 1 hour ago | Start time (RFC3339) |
end | No | now | End time (RFC3339) |
Response: 200 OK
{
"data": {
"cpu_usage": [],
"memory_used": [],
"memory_limit": [],
"memory_usage": [],
"network_receive": [],
"network_transmit": [],
"block_read": [],
"block_write": []
}
}
Each field contains an array of MetricDataPoint objects with time, avg_value, min_value, max_value, and sample_count.
Security (Composite)
GET /api/v1/hosts/:id/security
Returns a composite security overview for the host, fetching firewall rules, TLS certificates, loaded kernel modules, and security configuration items in parallel via errgroup.
Response: 200 OK
{
"data": {
"firewall_rules": [
{
"id": "...", "host_id": "...", "chain": "INPUT", "rule_number": 1,
"target": "ACCEPT", "protocol": "tcp", "port": "22",
"tool": "iptables", "table_name": "filter",
"rule_text": "-A INPUT -p tcp --dport 22 -j ACCEPT"
}
],
"certificates": [
{
"id": "...", "host_id": "...", "subject": "CN=example.com",
"issuer": "CN=Let's Encrypt Authority X3",
"not_before": "2026-01-01T00:00:00Z", "not_after": "2026-04-01T00:00:00Z",
"fingerprint_sha256": "AB:CD:EF:...", "is_ca": false,
"key_algorithm": "RSA", "key_bits": 2048
}
],
"kernel_modules": [
{
"id": "...", "host_id": "...", "name": "ext4",
"size_bytes": 757760, "instances": 1, "used_by": []
}
],
"security_items": [
{
"id": "...", "host_id": "...", "category": "ssh",
"key": "PermitRootLogin", "value": "no"
}
]
}
}
Cron Jobs
GET /api/v1/hosts/:id/cron-jobs?page=1&per_page=50
Returns scheduled tasks (crontab entries, cron.d files, and systemd timers) for the host. Supports pagination.
Response: 200 OK
{
"data": [
{
"id": "...", "host_id": "...", "username": "root",
"schedule": "0 2 * * *", "command": "/usr/local/bin/backup.sh",
"source": "crontab", "is_active": true
}
],
"meta": { "page": 1, "per_page": 50, "total": 3 }
}
GPU Devices
GET /api/v1/hosts/:id/gpu-devices
Returns GPU hardware devices detected on the host. Only populated for hosts with discrete GPUs (NVIDIA, AMD, Intel).
Response: 200 OK
{
"data": [
{
"id": "...", "host_id": "...", "device_index": 0,
"name": "NVIDIA A100", "vendor": "NVIDIA",
"driver_version": "550.127.05", "memory_total_bytes": 42949672960,
"pci_bus_id": "0000:05:00.0", "architecture": "Ampere"
}
]
}
Metrics
Metrics endpoints return time-series data collected by agents. They are nested under hosts as sub-resources.
List Metric Names
GET /api/v1/hosts/:id/metrics
Returns all distinct metric names collected for a host (e.g. cpu_usage_ratio, disk_used_ratio).
Response: 200 OK
{
"data": ["cpu_usage_ratio", "disk_used_ratio", "memory_used_ratio"]
}
Query Metric Data Points
GET /api/v1/hosts/:id/metrics/:metricName
Returns time-series data points for a specific metric. For ranges ≤6h, returns 1-minute buckets from the raw table. For longer ranges, returns hourly aggregates.
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
start | 1 hour ago | Start time (RFC3339) |
end | now | End time (RFC3339) |
labels_key | "" | Filter by labels key (e.g. device=sda1,mount=/) |
Response: 200 OK
{
"data": [
{
"time": "2026-02-16T10:00:00Z",
"avg_value": 45.2,
"min_value": 30.1,
"max_value": 62.8,
"sample_count": 4
}
]
}
List Metric Series
GET /api/v1/hosts/:id/metrics/:metricName/series
Returns distinct labels_key values for a metric, enabling discovery of labeled series (e.g. per-disk, per-network-interface).
Response: 200 OK
{
"data": ["", "device=sda1,mount=/", "device=sdb1,mount=/data"]
}
Batch Query Latest Metrics
GET /api/v1/hosts/metrics/latest
Returns the most recent value for each (host, metric) pair. Designed for the hosts list page to fetch utilization data for all online hosts in a single request instead of per-host calls.
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
host_ids | Yes | Comma-separated host IDs (UUIDs) |
metrics | Yes | Comma-separated metric names |
The query is bounded to the last hour — only metrics recorded within the past 60 minutes are returned. Input is limited to 100 host IDs and 50 metric names per request.
Response: 200 OK
{
"data": [
{
"host_id": "c5f8a2b0-1234-4abc-9def-567890abcdef",
"metric_name": "cpu_usage_ratio",
"value": 0.725,
"time": "2026-02-16T10:59:00Z"
},
{
"host_id": "c5f8a2b0-1234-4abc-9def-567890abcdef",
"metric_name": "memory_used_ratio",
"value": 0.55,
"time": "2026-02-16T10:59:00Z"
}
]
}
Errors:
400 Bad Request— missinghost_idsormetrics, invalid UUID, no valid metric names after parsing, or exceeding input limits (100 hosts, 50 metrics)
Integrations
List All Integrations
GET /api/v1/integrations
Returns all known integration types with host count and status summary.
Get Integration
GET /api/v1/integrations/:id
Returns a single integration type by ID (e.g., postgresql).
List Hosts for an Integration
GET /api/v1/integrations/:id/hosts
Returns all hosts running the specified integration, including per-collector status and runtime configuration.
Response: 200 OK
{
"data": [
{
"id": "hi-abc123",
"host_id": "host-uuid",
"integration_id": "postgresql",
"collector_name": "pg-main",
"status": "ok",
"status_message": "",
"enabled": true,
"config": {
"max_connections": {
"value": "100",
"source": "configuration file",
"category": "Connections and Authentication"
},
"shared_buffers": {
"value": "16384",
"unit": "8kB",
"source": "configuration file",
"category": "Resource Usage / Memory"
}
},
"hostname": "db-01",
"last_seen_at": "2026-02-20T10:00:00Z"
}
]
}
The config field contains runtime configuration parameters collected by the agent (e.g., PostgreSQL pg_settings). It is a JSON object keyed by parameter name, with each value containing value, unit (optional), source, and category fields. The config is updated every 5 minutes and preserved across heartbeats when no new config data is available.
List Integrations for a Host
GET /api/v1/hosts/:id/integrations
Returns all integrations running on a specific host with collector status and config.
List Integrations for a Client
GET /api/v1/clients/:id/integrations
Returns all integrations across all hosts belonging to a client.
Search (PQL)
The search API uses the Proxima Query Language (PQL) — a custom query language for searching across infrastructure entities. PQL is parsed by a recursive descent parser, compiled to an AST, and translated to parameterized SQL. Results are scoped to the authenticated user's accessible clients.
Search Hosts
GET /api/v1/search?q=host.os ~ "Ubuntu*" AND tag.tier = "critical"
Returns a paginated list of hosts matching the PQL query.
Query Parameters:
| Parameter | Default | Description |
|---|---|---|
q | — (required) | PQL query string |
page | 1 | Page number |
per_page | 20 | Items per page (max 100) |
format | json | Response format: json or csv |
Response: 200 OK
{
"data": [
{
"id": "host-uuid",
"hostname": "web-01",
"ip_address": "10.0.1.5",
"os": "Ubuntu 24.04",
"arch": "amd64",
"agent_status": "online",
"tags": { "role": "web" }
}
],
"meta": { "total": 12, "page": 1, "per_page": 20 }
}
When format=csv, returns Content-Type: text/csv with host data as CSV download.
Count Matching Hosts
GET /api/v1/search/count?q=host.agent_status = "online"
Returns only the count of matching hosts (faster than full search).
Response: 200 OK
{ "data": { "count": 42 } }
List Searchable Fields
GET /api/v1/search/fields
Returns all available PQL fields with their prefix, name, type, and supported operators. Useful for building autocomplete UIs.
Response: 200 OK
{
"data": [
{ "prefix": "host", "name": "hostname", "type": "string", "operators": ["=", "!=", "~", "IN", "NOT IN"] },
{ "prefix": "host", "name": "cpu_cores", "type": "number", "operators": ["=", "!=", ">", "<", ">=", "<=", "IN", "NOT IN"] },
{ "prefix": "tag", "name": "*", "type": "string", "operators": ["=", "!=", "~", "IN", "NOT IN", "EXISTS"] }
]
}
Validate PQL Query
POST /api/v1/search/validate
Validates PQL syntax without executing the query.
Request Body:
{ "query": "host.os = \"Ubuntu\"" }
Response: 200 OK
{ "data": { "valid": true, "error": "" } }
Invalid queries return the parse error with position information:
{ "data": { "valid": false, "error": "expected value at position 12, got EOF" } }
Aggregate Results
GET /api/v1/search/aggregate?q=host.agent_status = "online"&group_by=host.os
Groups matching hosts by a field and returns counts.
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
q | Yes | PQL query string |
group_by | Yes | Field to group by (must be a host.* field) |
Response: 200 OK
{
"data": [
{ "value": "Ubuntu 24.04", "count": 15 },
{ "value": "Debian 12", "count": 8 }
]
}
PQL Quick Reference
Field prefixes: host.*, label.* (agent labels from hosts.tags), tag.* (user-defined entity tags), service.*, container.*, package.*
Operators: =, !=, ~ (glob wildcard — * matches any chars), >, <, >=, <=, IN (...), NOT IN (...), EXISTS
Combinators: AND, OR, NOT, parenthesized grouping ()
Examples:
host.os = "Ubuntu 24.04"
host.arch IN ("amd64", "arm64")
host.hostname ~ "web-*"
service.name = "nginx" AND host.agent_status = "online"
label.role = "web" AND tag.tier = "production"
host.cpu_cores > 4 AND host.memory_total_bytes > 8000000000
NOT tag.owner EXISTS
(service.name = "postgresql" OR service.name = "mysql") AND host.os ~ "Ubuntu*"
Saved Searches
Save PQL queries for quick access. Users see their own searches plus shared searches.
List Saved Searches
GET /api/v1/saved-searches?page=1&per_page=20
Returns the current user's saved searches plus all shared searches.
Response: 200 OK
{
"data": [
{
"id": "search-uuid",
"user_id": "user-uuid",
"name": "Ubuntu production servers",
"query": "host.os ~ \"Ubuntu*\" AND tag.tier = \"production\"",
"description": "All Ubuntu hosts tagged as production tier",
"is_shared": true,
"created_at": "2026-02-26T10:00:00Z",
"updated_at": "2026-02-26T10:00:00Z"
}
],
"meta": { "total": 3, "page": 1, "per_page": 20 }
}
Create Saved Search
POST /api/v1/saved-searches
Saves a PQL query. The query is validated before saving.
Request Body:
{
"name": "Ubuntu production servers",
"query": "host.os ~ \"Ubuntu*\" AND tag.tier = \"production\"",
"description": "All Ubuntu hosts tagged as production tier",
"is_shared": true
}
Response: 201 Created
Get Saved Search
GET /api/v1/saved-searches/:id
Returns a saved search by ID. Private (non-shared) searches are only visible to the owner and super admins.
Response: 200 OK
Update Saved Search
PUT /api/v1/saved-searches/:id
Updates a saved search. Only the owner or a super admin can update.
Request Body: Same as create.
Response: 200 OK
Delete Saved Search
DELETE /api/v1/saved-searches/:id
Deletes a saved search. Only the owner or a super admin can delete.
Response: 204 No Content
Admin: Users
List Users
GET /api/v1/users
Returns a paginated list of all users. Requires users:read permission.
Query Parameters: page, per_page
Response: 200 OK
{
"data": [
{
"id": "user-uuid",
"email": "[email protected]",
"display_name": "Jane Doe",
"status": "active",
"is_super_admin": false,
"mfa_enabled": true,
"last_login_at": "2026-02-23T10:00:00Z",
"created_at": "2026-01-01T00:00:00Z"
}
],
"meta": { "total": 12, "page": 1, "per_page": 20 }
}
Create User
POST /api/v1/users
Creates a new user with status invited. If an email sender is configured, sends an invitation email with a token link. Requires users:write permission.
Request Body:
{
"email": "[email protected]",
"display_name": "New User"
}
Response: 201 Created
Get User
GET /api/v1/users/:id
Returns a user with their team memberships and direct client assignments. Requires users:read permission.
Response: 200 OK
{
"data": {
"id": "user-uuid",
"email": "[email protected]",
"display_name": "Jane Doe",
"status": "active",
"teams": [
{ "team_id": "...", "team_name": "Ops Team", "role_id": "...", "role_name": "Editor" }
],
"clients": [
{ "client_id": "...", "client_name": "Acme", "client_slug": "acme", "role_id": "...", "role_name": "Viewer" }
]
}
}
Update User
PUT /api/v1/users/:id
Updates user fields (display_name, is_super_admin, status). Requires users:write permission.
Delete (Disable) User
DELETE /api/v1/users/:id
Sets user status to disabled, revokes all sessions, and invalidates the access cache. Requires users:delete permission.
Response: 204 No Content
Resend Invitation
POST /api/v1/users/:id/resend-invite
Resends the invitation email. Only works for users with status invited. Requires users:write permission.
Reset Password
POST /api/v1/users/:id/reset-password
Generates a password reset token and sends a reset email. Requires users:write permission and an email sender to be configured.
User Client Assignments
Direct user-to-client assignments (bypassing team-based access):
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/users/:id/clients | List direct client assignments |
| POST | /api/v1/users/:id/clients | Assign user to client with role |
| PUT | /api/v1/users/:id/clients/:clientId | Change assignment role |
| DELETE | /api/v1/users/:id/clients/:clientId | Remove assignment |
Admin: Teams
List Teams
GET /api/v1/teams
Returns a paginated list of all teams. Requires teams:read permission.
Create Team
POST /api/v1/teams
Request Body:
{
"name": "Ops Team",
"description": "Operations team"
}
Response: 201 Created
Get Team
GET /api/v1/teams/:id
Returns a team with its members and client assignments.
Response: 200 OK
{
"data": {
"id": "team-uuid",
"name": "Ops Team",
"description": "Operations team",
"members": [
{ "user_id": "...", "email": "[email protected]", "display_name": "Jane", "role_id": "...", "role_name": "Editor" }
],
"clients": [
{ "client_id": "...", "name": "Acme Corp", "slug": "acme" }
]
}
}
Update Team
PUT /api/v1/teams/:id
Delete Team
DELETE /api/v1/teams/:id
Deletes the team and cascades to team_members and team_clients. Invalidates access cache for all former members.
Response: 204 No Content
Team Members
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/teams/:id/members | Add member (user_id, role_id) |
| PUT | /api/v1/teams/:id/members/:userId | Change member's role (role_id) |
| DELETE | /api/v1/teams/:id/members/:userId | Remove member |
Team Clients
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/teams/:id/clients | Add client (client_id) |
| DELETE | /api/v1/teams/:id/clients/:clientId | Remove client |
Admin: Roles
List Roles
GET /api/v1/roles
Returns all roles (system roles listed first). Requires roles:read permission.
Create Role
POST /api/v1/roles
Request Body:
{
"name": "Custom Viewer",
"description": "Read-only access to hosts and metrics",
"permissions": ["hosts:read", "metrics:read"]
}
Permissions are validated against the registry. System roles cannot be created via the API.
Response: 201 Created
Get Role
GET /api/v1/roles/:id
Update Role
PUT /api/v1/roles/:id
System roles (is_system=true) cannot be updated. After update, all users assigned to this role have their access cache invalidated.
Delete Role
DELETE /api/v1/roles/:id
System roles cannot be deleted. Response: 204 No Content
List Permissions
GET /api/v1/permissions
Returns all available permissions in the system (resource:action pairs).
Admin: Service Accounts
List Service Accounts
GET /api/v1/service-accounts
Returns a paginated list. The api_key_hash field is never exposed.
Create Service Account
POST /api/v1/service-accounts
Request Body:
{
"name": "CI Deploy",
"description": "CI pipeline service account",
"role_id": "role-uuid",
"client_scope": ["client-uuid-1", "client-uuid-2"],
"expires_at": "2027-01-01T00:00:00Z"
}
Generates a prxm_-prefixed API key. The plaintext key is returned once in the response — store it securely.
Response: 201 Created
{
"data": {
"id": "sa-uuid",
"name": "CI Deploy",
"api_key": "prxm_base64url-encoded-key",
"api_key_prefix": "prxm_base64u",
"created_at": "2026-02-23T10:00:00Z"
}
}
Get / Update / Delete Service Account
GET /api/v1/service-accounts/:id
PUT /api/v1/service-accounts/:id
DELETE /api/v1/service-accounts/:id
Delete performs a soft-delete (sets is_active=false).
Admin: Audit Log
Query Audit Log
GET /api/v1/audit-log
Returns a paginated, filterable list of audit log entries. Requires audit:read permission.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
actor_id | UUID | Filter by actor |
action | string | Filter by action (e.g., user.login, role.create) |
resource_type | string | Filter by resource type (e.g., user, team, role) |
resource_id | string | Filter by resource ID |
from | RFC3339 | Start time |
to | RFC3339 | End time |
page | int | Page number |
per_page | int | Items per page |
Authentication
Auth endpoints are documented in detail on the Authentication page. Quick reference:
Public Auth Routes (rate limited: 5/min per IP)
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/auth/login | Login with email and password |
| POST | /api/v1/auth/refresh | Refresh access token (rotate refresh token) |
| POST | /api/v1/auth/mfa/verify | Verify MFA code during login |
| POST | /api/v1/auth/forgot-password | Request password reset email |
| POST | /api/v1/auth/reset-password | Reset password with token |
| POST | /api/v1/auth/accept-invite | Accept invitation and set password |
Protected Auth Routes (JWT required)
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/auth/logout | Logout (revoke session) |
| GET | /api/v1/auth/me | Get current user profile + permissions |
| POST | /api/v1/auth/mfa/setup | Start MFA setup (returns TOTP secret + recovery codes) |
| POST | /api/v1/auth/mfa/confirm | Confirm MFA setup with TOTP code |
| DELETE | /api/v1/auth/mfa | Disable MFA (requires password) |
| PUT | /api/v1/auth/password | Change password |
| GET | /api/v1/auth/sessions | List active sessions |
| DELETE | /api/v1/auth/sessions/:id | Revoke a specific session |
| DELETE | /api/v1/auth/sessions | Revoke all sessions |
Health Endpoints
These endpoints do not require authentication.
Liveness
GET /healthz
Returns 200 OK if the backend process is alive.
{ "status": "ok" }
Readiness
GET /readyz
Returns 200 OK if all dependencies (PostgreSQL and NATS) are connected and healthy. Returns 503 Service Unavailable if any dependency is down.
{ "status": "ready" }
Metrics
GET /metrics
Returns Prometheus-formatted metrics for scraping.
Watch Config
Manage per-host file watch configuration. Changes are persisted to the database and pushed to agents in real-time via the NATS command channel.
Get Watch Config
GET /api/v1/hosts/:hostID/watch-config
Returns the current watch config for a host, or 404 if no config has been set.
Response (200):
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"host_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"config_type": "watch_files",
"config_data": {
"paths": ["/etc", "/opt/myapp/config"],
"exclude_patterns": ["*.swp", "*.bak"],
"sensitive_files": ["*shadow*", "*.key"],
"max_file_size": 1048576
},
"version": 3,
"created_at": "2026-02-15T10:30:00Z",
"updated_at": "2026-03-01T14:20:00Z"
}
}
Response (404): No watch config set for this host.
Update Watch Config
PUT /api/v1/hosts/:hostID/watch-config
Creates or updates the watch config for a host. The config is saved to the database and published to the agent's command channel for immediate application.
Request body:
{
"paths": ["/etc", "/opt/myapp/config"],
"exclude_patterns": ["*.swp", "*.bak", "*.tmp"],
"sensitive_files": ["*shadow*", "*.key", "*.pem"],
"max_file_size": 1048576
}
| Field | Type | Required | Description |
|---|---|---|---|
paths | string[] | Yes | Filesystem paths to monitor (must be non-empty) |
exclude_patterns | string[] | No | Glob patterns for files to exclude |
sensitive_files | string[] | No | Glob patterns for sensitive files (tracked but content not sent) |
max_file_size | int | No | Maximum file size in bytes (default: 1 MB) |
Response (200): Returns the saved config (same format as GET).
Response (400): paths field is empty or missing.
Side effect: On successful save, the backend publishes a command to proxima.system.commands.{agentID} (keyed by the agent ID, not the host ID — these are distinct values, and the agent's NATS JWT only permits subscribing to its own per-agent command subject):
{
"type": "config_update",
"config_type": "watch_files",
"version": 3,
"payload": { "paths": [...], "exclude_patterns": [...], ... }
}
If the agent is online, it applies the new config immediately. If offline, the agent will fetch the latest config on next startup.
Events Timeline
Get Event Timeline
GET /api/v1/events/timeline?start=2026-03-01T00:00:00Z&end=2026-03-02T00:00:00Z&host_id=<uuid>
Returns aggregated events for use as chart markers or timeline overlays.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
start | RFC3339 | Yes | Start of time range |
end | RFC3339 | Yes | End of time range |
host_id | UUID | No | Filter events for a specific host |
environment_id | UUID | No | Filter events for a specific environment |
event_type | string | No | Filter by type: deploy, file_change, agent_status |
limit | int | No | Maximum number of events (default 100) |
Response (200):
{
"data": [
{
"timestamp": "2026-03-01T10:30:00Z",
"event_type": "deploy",
"title": "Config updated",
"description": "Agent config v3 applied",
"host_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"environment_id": "c5f8a2b0-1234-4abc-9def-567890abcdef"
}
]
}
MetricsQL Query
Execute Query
POST /api/v1/metrics/query
Executes a MetricsQL expression against VictoriaMetrics with automatic tenant-scoped filtering. The backend injects extra_filters[] based on the authenticated user's client access to enforce tenant isolation.
Request body:
{
"query": "rate(cpu_usage_ratio[5m])",
"start": "2026-03-01T00:00:00Z",
"end": "2026-03-01T01:00:00Z",
"step": "60s",
"host_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
}
host_id and environment_id are top-level fields (there is no scope
wrapper), and at least one is required for scope resolution.
| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | MetricsQL expression |
start | RFC3339 | Yes | Start of time range |
end | RFC3339 | Yes | End of time range |
step | string | No | Query resolution step (e.g. 60s, 5m) |
host_id | UUID | Conditional | Scope to one host. At least one of host_id / environment_id is required. |
environment_id | UUID | Conditional | Scope to one environment. At least one of host_id / environment_id is required. |
Response: Streams Prometheus-format JSON (same schema as VictoriaMetrics /api/v1/query_range).
Annotations
Create Annotation
POST /api/v1/annotations
Creates a metric annotation attached to a host at a specific point in time.
Request body:
{
"host_id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"timestamp": "2026-03-01T10:30:00Z",
"text": "Deployment v2.3.1 completed"
}
| Field | Type | Required | Description |
|---|---|---|---|
host_id | UUID | Yes | Host to attach annotation to |
timestamp | RFC3339 | Yes | Point-in-time for the annotation |
text | string | Yes | Annotation text |
Response (201): Returns the created annotation object.
List Annotations
GET /api/v1/annotations?host_id=<uuid>&start=<RFC3339>&end=<RFC3339>
Returns annotations matching the filter criteria.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
host_id | UUID | No | Filter by host |
environment_id | UUID | No | Filter by environment |
start | RFC3339 | No | Start of time range |
end | RFC3339 | No | End of time range |
Response (200): Array of annotation objects.
Delete Annotation
DELETE /api/v1/annotations/:id
Deletes an annotation. Only the annotation creator or a super admin can delete annotations.
Response (204): No content on success.
Response (403): Caller is not the annotation creator or a super admin.
Agent Enrollment
Agent enrollment is handled via HTTPS, not NATS. Agents use one-time install tokens and a challenge-response protocol to obtain NATS credentials. See NATS Security -- Agent Enrollment for the full protocol.
Agent Config Fetch
Config fetch is handled via NATS request-reply, not the REST API. Each agent sends a request to its own per-agent subject:
proxima.system.agent.config.{agentID}
An agent's NATS user JWT only permits publishing to its own per-agent subject, so the backend derives the requesting agent's identity from the broker-enforced subject (the trailing {agentID} token) and never trusts an agent_id supplied in the request body. The backend's ConfigFetchWorker responds with all config types for the requesting agent's host. See Agent -- Config Fetch at Startup for details.