Skip to content

REST API

The full REST API surface, rendered from the OpenAPI 3.x spec at admin-openapi-v0.2.0.json.

For an interactive try it UI, point your browser at /swaggerui on a running admin — the spec there is always authoritative for that admin's deployed version.

Edge Admin OpenAPI 0.2.0

REST API for Edge Admin — the orchestration server for Edge Core.

Most endpoints require an API key (Authorization: Bearer <API_KEY> or <MASTER_KEY>). A small set of bootstrap endpoints is intentionally public — see the per-operation security field in the spec; an empty array there means the endpoint is unauthenticated by design (e.g. public enrollment-key creation).

Explore: - Swagger UI — interactive API explorer - ReDoc — reference documentation - Raw spec — OpenAPI JSON

Event streaming: Edge Admin also publishes lifecycle events to a message broker. See the AsyncAPI spec or download it.


Admins.Metadata

GET /api/v1/admins/me

Get the current admin

Description Returns the current admin's identity and configuration from metadata.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 200 OK

application/json

{
    "data": {
        "admin_cluster_name": "admin-cluster-1",
        "admin_peer_count": 1,
        "edge_node_capacity": 249,
        "erlang_node_name": "admin@admin-k7m3n2p9x4j6.admin-cluster-1.nm.internal",
        "id": "k7m3n2p9x4j6",
        "last_computed_at": "2025-01-15T12:00:00Z",
        "max_wireguard_peers": 250,
        "name": "admin-k7m3n2p9x4j6",
        "netmaker_host_id": "95e2707e-d11f-4551-bdd4-4ab2ab917505",
        "vpn_hostname": "admin-k7m3n2p9x4j6.admin-cluster-1.nm.internal"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single admin identity response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/Admin"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "AdminResponse",
    "type": "object"
}

GET /api/v1/admins/my_admin_cluster

Get this admin's admin cluster

Description Returns metadata and peer topology for the admin cluster this admin belongs to.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 200 OK

application/json

{
    "data": {
        "degraded": false,
        "name": "admin-cluster-1",
        "topology": [
            {
                "admin_peer_count": 1,
                "edge_node_capacity": 249,
                "erlang_node_name": "admin@admin-k7m3n2p9x4j6.admin-cluster-1.nm.internal",
                "max_wireguard_peers": 250,
                "name": "admin-k7m3n2p9x4j6",
                "netmaker_host_id": "95e2707e-d11f-4551-bdd4-4ab2ab917505",
                "vpn_hostname": "admin-k7m3n2p9x4j6.admin-cluster-1.nm.internal"
            },
            {
                "admin_peer_count": 1,
                "edge_node_capacity": 249,
                "erlang_node_name": "admin@admin-x9j4p2k7m8n3.admin-cluster-1.nm.internal",
                "max_wireguard_peers": 250,
                "name": "admin-x9j4p2k7m8n3",
                "netmaker_host_id": "7f3c8d4e-9a1b-4c2d-8e3f-5a6b7c8d9e0f",
                "vpn_hostname": "admin-x9j4p2k7m8n3.admin-cluster-1.nm.internal"
            }
        ],
        "total_admins": 2,
        "total_edge_capacity": 498,
        "total_nodes": 42,
        "weak_leader": "admin-k7m3n2p9x4j6"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Topology and state of the admin cluster this admin belongs to",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/MyAdminCluster"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "MyAdminClusterResponse",
    "type": "object"
}

GET /api/v1/admins/admin_clusters

List all admin clusters from Netmaker

Description Lists every admin cluster Netmaker knows about, with each cluster's admins. Includes admins this instance is not a member of (cross-cluster visibility) and may include stale entries.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 200 OK

application/json

{
    "data": [
        {
            "admin_count": 1,
            "admins": [
                {
                    "ipv4_address": "100.64.0.1",
                    "last_checked_in": "2026-04-28T12:34:56Z",
                    "name": "admin-7k3m9p2n",
                    "netmaker_host_id": "f272e703-b48f-4b61-b4c1-bfe4fffde62b",
                    "status": "online",
                    "use_static_port": true,
                    "vpn_hostname": "admin-7k3m9p2n.admin-cluster-main.nm.internal",
                    "wireguard_ip_address": "10.0.0.7",
                    "wireguard_port": 51820
                }
            ],
            "ipv4_range": "100.64.0.0/24",
            "name": "admin-cluster-main"
        }
    ],
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "All admin clusters Netmaker knows about",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/AdminClusters"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "AdminClustersResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

GET /api/v1/admins/edge_clusters

Get all edge cluster assignments

Description Returns all edge cluster assignments across all admins from metadata

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 200 OK

application/json

{
    "data": {
        "admin-k7m3n2p9x4j6": {
            "cluster-p4k7n2m9x3j6": [
                "node-uuid-x"
            ],
            "cluster-x7j2p9k4m8n3": [
                "node-uuid-1",
                "node-uuid-2"
            ]
        },
        "admin-x9j4p2k7m8n3": {
            "cluster-j6m8n3p7k2x4": [],
            "cluster-m3n9p2k8x7j4": [
                "node-uuid-3"
            ]
        }
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "All edge cluster assignments across all admins",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/EdgeClusters"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EdgeClustersResponse",
    "type": "object"
}

GET /api/v1/admins/orphaned_clusters

Get all orphaned clusters

Description Returns all clusters that could not be assigned to any admin due to capacity constraints. Empty map when system is not degraded.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 200 OK

application/json

{
    "data": {
        "cluster-orphaned-1": [
            "node-uuid-5",
            "node-uuid-6"
        ],
        "cluster-orphaned-2": [
            "node-uuid-7"
        ]
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Clusters with no assigned admin instance",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/OrphanedClusters"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "OrphanedClustersResponse",
    "type": "object"
}

Admins.Metrics

GET /api/v1/admins/me/metrics

Get metrics for this admin

Description Returns application-level metrics from the edge_admin PromEx: - Application: uptime, BEAM stats (processes, memory, atoms, ETS tables) - Metadata: degraded status, orphaned/assigned clusters - Membership: step counts and full sequence completions - Discovery: peer discovery scan, DNS resolution, and connection counts - Nodes: health check statistics - Commands: delivery runs, per-execution delivery, completions, expirations - SSH: credential verification attempts and failures - Reconciliation: cluster Netmaker↔DB sync runs and errors - Self-updates: request processing completions - Gateways: connection events, active count, scrape totals - Event broker: publish/enqueue counters (zeroed when broker is disabled) - Oban: job queue states (available, scheduled, executing, etc.)

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 200 OK

application/json

{
    "data": {
        "application": {
            "atom_count": 38522,
            "ets_count": 144,
            "memory_atom_bytes": 1223807,
            "memory_atom_mb": 1.17,
            "memory_binary_bytes": 8817904,
            "memory_binary_mb": 8.41,
            "memory_code_bytes": 30935279,
            "memory_code_mb": 29.5,
            "memory_ets_bytes": 2884160,
            "memory_ets_mb": 2.75,
            "memory_processes_bytes": 25999000,
            "memory_processes_mb": 24.79,
            "memory_total_bytes": 101185152,
            "memory_total_mb": 96.5,
            "port_count": 31,
            "process_count": 811,
            "uptime_human": "23m",
            "uptime_seconds": 1404
        },
        "commands": {
            "delivery_delivered_count": 0,
            "delivery_total": 48,
            "execution_completed_total": 21,
            "execution_delivered_total": 23,
            "expiration_total": 2
        },
        "discovery": {
            "dns_resolutions_total": 12,
            "peer_connections_total": 3,
            "scans_total": 144
        },
        "event_broker": {
            "enabled": true,
            "enqueues_total": 1235,
            "publishes_error_total": 4,
            "publishes_ok_total": 1230,
            "publishes_total": 1234
        },
        "gateways": {
            "active_count": 0,
            "connections_total": 2,
            "scrapes_total": 0
        },
        "membership": {
            "complete_total": 1,
            "steps_completed_total": 4
        },
        "metadata": {
            "assigned_clusters": 0,
            "degraded": false,
            "orphaned_clusters": 0,
            "recomputations_total": 26
        },
        "nodes": {
            "health_checks_total": 480
        },
        "oban_queues": [
            {
                "available": 0,
                "cancelled": 0,
                "completed": 81,
                "discarded": 0,
                "executing": 0,
                "queue": "zombie_admin_cleanup",
                "retryable": 0,
                "scheduled": 0
            },
            {
                "available": 0,
                "cancelled": 0,
                "completed": 0,
                "discarded": 0,
                "executing": 0,
                "queue": "execution_creation",
                "retryable": 0,
                "scheduled": 0
            }
        ],
        "proxy": {
            "auth_failures_total": 34,
            "bytes_down_mb": 9419.4,
            "bytes_down_total": 9876543210,
            "bytes_up_mb": 1452.9,
            "bytes_up_total": 1523456789,
            "connections_auth_failed_total": 34,
            "connections_failure_total": 22,
            "connections_success_total": 1189,
            "connections_total": 1245,
            "tunnels_closed_deadline_total": 38,
            "tunnels_closed_drain_timeout_total": 11,
            "tunnels_closed_normal_total": 1140,
            "tunnels_closed_total": 1189
        },
        "quantum": {
            "jobs_exceptions_total": 0,
            "jobs_executed_total": 156
        },
        "reconciliation": {
            "errors": 0,
            "total": 12
        },
        "self_updates": {
            "completed_total": 3
        },
        "ssh": {
            "verifications_failed": 1,
            "verifications_total": 34
        },
        "timestamp": "2025-12-26T15:30:00Z",
        "vpn": {
            "zombie_cleanup_deleted_count": 0,
            "zombie_cleanup_total": 81
        },
        "webhook": {
            "deliveries_ok_total": 2400,
            "deliveries_recoverable_total": 60,
            "deliveries_terminal_total": 10,
            "deliveries_total": 2470,
            "fan_outs_total": 1235
        }
    },
    "meta": "Elixir.EdgeAdminWeb.Schemas.CommonSchemas.MetaSchema"
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Application-level metrics from edge_admin PromEx (BEAM stats, metadata, Oban, etc.).\n",
    "example": {
        "data": {
            "application": {
                "atom_count": 38522,
                "ets_count": 144,
                "memory_atom_bytes": 1223807,
                "memory_atom_mb": 1.17,
                "memory_binary_bytes": 8817904,
                "memory_binary_mb": 8.41,
                "memory_code_bytes": 30935279,
                "memory_code_mb": 29.5,
                "memory_ets_bytes": 2884160,
                "memory_ets_mb": 2.75,
                "memory_processes_bytes": 25999000,
                "memory_processes_mb": 24.79,
                "memory_total_bytes": 101185152,
                "memory_total_mb": 96.5,
                "port_count": 31,
                "process_count": 811,
                "uptime_human": "23m",
                "uptime_seconds": 1404
            },
            "commands": {
                "delivery_delivered_count": 0,
                "delivery_total": 48,
                "execution_completed_total": 21,
                "execution_delivered_total": 23,
                "expiration_total": 2
            },
            "discovery": {
                "dns_resolutions_total": 12,
                "peer_connections_total": 3,
                "scans_total": 144
            },
            "event_broker": {
                "enabled": true,
                "enqueues_total": 1235,
                "publishes_error_total": 4,
                "publishes_ok_total": 1230,
                "publishes_total": 1234
            },
            "gateways": {
                "active_count": 0,
                "connections_total": 2,
                "scrapes_total": 0
            },
            "membership": {
                "complete_total": 1,
                "steps_completed_total": 4
            },
            "metadata": {
                "assigned_clusters": 0,
                "degraded": false,
                "orphaned_clusters": 0,
                "recomputations_total": 26
            },
            "nodes": {
                "health_checks_total": 480
            },
            "oban_queues": [
                {
                    "available": 0,
                    "cancelled": 0,
                    "completed": 81,
                    "discarded": 0,
                    "executing": 0,
                    "queue": "zombie_admin_cleanup",
                    "retryable": 0,
                    "scheduled": 0
                },
                {
                    "available": 0,
                    "cancelled": 0,
                    "completed": 0,
                    "discarded": 0,
                    "executing": 0,
                    "queue": "execution_creation",
                    "retryable": 0,
                    "scheduled": 0
                }
            ],
            "proxy": {
                "auth_failures_total": 34,
                "bytes_down_mb": 9419.4,
                "bytes_down_total": 9876543210,
                "bytes_up_mb": 1452.9,
                "bytes_up_total": 1523456789,
                "connections_auth_failed_total": 34,
                "connections_failure_total": 22,
                "connections_success_total": 1189,
                "connections_total": 1245,
                "tunnels_closed_deadline_total": 38,
                "tunnels_closed_drain_timeout_total": 11,
                "tunnels_closed_normal_total": 1140,
                "tunnels_closed_total": 1189
            },
            "quantum": {
                "jobs_exceptions_total": 0,
                "jobs_executed_total": 156
            },
            "reconciliation": {
                "errors": 0,
                "total": 12
            },
            "self_updates": {
                "completed_total": 3
            },
            "ssh": {
                "verifications_failed": 1,
                "verifications_total": 34
            },
            "timestamp": "2025-12-26T15:30:00Z",
            "vpn": {
                "zombie_cleanup_deleted_count": 0,
                "zombie_cleanup_total": 81
            },
            "webhook": {
                "deliveries_ok_total": 2400,
                "deliveries_recoverable_total": 60,
                "deliveries_terminal_total": 10,
                "deliveries_total": 2470,
                "fan_outs_total": 1235
            }
        },
        "meta": "Elixir.EdgeAdminWeb.Schemas.CommonSchemas.MetaSchema"
    },
    "properties": {
        "data": {
            "properties": {
                "application": {
                    "description": "Application health and BEAM VM stats",
                    "properties": {
                        "atom_count": {
                            "description": "Number of allocated atoms",
                            "nullable": true,
                            "type": "integer"
                        },
                        "ets_count": {
                            "description": "Number of ETS tables",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_atom_bytes": {
                            "description": "Memory used by atoms in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_atom_mb": {
                            "description": "Memory used by atoms in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_binary_bytes": {
                            "description": "Memory used by binaries in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_binary_mb": {
                            "description": "Memory used by binaries in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_code_bytes": {
                            "description": "Memory used by code in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_code_mb": {
                            "description": "Memory used by code in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_ets_bytes": {
                            "description": "Memory used by ETS tables in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_ets_mb": {
                            "description": "Memory used by ETS tables in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_processes_bytes": {
                            "description": "Memory used by processes in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_processes_mb": {
                            "description": "Memory used by processes in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_total_bytes": {
                            "description": "Total BEAM memory allocated in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_total_mb": {
                            "description": "Total BEAM memory in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "port_count": {
                            "description": "Number of active ports",
                            "nullable": true,
                            "type": "integer"
                        },
                        "process_count": {
                            "description": "Number of BEAM processes running",
                            "nullable": true,
                            "type": "integer"
                        },
                        "uptime_human": {
                            "description": "Human-readable uptime (e.g., '2d 5h 30m')",
                            "nullable": true,
                            "type": "string"
                        },
                        "uptime_seconds": {
                            "description": "Application uptime in seconds",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "commands": {
                    "description": "Command execution and delivery metrics",
                    "properties": {
                        "delivery_delivered_count": {
                            "description": "Number of executions queued for delivery in last batch run",
                            "nullable": true,
                            "type": "integer"
                        },
                        "delivery_total": {
                            "description": "Total delivery batch runs (Quantum scheduler cycles)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "execution_completed_total": {
                            "description": "Total executions completed (result reported back by agent)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "execution_delivered_total": {
                            "description": "Total individual execution delivery attempts to agents (success + failure)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "expiration_total": {
                            "description": "Total stale execution expiration sweeps",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "discovery": {
                    "description": "Peer admin discovery metrics",
                    "properties": {
                        "dns_resolutions_total": {
                            "description": "Total DNS resolution attempts during peer discovery",
                            "nullable": true,
                            "type": "integer"
                        },
                        "peer_connections_total": {
                            "description": "Total Erlang peer connection attempts (success + failure + already_connected)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "scans_total": {
                            "description": "Total peer discovery scan cycles completed",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "event_broker": {
                    "description": "Event broker publish metrics. When the broker is disabled (default), `enabled` is `false`\nand all counters are 0. A sustained gap between `enqueues_total` and `publishes_ok_total`\nindicates broker failures with events accumulating in Oban for retry.\n",
                    "properties": {
                        "enabled": {
                            "description": "Whether the event broker is enabled (mirrors EVENT_BROKER_ENABLED config)",
                            "nullable": true,
                            "type": "boolean"
                        },
                        "enqueues_total": {
                            "description": "Total events enqueued for async broker delivery (before any publish attempt)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "publishes_error_total": {
                            "description": "Total broker publishes that failed (will be retried by Oban)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "publishes_ok_total": {
                            "description": "Total broker publishes that succeeded",
                            "nullable": true,
                            "type": "integer"
                        },
                        "publishes_total": {
                            "description": "Total broker publish attempts (ok + error)",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "gateways": {
                    "description": "Gateway connection and scrape metrics",
                    "properties": {
                        "active_count": {
                            "description": "Current number of active gateway connections",
                            "nullable": true,
                            "type": "integer"
                        },
                        "connections_total": {
                            "description": "Total gateway connection events (connects + disconnects)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "scrapes_total": {
                            "description": "Total metrics scrape operations performed by gateways",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "membership": {
                    "description": "Admin-cluster membership initialization metrics",
                    "properties": {
                        "complete_total": {
                            "description": "Total full membership sequences completed (success + failure)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "steps_completed_total": {
                            "description": "Total individual membership steps completed across all restarts",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "metadata": {
                    "description": "Admin metadata and cluster assignment status",
                    "properties": {
                        "assigned_clusters": {
                            "description": "Number of clusters assigned to this admin",
                            "nullable": true,
                            "type": "integer"
                        },
                        "degraded": {
                            "description": "Whether admin is in degraded state",
                            "nullable": true,
                            "type": "boolean"
                        },
                        "orphaned_clusters": {
                            "description": "Number of orphaned clusters detected",
                            "nullable": true,
                            "type": "integer"
                        },
                        "recomputations_total": {
                            "description": "Total metadata recomputations performed",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "nodes": {
                    "description": "Node health check metrics",
                    "properties": {
                        "health_checks_total": {
                            "description": "Total node health checks performed",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "oban_queues": {
                    "description": "Oban job queue states",
                    "items": {
                        "properties": {
                            "available": {
                                "description": "Jobs available to run",
                                "type": "integer"
                            },
                            "cancelled": {
                                "description": "Cancelled jobs",
                                "type": "integer"
                            },
                            "completed": {
                                "description": "Completed jobs",
                                "type": "integer"
                            },
                            "discarded": {
                                "description": "Discarded jobs (max retries exceeded)",
                                "type": "integer"
                            },
                            "executing": {
                                "description": "Jobs currently executing",
                                "type": "integer"
                            },
                            "queue": {
                                "description": "Queue name (e.g., 'zombie_admin_cleanup', 'execution_creation')",
                                "type": "string"
                            },
                            "retryable": {
                                "description": "Jobs awaiting retry",
                                "type": "integer"
                            },
                            "scheduled": {
                                "description": "Jobs scheduled for future execution",
                                "type": "integer"
                            }
                        },
                        "type": "object"
                    },
                    "type": "array"
                },
                "proxy": {
                    "description": "HTTP and SOCKS5 forward proxy metrics (connections, tunnels, bytes transferred)",
                    "properties": {
                        "auth_failures_total": {
                            "description": "Total proxy authentication failures (mirrors connections_auth_failed_total)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "bytes_down_mb": {
                            "description": "Cumulative target→client bytes in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "bytes_down_total": {
                            "description": "Cumulative bytes forwarded target→client across all tunnels",
                            "nullable": true,
                            "type": "integer"
                        },
                        "bytes_up_mb": {
                            "description": "Cumulative client→target bytes in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "bytes_up_total": {
                            "description": "Cumulative bytes forwarded client→target across all tunnels",
                            "nullable": true,
                            "type": "integer"
                        },
                        "connections_auth_failed_total": {
                            "description": "Total proxy connections rejected at authentication",
                            "nullable": true,
                            "type": "integer"
                        },
                        "connections_failure_total": {
                            "description": "Total proxy connections that failed for non-auth reasons (protocol, network, gateway, etc.)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "connections_success_total": {
                            "description": "Total proxy connections that authenticated and established a tunnel",
                            "nullable": true,
                            "type": "integer"
                        },
                        "connections_total": {
                            "description": "Total proxy connections seen (success + auth_failed + failure)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_deadline_total": {
                            "description": "Tunnels force-closed by the total-duration deadline (slowloris defence)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_drain_timeout_total": {
                            "description": "Tunnels force-closed after exceeding the graceful drain grace window",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_normal_total": {
                            "description": "Tunnels closed normally (both sides EOF'd cleanly)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_total": {
                            "description": "Total tunnels that reached end-of-life (all close reasons combined)",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "quantum": {
                    "description": "Quantum scheduler job execution metrics",
                    "properties": {
                        "jobs_exceptions_total": {
                            "description": "Total Quantum job exceptions/failures",
                            "nullable": true,
                            "type": "integer"
                        },
                        "jobs_executed_total": {
                            "description": "Total Quantum jobs executed across all job types",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "reconciliation": {
                    "description": "Cluster reconciliation metrics (Netmaker ↔ DB sync)",
                    "properties": {
                        "errors": {
                            "description": "Number of errors in last reconciliation run",
                            "nullable": true,
                            "type": "integer"
                        },
                        "total": {
                            "description": "Total cluster reconciliation runs",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "self_updates": {
                    "description": "Self-update request processing metrics",
                    "properties": {
                        "completed_total": {
                            "description": "Total self-update requests processed to completion",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "ssh": {
                    "description": "SSH credential verification metrics",
                    "properties": {
                        "verifications_failed": {
                            "description": "Total SSH credential verification failures",
                            "nullable": true,
                            "type": "integer"
                        },
                        "verifications_total": {
                            "description": "Total SSH credential verification attempts (all auth methods)",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "timestamp": {
                    "description": "When the metrics were collected (ISO 8601 format)",
                    "format": "date-time",
                    "type": "string"
                },
                "vpn": {
                    "description": "VPN management metrics",
                    "properties": {
                        "zombie_cleanup_deleted_count": {
                            "description": "Number of zombie admins deleted in last cleanup",
                            "nullable": true,
                            "type": "integer"
                        },
                        "zombie_cleanup_total": {
                            "description": "Total zombie admin cleanup runs",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "webhook": {
                    "description": "Webhook delivery metrics. `fan_outs_total` counts publish-time fan-out invocations\n(one per published event regardless of how many webhooks match). `deliveries_*` count\nindividual HTTP delivery attempts and their outcomes — `ok`, `recoverable` (retried by\nOban: 408/429/503/network until `WEBHOOK_MAX_ATTEMPTS` is exhausted), `terminal`\n(cancelled by the worker, no further retries).\n",
                    "properties": {
                        "deliveries_ok_total": {
                            "description": "Total deliveries that returned 2xx",
                            "nullable": true,
                            "type": "integer"
                        },
                        "deliveries_recoverable_total": {
                            "description": "Total deliveries that hit a recoverable error (will be retried)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "deliveries_terminal_total": {
                            "description": "Total deliveries that hit a terminal error (cancelled, contributes to auto-disable)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "deliveries_total": {
                            "description": "Total webhook delivery attempts (ok + recoverable + terminal)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "fan_outs_total": {
                            "description": "Total fan-out invocations from the publish path",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                }
            },
            "type": "object"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "AdminMetricsResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

Nodes.Cluster

POST /api/v1/clusters

Create a new cluster

Description Create a new edge cluster with optional IP range. The name default is reserved (used as a URL keyword on convenience routes) and will be rejected with HTTP 422.

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Request body

application/json

{
    "ipv4_range": "100.64.1.0/24",
    "name": "prod-east",
    "node_limit": 50
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Parameters for creating a new cluster",
    "example": {
        "ipv4_range": "100.64.1.0/24",
        "name": "prod-east",
        "node_limit": 50
    },
    "properties": {
        "ipv4_range": {
            "description": "IPv4 CIDR range (auto-generated if not provided)",
            "example": "100.64.0.0/24",
            "nullable": true,
            "pattern": "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\/\\d{1,2}$",
            "type": "string"
        },
        "name": {
            "description": "Cluster name — primary identifier (max 24 chars, lowercase alphanumeric + hyphens)",
            "example": "prod-east",
            "maxLength": 24,
            "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
            "type": "string"
        },
        "node_limit": {
            "description": "Maximum nodes allowed in this cluster (null means no limit enforced)",
            "example": 50,
            "minimum": 1,
            "nullable": true,
            "type": "integer"
        }
    },
    "required": [
        "name"
    ],
    "title": "ClusterCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "id": "abc12345-1234-1234-1234-123456789abc",
        "inserted_at": "2025-06-09T08:00:00Z",
        "ipv4_range": "100.64.0.0/24",
        "name": "prod-east",
        "network_name": "cluster-prod-east",
        "node_count": 2,
        "node_limit": 50,
        "nodes": [
            {
                "id": "abc12345-1234-1234-1234-123456789abc",
                "id_type": "persistent",
                "status": "healthy",
                "vpn_hostname": "node-abc12345-1234-1234-1234-123456789abc.cluster-prod-east.nm.internal"
            },
            {
                "id": "def67890-5678-5678-5678-567890abcdef",
                "id_type": "persistent",
                "status": "healthy",
                "vpn_hostname": "node-def67890-5678-5678-5678-567890abcdef.cluster-prod-east.nm.internal"
            }
        ],
        "updated_at": "2025-06-09T08:00:00Z",
        "vpn_domain": "cluster-prod-east.nm.internal"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single cluster response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/ClusterResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "ClusterSingleResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

GET /api/v1/clusters

List all clusters

Description Returns a paginated list of all edge clusters with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
has_node_limit query boolean No Filter by whether a node limit is set: true returns clusters with a limit, false returns unlimited
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
ipv4_range query string No Filter by IPv4 range (exact match or wildcard)
name query string No Filter by cluster name (exact match or wildcard: prod, tion, rod)
node_count__gte query integer No Filter by minimum node_count
node_count__lte query integer No Filter by maximum node_count
node_limit query integer No Filter by exact node limit
node_limit__gte query integer No Filter by minimum node_limit
node_limit__lte query integer No Filter by maximum node_limit
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)

Response 200 OK

application/json

{
    "data": [
        {
            "id": "abc12345-1234-1234-1234-123456789abc",
            "inserted_at": "2025-06-09T08:00:00Z",
            "ipv4_range": "100.64.0.0/24",
            "name": "prod-east",
            "network_name": "cluster-prod-east",
            "node_count": 2,
            "node_limit": 50,
            "nodes": [
                {
                    "id": "abc12345-1234-1234-1234-123456789abc",
                    "id_type": "persistent",
                    "status": "healthy",
                    "vpn_hostname": "node-abc12345-1234-1234-1234-123456789abc.cluster-prod-east.nm.internal"
                },
                {
                    "id": "def67890-5678-5678-5678-567890abcdef",
                    "id_type": "persistent",
                    "status": "healthy",
                    "vpn_hostname": "node-def67890-5678-5678-5678-567890abcdef.cluster-prod-east.nm.internal"
                }
            ],
            "updated_at": "2025-06-09T08:00:00Z",
            "vpn_domain": "cluster-prod-east.nm.internal"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of clusters with metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/ClusterResponse"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "ClusterPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/clusters/{name}

Get a specific cluster

Description Returns details for a specific cluster by name

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
name path string No Cluster name

Response 200 OK

application/json

{
    "data": {
        "id": "abc12345-1234-1234-1234-123456789abc",
        "inserted_at": "2025-06-09T08:00:00Z",
        "ipv4_range": "100.64.0.0/24",
        "name": "prod-east",
        "network_name": "cluster-prod-east",
        "node_count": 2,
        "node_limit": 50,
        "nodes": [
            {
                "id": "abc12345-1234-1234-1234-123456789abc",
                "id_type": "persistent",
                "status": "healthy",
                "vpn_hostname": "node-abc12345-1234-1234-1234-123456789abc.cluster-prod-east.nm.internal"
            },
            {
                "id": "def67890-5678-5678-5678-567890abcdef",
                "id_type": "persistent",
                "status": "healthy",
                "vpn_hostname": "node-def67890-5678-5678-5678-567890abcdef.cluster-prod-east.nm.internal"
            }
        ],
        "updated_at": "2025-06-09T08:00:00Z",
        "vpn_domain": "cluster-prod-east.nm.internal"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single cluster response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/ClusterResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "ClusterSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

PATCH /api/v1/clusters/{name}

Update a cluster

Description Update a cluster's settings. Only provided fields are changed. Pass null to unset a nullable field.

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
name path string No Cluster name

Request body

application/json

{
    "node_limit": 50
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Parameters for updating a cluster. Only provided fields are updated. Pass null to unset a nullable field.",
    "example": {
        "node_limit": 50
    },
    "properties": {
        "node_limit": {
            "description": "Maximum nodes allowed in this cluster (null means no limit enforced)",
            "example": 50,
            "minimum": 1,
            "nullable": true,
            "type": "integer"
        }
    },
    "title": "ClusterUpdateRequest",
    "type": "object"
}

Response 200 OK

application/json

{
    "data": {
        "id": "abc12345-1234-1234-1234-123456789abc",
        "inserted_at": "2025-06-09T08:00:00Z",
        "ipv4_range": "100.64.0.0/24",
        "name": "prod-east",
        "network_name": "cluster-prod-east",
        "node_count": 2,
        "node_limit": 50,
        "nodes": [
            {
                "id": "abc12345-1234-1234-1234-123456789abc",
                "id_type": "persistent",
                "status": "healthy",
                "vpn_hostname": "node-abc12345-1234-1234-1234-123456789abc.cluster-prod-east.nm.internal"
            },
            {
                "id": "def67890-5678-5678-5678-567890abcdef",
                "id_type": "persistent",
                "status": "healthy",
                "vpn_hostname": "node-def67890-5678-5678-5678-567890abcdef.cluster-prod-east.nm.internal"
            }
        ],
        "updated_at": "2025-06-09T08:00:00Z",
        "vpn_domain": "cluster-prod-east.nm.internal"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single cluster response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/ClusterResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "ClusterSingleResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

DELETE /api/v1/clusters/{name}

Delete a cluster

Description Delete an empty cluster (must have no nodes).

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
name path string No Cluster name

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

Nodes.EnrollmentKey

POST /api/v1/clusters/default/enrollment_keys/public

Get a public enrollment key for the default cluster

Description Public endpoint (no authentication required). Only enabled when both PUBLIC_ENROLLMENT_KEY_ENABLED=true and DEFAULT_CLUSTER_NAME are configured.

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 201 Created

application/json

{
    "data": {
        "cluster_name": "prod-east",
        "expired_at": "2026-12-31T23:59:59Z",
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "inserted_at": "2025-06-09T08:00:00Z",
        "key": "eyJzZXJ2ZXIiOiJodHRwczovL25ldG1ha2VyLmV4YW1wbGUuY29tIiwia2V5IjoiYWJjMTIzIn0=",
        "last_used_at": null,
        "name": "prod rollout",
        "updated_at": "2025-06-09T08:00:00Z",
        "uses_remaining": 5
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single enrollment key response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/EnrollmentKeyResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EnrollmentKeySingleResponse",
    "type": "object"
}

Response 403 Forbidden

application/json

{
    "error": {
        "code": "forbidden",
        "message": "Insufficient permissions"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "403 Forbidden",
    "example": {
        "error": {
            "code": "forbidden",
            "message": "Insufficient permissions"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "forbidden",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Insufficient permissions",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ForbiddenResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

POST /api/v1/clusters/default/enrollment_keys

Create an enrollment key for the default cluster

Description Convenience endpoint for the default cluster (configured via DEFAULT_CLUSTER_NAME env).

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Request body

application/json

{
    "expired_at": "2026-12-31T23:59:59Z",
    "name": "prod rollout",
    "uses_remaining": 5
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Parameters for creating a new enrollment key for a cluster. All fields are optional.",
    "example": {
        "expired_at": "2026-12-31T23:59:59Z",
        "name": "prod rollout",
        "uses_remaining": 5
    },
    "properties": {
        "expired_at": {
            "description": "Expiry datetime (ISO 8601). Omit or pass null for no expiry.",
            "example": "2026-12-31T23:59:59Z",
            "format": "date-time",
            "nullable": true,
            "type": "string"
        },
        "name": {
            "description": "Optional human-readable label for this key. Display only — not used for lookup.",
            "example": "prod rollout",
            "nullable": true,
            "type": "string"
        },
        "uses_remaining": {
            "description": "Number of uses (must be >= 1). Pass null for unlimited. Omit to use the default of 1.",
            "example": 5,
            "minimum": 1,
            "nullable": true,
            "type": "integer"
        }
    },
    "title": "EnrollmentKeyCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "cluster_name": "prod-east",
        "expired_at": "2026-12-31T23:59:59Z",
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "inserted_at": "2025-06-09T08:00:00Z",
        "key": "eyJzZXJ2ZXIiOiJodHRwczovL25ldG1ha2VyLmV4YW1wbGUuY29tIiwia2V5IjoiYWJjMTIzIn0=",
        "last_used_at": null,
        "name": "prod rollout",
        "updated_at": "2025-06-09T08:00:00Z",
        "uses_remaining": 5
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single enrollment key response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/EnrollmentKeyResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EnrollmentKeySingleResponse",
    "type": "object"
}

Response 403 Forbidden

application/json

{
    "error": {
        "code": "forbidden",
        "message": "Insufficient permissions"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "403 Forbidden",
    "example": {
        "error": {
            "code": "forbidden",
            "message": "Insufficient permissions"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "forbidden",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Insufficient permissions",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ForbiddenResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

POST /api/v1/clusters/{cluster_name}/enrollment_keys

Create an enrollment key for a cluster

Description Create a new enrollment key for an edge cluster. The returned key blob must be set as the ENROLLMENT_KEY environment variable on the agent to allow it to join the cluster's VPN network.

Keys can be limited by use count (uses_remaining) or by expiry time (expired_at). Omit both for a single-use key with no expiry.

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
cluster_name path string No Cluster name

Request body

application/json

{
    "expired_at": "2026-12-31T23:59:59Z",
    "name": "prod rollout",
    "uses_remaining": 5
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Parameters for creating a new enrollment key for a cluster. All fields are optional.",
    "example": {
        "expired_at": "2026-12-31T23:59:59Z",
        "name": "prod rollout",
        "uses_remaining": 5
    },
    "properties": {
        "expired_at": {
            "description": "Expiry datetime (ISO 8601). Omit or pass null for no expiry.",
            "example": "2026-12-31T23:59:59Z",
            "format": "date-time",
            "nullable": true,
            "type": "string"
        },
        "name": {
            "description": "Optional human-readable label for this key. Display only — not used for lookup.",
            "example": "prod rollout",
            "nullable": true,
            "type": "string"
        },
        "uses_remaining": {
            "description": "Number of uses (must be >= 1). Pass null for unlimited. Omit to use the default of 1.",
            "example": 5,
            "minimum": 1,
            "nullable": true,
            "type": "integer"
        }
    },
    "title": "EnrollmentKeyCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "cluster_name": "prod-east",
        "expired_at": "2026-12-31T23:59:59Z",
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "inserted_at": "2025-06-09T08:00:00Z",
        "key": "eyJzZXJ2ZXIiOiJodHRwczovL25ldG1ha2VyLmV4YW1wbGUuY29tIiwia2V5IjoiYWJjMTIzIn0=",
        "last_used_at": null,
        "name": "prod rollout",
        "updated_at": "2025-06-09T08:00:00Z",
        "uses_remaining": 5
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single enrollment key response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/EnrollmentKeyResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EnrollmentKeySingleResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

GET /api/v1/enrollment_keys

List enrollment keys

Description Returns a paginated list of enrollment keys with filtering and sorting.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
cluster_name query string No Filter by cluster name (exact match or wildcard: prod, east, etc.)
expired_at__gte query No Filter records where expired_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
expired_at__lte query No Filter records where expired_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
has_expiry query boolean No Filter by whether the key has an expiry set: true returns keys with expired_at present, false returns keys with no expiry (unlimited lifetime)
has_name query boolean No Filter by whether the key has a name set: true returns keys with a human-readable label, false returns unlabeled keys (e.g. those issued by the public/default-cluster endpoint)
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
is_expired query boolean No Filter by whether the key is expired: true returns keys where expired_at is in the past, false returns active keys (including those with no expiry)
is_never_used query boolean No Filter by whether the key has never been used: true returns keys where last_used_at is null, false returns keys that have been used at least once
is_spent query boolean No Filter by whether the key is exhausted: true returns keys with uses_remaining == 0, false returns keys with uses remaining
is_unlimited query boolean No Filter by whether the key has unlimited uses: true returns unlimited keys (uses_remaining is null), false returns keys with a finite use count
key query string No Filter by exact key value
last_used_at__gte query No Filter records where last_used_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
last_used_at__lte query No Filter records where last_used_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
name query string No Filter by enrollment key name (case-insensitive substring or wildcard: prod, rollout, etc.)
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
uses_remaining query integer No Filter by exact uses_remaining (positive integer; use is_unlimited=true to find unlimited keys)
uses_remaining__gte query integer No Filter by minimum uses_remaining
uses_remaining__lte query integer No Filter by maximum uses_remaining

Response 200 OK

application/json

{
    "data": [
        {
            "cluster_name": "prod-east",
            "expired_at": "2026-12-31T23:59:59Z",
            "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
            "inserted_at": "2025-06-09T08:00:00Z",
            "key": "eyJzZXJ2ZXIiOiJodHRwczovL25ldG1ha2VyLmV4YW1wbGUuY29tIiwia2V5IjoiYWJjMTIzIn0=",
            "last_used_at": null,
            "name": "prod rollout",
            "updated_at": "2025-06-09T08:00:00Z",
            "uses_remaining": 5
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of enrollment keys with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/EnrollmentKeyResponse"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EnrollmentKeyPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/enrollment_keys/{id}

Get an enrollment key

Description Returns details for a specific enrollment key by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Enrollment key ID

Response 200 OK

application/json

{
    "data": {
        "cluster_name": "prod-east",
        "expired_at": "2026-12-31T23:59:59Z",
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "inserted_at": "2025-06-09T08:00:00Z",
        "key": "eyJzZXJ2ZXIiOiJodHRwczovL25ldG1ha2VyLmV4YW1wbGUuY29tIiwia2V5IjoiYWJjMTIzIn0=",
        "last_used_at": null,
        "name": "prod rollout",
        "updated_at": "2025-06-09T08:00:00Z",
        "uses_remaining": 5
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single enrollment key response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/EnrollmentKeyResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EnrollmentKeySingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

PATCH /api/v1/enrollment_keys/{id}

Update an enrollment key

Description Update expired_at or uses_remaining. Pass null to unset a nullable field.

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Enrollment key ID

Request body

application/json

{
    "expired_at": "2026-12-31T23:59:59Z",
    "name": "prod rollout",
    "uses_remaining": null
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Parameters for updating an enrollment key. Only fields that are present in the request body are updated — omitting a field leaves it unchanged.\n\n- `name`: pass a string to set a label, or `null` to clear it.\n- `uses_remaining`: pass a positive integer to set a limit, or `null` to make the key unlimited.\n- `expired_at`: pass a datetime to set expiry, or `null` to remove expiry.\n",
    "example": {
        "expired_at": "2026-12-31T23:59:59Z",
        "name": "prod rollout",
        "uses_remaining": null
    },
    "properties": {
        "expired_at": {
            "description": "Expiry datetime (ISO 8601), or null to remove expiry. Omit to leave unchanged.",
            "example": "2026-12-31T23:59:59Z",
            "format": "date-time",
            "nullable": true,
            "type": "string"
        },
        "name": {
            "description": "Human-readable label for this key, or null to clear. Omit to leave unchanged.",
            "example": "prod rollout",
            "nullable": true,
            "type": "string"
        },
        "uses_remaining": {
            "description": "Positive integer to set a use limit, or null to make the key unlimited. Omit to leave unchanged.",
            "example": 10,
            "minimum": 1,
            "nullable": true,
            "type": "integer"
        }
    },
    "title": "EnrollmentKeyUpdateRequest",
    "type": "object"
}

Response 200 OK

application/json

{
    "data": {
        "cluster_name": "prod-east",
        "expired_at": "2026-12-31T23:59:59Z",
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "inserted_at": "2025-06-09T08:00:00Z",
        "key": "eyJzZXJ2ZXIiOiJodHRwczovL25ldG1ha2VyLmV4YW1wbGUuY29tIiwia2V5IjoiYWJjMTIzIn0=",
        "last_used_at": null,
        "name": "prod rollout",
        "updated_at": "2025-06-09T08:00:00Z",
        "uses_remaining": 5
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single enrollment key response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/EnrollmentKeyResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EnrollmentKeySingleResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

DELETE /api/v1/enrollment_keys/{id}

Delete an enrollment key

Description Permanently deletes an enrollment key. Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Enrollment key ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

Nodes.Node

GET /api/v1/nodes

List all nodes

Description Returns a paginated list of all registered edge nodes with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
cluster_name query string No Filter by cluster name (exact match or wildcard: prod, east, etc.)
id_type query string No Filter by node ID type
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
last_seen_at__gte query No Filter records where last_seen_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
last_seen_at__lte query No Filter records where last_seen_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
self_update_enabled query boolean No Filter by self-update enabled status
status query string No Filter by node status
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
version query string No Filter by agent version (exact match or wildcard: 1.0.0, 1.*, etc.)

Response 200 OK

application/json

{
    "data": [
        {
            "api_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
            "cluster_name": "prod-east",
            "host_metrics_port": 49100,
            "http_port": 44000,
            "http_proxy_port": 44880,
            "id": "01234567-89ab-cdef-0123-456789abcdef",
            "id_type": "persistent",
            "inserted_at": "2025-06-09T08:00:00Z",
            "last_seen_at": "2025-06-09T08:20:00Z",
            "mdns_hostname": "node-01234567-89ab-cdef-0123-456789abcdef.local",
            "netmaker_host_id": "def67890-5678-5678-5678-567890abcdef",
            "node_name": "node-01234567-89ab-cdef-0123-456789abcdef",
            "proxy_password": "securepassword123",
            "self_update_enabled": false,
            "socks5_proxy_port": 44180,
            "ssh_port": 42222,
            "status": "healthy",
            "updated_at": "2025-06-09T08:20:00Z",
            "version": "0.1.0",
            "vpn_hostname": "node-01234567-89ab-cdef-0123-456789abcdef.cluster-prod-east.nm.internal",
            "wireguard_metrics_port": 49586
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of nodes with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/NodeResponse"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "NodePaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/nodes/{id}

Get a specific node

Description Returns details for a specific node by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Node ID

Response 200 OK

application/json

{
    "data": {
        "api_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "cluster_name": "prod-east",
        "host_metrics_port": 49100,
        "http_port": 44000,
        "http_proxy_port": 44880,
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "id_type": "persistent",
        "inserted_at": "2025-06-09T08:00:00Z",
        "last_seen_at": "2025-06-09T08:20:00Z",
        "mdns_hostname": "node-01234567-89ab-cdef-0123-456789abcdef.local",
        "netmaker_host_id": "def67890-5678-5678-5678-567890abcdef",
        "node_name": "node-01234567-89ab-cdef-0123-456789abcdef",
        "proxy_password": "securepassword123",
        "self_update_enabled": false,
        "socks5_proxy_port": 44180,
        "ssh_port": 42222,
        "status": "healthy",
        "updated_at": "2025-06-09T08:20:00Z",
        "version": "0.1.0",
        "vpn_hostname": "node-01234567-89ab-cdef-0123-456789abcdef.cluster-prod-east.nm.internal",
        "wireguard_metrics_port": 49586
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single node response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/NodeResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "NodeSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/nodes/{id}

Delete a node

Description Delete a node. Removes the Netmaker host first, then the DB row. Cascade: ssh_usernames (and their ssh_public_keys) and aliases are deleted; command_executions are kept with node_id set to NULL for history.

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Node ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

PATCH /api/v1/nodes/{id}/change_cluster

Change a node's cluster

Description Move a node to a different cluster. Performs cluster migration via Netmaker (best-effort, reconciliation worker handles failures).

Note: This endpoint is unavailable during degraded mode (503).

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Node ID

Request body

application/json

{
    "cluster_name": "prod-west"
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Request to move a node to a different cluster. Performs cluster migration via Netmaker (best-effort, reconciliation worker handles failures).",
    "example": {
        "cluster_name": "prod-west"
    },
    "properties": {
        "cluster_name": {
            "description": "Name of the target cluster to move this node to.",
            "example": "prod-west",
            "maxLength": 24,
            "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
            "type": "string"
        }
    },
    "required": [
        "cluster_name"
    ],
    "title": "ChangeClusterRequest",
    "type": "object"
}

Response 200 OK

application/json

{
    "data": {
        "api_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "cluster_name": "prod-east",
        "host_metrics_port": 49100,
        "http_port": 44000,
        "http_proxy_port": 44880,
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "id_type": "persistent",
        "inserted_at": "2025-06-09T08:00:00Z",
        "last_seen_at": "2025-06-09T08:20:00Z",
        "mdns_hostname": "node-01234567-89ab-cdef-0123-456789abcdef.local",
        "netmaker_host_id": "def67890-5678-5678-5678-567890abcdef",
        "node_name": "node-01234567-89ab-cdef-0123-456789abcdef",
        "proxy_password": "securepassword123",
        "self_update_enabled": false,
        "socks5_proxy_port": 44180,
        "ssh_port": 42222,
        "status": "healthy",
        "updated_at": "2025-06-09T08:20:00Z",
        "version": "0.1.0",
        "vpn_hostname": "node-01234567-89ab-cdef-0123-456789abcdef.cluster-prod-east.nm.internal",
        "wireguard_metrics_port": 49586
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single node response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/NodeResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "NodeSingleResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

Nodes.Alias

POST /api/v1/nodes/{node_id}/aliases

Create a new alias for a node

Description Creates a new alias and corresponding DNS entry for the specified node

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
node_id path string No Node ID

Request body

application/json

{
    "name": "web-server"
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Parameters for creating a new DNS alias for a node",
    "example": {
        "name": "web-server"
    },
    "properties": {
        "name": {
            "description": "Alias name (lowercase alphanumeric with hyphens)",
            "example": "web-server",
            "maxLength": 63,
            "minLength": 1,
            "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
            "type": "string"
        }
    },
    "required": [
        "name"
    ],
    "title": "CreateAliasRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "cluster_name": "prod",
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "inserted_at": "2024-01-15T10:30:00Z",
        "name": "web-server",
        "node_id": "01234567-89ab-cdef-0123-456789abcdef",
        "updated_at": "2024-01-15T10:30:00Z",
        "vpn_hostname": "node-web-server.cluster-prod.nm.internal"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single alias response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/AliasResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "AliasSingleResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

GET /api/v1/aliases

List all aliases

Description Returns a paginated list of node aliases with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
cluster_name query string No Filter by cluster name (exact match or wildcard: prod, east, etc.)
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
name query string No Filter by alias name (exact match or wildcard: prod, east, etc.)
node_id query string No Filter by node ID (exact match UUID)
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)

Response 200 OK

application/json

{
    "data": [
        {
            "cluster_name": "prod",
            "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
            "inserted_at": "2024-01-15T10:30:00Z",
            "name": "web-server",
            "node_id": "01234567-89ab-cdef-0123-456789abcdef",
            "updated_at": "2024-01-15T10:30:00Z",
            "vpn_hostname": "node-web-server.cluster-prod.nm.internal"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of aliases with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/AliasResponse"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "AliasPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/aliases/{id}

Get a specific alias

Description Returns details for a specific alias by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Alias ID

Response 200 OK

application/json

{
    "data": {
        "cluster_name": "prod",
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "inserted_at": "2024-01-15T10:30:00Z",
        "name": "web-server",
        "node_id": "01234567-89ab-cdef-0123-456789abcdef",
        "updated_at": "2024-01-15T10:30:00Z",
        "vpn_hostname": "node-web-server.cluster-prod.nm.internal"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single alias response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/AliasResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "AliasSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/aliases/{id}

Delete an alias

Description Deletes an alias and its corresponding DNS entry

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Alias ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

Nodes.Metrics

GET /api/v1/nodes/{node_id}/metrics

Get unified metrics for a node

Description Returns aggregated metrics from all available sources for a node: - Host metrics (Node Exporter): CPU, memory, disk, uptime - Agent metrics (agent PromEx): BEAM stats, commands, proxy, SSH, VPN, health check, Oban

Provides a complete view of node health and performance in a single request. Uses best-effort fetching - if one source fails, others are still returned.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
node_id path string No Node UUID

Response 200 OK

application/json

{
    "data": {
        "agent": {
            "application": {},
            "available": true,
            "commands": {},
            "discovery": {},
            "health_check": {},
            "oban_queues": [
                {}
            ],
            "proxy": {},
            "ssh": {},
            "vpn": {}
        },
        "cluster_name": "string",
        "host": {
            "available": true,
            "cpu": {},
            "disk": {},
            "memory": {},
            "uptime": {}
        },
        "node_id": "de6cdeeb-184d-4cdd-a56d-52986bd14811",
        "timestamp": "2022-04-13T15:42:05.901Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Complete metrics from all sources: host (Node Exporter) and agent (PromEx).\nProvides a unified view of node health and performance.\nUses best-effort fetching - if one source fails, it's marked as unavailable.\n",
    "properties": {
        "data": {
            "properties": {
                "agent": {
                    "description": "Agent application metrics from PromEx",
                    "properties": {
                        "application": {
                            "description": "BEAM VM stats",
                            "nullable": true,
                            "type": "object"
                        },
                        "available": {
                            "description": "Whether agent metrics were successfully fetched",
                            "type": "boolean"
                        },
                        "commands": {
                            "description": "Command execution metrics",
                            "nullable": true,
                            "type": "object"
                        },
                        "discovery": {
                            "description": "Admin discovery metrics",
                            "nullable": true,
                            "type": "object"
                        },
                        "health_check": {
                            "description": "Health check report metrics (HTTP fallback mode)",
                            "nullable": true,
                            "type": "object"
                        },
                        "oban_queues": {
                            "description": "Oban job queue states",
                            "items": {
                                "type": "object"
                            },
                            "nullable": true,
                            "type": "array"
                        },
                        "proxy": {
                            "description": "Proxy server metrics",
                            "nullable": true,
                            "type": "object"
                        },
                        "ssh": {
                            "description": "SSH server metrics",
                            "nullable": true,
                            "type": "object"
                        },
                        "vpn": {
                            "description": "VPN config pull metrics",
                            "nullable": true,
                            "type": "object"
                        }
                    },
                    "type": "object"
                },
                "cluster_name": {
                    "description": "Name of the cluster this node belongs to",
                    "type": "string"
                },
                "host": {
                    "description": "Host-level metrics from Node Exporter",
                    "properties": {
                        "available": {
                            "description": "Whether host metrics were successfully fetched",
                            "type": "boolean"
                        },
                        "cpu": {
                            "description": "CPU metrics",
                            "nullable": true,
                            "type": "object"
                        },
                        "disk": {
                            "description": "Disk metrics",
                            "nullable": true,
                            "type": "object"
                        },
                        "memory": {
                            "description": "Memory metrics",
                            "nullable": true,
                            "type": "object"
                        },
                        "uptime": {
                            "description": "Uptime information",
                            "nullable": true,
                            "type": "object"
                        }
                    },
                    "type": "object"
                },
                "node_id": {
                    "description": "Node unique identifier",
                    "format": "uuid",
                    "type": "string"
                },
                "timestamp": {
                    "description": "When the metrics were collected (ISO 8601 format)",
                    "format": "date-time",
                    "type": "string"
                }
            },
            "required": [
                "node_id",
                "cluster_name",
                "timestamp"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "UnifiedMetricsResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

GET /api/v1/nodes/{node_id}/metrics/host

Get host metrics for a node

Description Returns host-level system metrics from Node Exporter: - CPU: cores, load averages - Memory: usage, total/available/used in bytes and GB - Disk: usage, total/available/used for root filesystem - Uptime: seconds and human-readable format

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
node_id path string No Node UUID

Response 200 OK

application/json

{
    "cluster_name": "production",
    "cpu": {
        "cores": 4,
        "load_15m": 0.9,
        "load_1m": 1.2,
        "load_5m": 1.1,
        "usage_percent": 25.5
    },
    "disk": {
        "available_bytes": 58249036800,
        "available_gb": 54.2,
        "total_bytes": 107374182400,
        "total_gb": 100.0,
        "usage_percent": 45.8,
        "used_bytes": 49125145600,
        "used_gb": 45.8
    },
    "memory": {
        "available_bytes": 2814377984,
        "available_gb": 2.6,
        "total_bytes": 8589934592,
        "total_gb": 8.0,
        "usage_percent": 67.3,
        "used_bytes": 5775556608,
        "used_gb": 5.4
    },
    "node_id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": "2025-01-15T15:30:00Z",
    "uptime": {
        "human": "1d 1h 1m",
        "seconds": 90061
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Host-level system metrics from Node Exporter (CPU, memory, disk, uptime).\n",
    "example": {
        "cluster_name": "production",
        "cpu": {
            "cores": 4,
            "load_15m": 0.9,
            "load_1m": 1.2,
            "load_5m": 1.1,
            "usage_percent": 25.5
        },
        "disk": {
            "available_bytes": 58249036800,
            "available_gb": 54.2,
            "total_bytes": 107374182400,
            "total_gb": 100.0,
            "usage_percent": 45.8,
            "used_bytes": 49125145600,
            "used_gb": 45.8
        },
        "memory": {
            "available_bytes": 2814377984,
            "available_gb": 2.6,
            "total_bytes": 8589934592,
            "total_gb": 8.0,
            "usage_percent": 67.3,
            "used_bytes": 5775556608,
            "used_gb": 5.4
        },
        "node_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2025-01-15T15:30:00Z",
        "uptime": {
            "human": "1d 1h 1m",
            "seconds": 90061
        }
    },
    "properties": {
        "cluster_name": {
            "description": "Name of the cluster this node belongs to",
            "type": "string"
        },
        "cpu": {
            "description": "CPU metrics",
            "properties": {
                "cores": {
                    "description": "Number of CPU cores detected on the system",
                    "nullable": true,
                    "type": "integer"
                },
                "load_15m": {
                    "description": "System load average over the last 15 minutes",
                    "nullable": true,
                    "type": "number"
                },
                "load_1m": {
                    "description": "System load average over the last 1 minute",
                    "nullable": true,
                    "type": "number"
                },
                "load_5m": {
                    "description": "System load average over the last 5 minutes",
                    "nullable": true,
                    "type": "number"
                }
            },
            "type": "object"
        },
        "disk": {
            "description": "Disk metrics for root filesystem (/)",
            "properties": {
                "available_bytes": {
                    "description": "Available disk space in bytes",
                    "nullable": true,
                    "type": "integer"
                },
                "available_gb": {
                    "description": "Available disk space in gigabytes (GB)",
                    "nullable": true,
                    "type": "number"
                },
                "total_bytes": {
                    "description": "Total disk space in bytes",
                    "nullable": true,
                    "type": "integer"
                },
                "total_gb": {
                    "description": "Total disk space in gigabytes (GB)",
                    "nullable": true,
                    "type": "number"
                },
                "usage_percent": {
                    "description": "Disk usage percentage calculated as (total - available) / total * 100",
                    "nullable": true,
                    "type": "number"
                },
                "used_bytes": {
                    "description": "Used disk space in bytes (calculated as total - available)",
                    "nullable": true,
                    "type": "integer"
                },
                "used_gb": {
                    "description": "Used disk space in gigabytes (GB)",
                    "nullable": true,
                    "type": "number"
                }
            },
            "type": "object"
        },
        "memory": {
            "description": "Memory metrics",
            "properties": {
                "available_bytes": {
                    "description": "Available RAM in bytes (includes buffers/cache)",
                    "nullable": true,
                    "type": "integer"
                },
                "available_gb": {
                    "description": "Available RAM in gigabytes (GB)",
                    "nullable": true,
                    "type": "number"
                },
                "total_bytes": {
                    "description": "Total RAM in bytes",
                    "nullable": true,
                    "type": "integer"
                },
                "total_gb": {
                    "description": "Total RAM in gigabytes (GB)",
                    "nullable": true,
                    "type": "number"
                },
                "usage_percent": {
                    "description": "Memory usage percentage calculated as (total - available) / total * 100",
                    "nullable": true,
                    "type": "number"
                },
                "used_bytes": {
                    "description": "Used RAM in bytes (calculated as total - available)",
                    "nullable": true,
                    "type": "integer"
                },
                "used_gb": {
                    "description": "Used RAM in gigabytes (GB)",
                    "nullable": true,
                    "type": "number"
                }
            },
            "type": "object"
        },
        "node_id": {
            "description": "Node unique identifier",
            "format": "uuid",
            "type": "string"
        },
        "timestamp": {
            "description": "When the metrics were collected (ISO 8601 format)",
            "format": "date-time",
            "type": "string"
        },
        "uptime": {
            "description": "System uptime information",
            "properties": {
                "human": {
                    "description": "Human-readable uptime format (e.g., '1d 2h 30m', '5h 15m', '30m')",
                    "nullable": true,
                    "type": "string"
                },
                "seconds": {
                    "description": "System uptime in seconds since last boot",
                    "nullable": true,
                    "type": "integer"
                }
            },
            "type": "object"
        }
    },
    "required": [
        "node_id",
        "cluster_name",
        "timestamp"
    ],
    "title": "HostMetricsResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

GET /api/v1/nodes/{node_id}/metrics/agent

Get agent metrics for a node

Description Returns application-level metrics from the edge_agent PromEx: - Application: uptime, BEAM stats (processes, memory breakdown) - Commands: sync/enqueue/complete/report statistics - Discovery: admin discovery scan metrics - Proxy: HTTP and SOCKS5 connection and blocked-request statistics - SSH: authentication attempts and connection count - VPN: config pull count (daily backstop for DNS recovery) - Health Check: fallback health report count (only non-zero when VPN is down) - Oban: job queue states (available, executing, completed, etc.)

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
node_id path string No Node UUID

Response 200 OK

application/json

{
    "data": {
        "application": {
            "memory_binary_bytes": 2097152,
            "memory_binary_mb": 2.0,
            "memory_ets_bytes": 4194304,
            "memory_ets_mb": 4.0,
            "memory_processes_bytes": 83886080,
            "memory_processes_mb": 80.0,
            "memory_total_bytes": 125829120,
            "memory_total_mb": 120.0,
            "process_count": 342,
            "uptime_human": "2d 0h 0m",
            "uptime_seconds": 172800
        },
        "cluster_name": "production",
        "commands": {
            "completed_total": 150,
            "enqueued_total": 152,
            "reported_total": 150,
            "synced_total": 156
        },
        "discovery": {
            "admins_found_last": 5,
            "scans_total": 48
        },
        "health_check": {
            "reports_total": 0
        },
        "node_id": "550e8400-e29b-41d4-a716-446655440000",
        "oban_queues": [
            {
                "available": 0,
                "completed": 245,
                "discarded": 1,
                "executing": 1,
                "queue": "default",
                "retryable": 0
            },
            {
                "available": 0,
                "completed": 150,
                "discarded": 0,
                "executing": 0,
                "queue": "commands",
                "retryable": 0
            }
        ],
        "proxy": {
            "bytes_down_mb": 900.0,
            "bytes_down_total": 943718400,
            "bytes_up_mb": 150.0,
            "bytes_up_total": 157286400,
            "http_blocked_by_reason": {
                "agent_port_blocked": 1,
                "docker_network_blocked": 4,
                "localhost_blocked": 8,
                "metadata_service_blocked": 2
            },
            "http_blocked_total": 15,
            "http_connections_total": 523,
            "socks5_blocked_by_reason": {
                "docker_port_blocked": 2,
                "localhost_blocked": 3
            },
            "socks5_blocked_total": 5,
            "socks5_connections_total": 87,
            "tunnels_closed_deadline_total": 12,
            "tunnels_closed_drain_timeout_total": 3,
            "tunnels_closed_normal_total": 590,
            "tunnels_closed_total": 605
        },
        "ssh": {
            "authentications_total": 45,
            "connections_total": 44
        },
        "timestamp": "2025-01-15T15:30:00Z",
        "vpn": {
            "pulls_total": 7
        }
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Application-level metrics from edge_agent PromEx (BEAM stats, Oban, business metrics).\n",
    "example": {
        "data": {
            "application": {
                "memory_binary_bytes": 2097152,
                "memory_binary_mb": 2.0,
                "memory_ets_bytes": 4194304,
                "memory_ets_mb": 4.0,
                "memory_processes_bytes": 83886080,
                "memory_processes_mb": 80.0,
                "memory_total_bytes": 125829120,
                "memory_total_mb": 120.0,
                "process_count": 342,
                "uptime_human": "2d 0h 0m",
                "uptime_seconds": 172800
            },
            "cluster_name": "production",
            "commands": {
                "completed_total": 150,
                "enqueued_total": 152,
                "reported_total": 150,
                "synced_total": 156
            },
            "discovery": {
                "admins_found_last": 5,
                "scans_total": 48
            },
            "health_check": {
                "reports_total": 0
            },
            "node_id": "550e8400-e29b-41d4-a716-446655440000",
            "oban_queues": [
                {
                    "available": 0,
                    "completed": 245,
                    "discarded": 1,
                    "executing": 1,
                    "queue": "default",
                    "retryable": 0
                },
                {
                    "available": 0,
                    "completed": 150,
                    "discarded": 0,
                    "executing": 0,
                    "queue": "commands",
                    "retryable": 0
                }
            ],
            "proxy": {
                "bytes_down_mb": 900.0,
                "bytes_down_total": 943718400,
                "bytes_up_mb": 150.0,
                "bytes_up_total": 157286400,
                "http_blocked_by_reason": {
                    "agent_port_blocked": 1,
                    "docker_network_blocked": 4,
                    "localhost_blocked": 8,
                    "metadata_service_blocked": 2
                },
                "http_blocked_total": 15,
                "http_connections_total": 523,
                "socks5_blocked_by_reason": {
                    "docker_port_blocked": 2,
                    "localhost_blocked": 3
                },
                "socks5_blocked_total": 5,
                "socks5_connections_total": 87,
                "tunnels_closed_deadline_total": 12,
                "tunnels_closed_drain_timeout_total": 3,
                "tunnels_closed_normal_total": 590,
                "tunnels_closed_total": 605
            },
            "ssh": {
                "authentications_total": 45,
                "connections_total": 44
            },
            "timestamp": "2025-01-15T15:30:00Z",
            "vpn": {
                "pulls_total": 7
            }
        }
    },
    "properties": {
        "data": {
            "properties": {
                "application": {
                    "description": "Application health and BEAM VM stats",
                    "properties": {
                        "memory_binary_bytes": {
                            "description": "Memory used by binaries in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_binary_mb": {
                            "description": "Memory used by binaries in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_ets_bytes": {
                            "description": "Memory used by ETS tables in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_ets_mb": {
                            "description": "Memory used by ETS tables in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_processes_bytes": {
                            "description": "Memory used by BEAM processes in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_processes_mb": {
                            "description": "Memory used by BEAM processes in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "memory_total_bytes": {
                            "description": "Total BEAM memory allocated in bytes",
                            "nullable": true,
                            "type": "integer"
                        },
                        "memory_total_mb": {
                            "description": "Total BEAM memory in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "process_count": {
                            "description": "Number of BEAM processes running",
                            "nullable": true,
                            "type": "integer"
                        },
                        "uptime_human": {
                            "description": "Human-readable uptime (e.g., '2d 5h 30m')",
                            "nullable": true,
                            "type": "string"
                        },
                        "uptime_seconds": {
                            "description": "Application uptime in seconds",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "cluster_name": {
                    "description": "Name of the cluster this node belongs to",
                    "type": "string"
                },
                "commands": {
                    "description": "Command execution metrics",
                    "properties": {
                        "completed_total": {
                            "description": "Total command executions completed",
                            "nullable": true,
                            "type": "integer"
                        },
                        "enqueued_total": {
                            "description": "Total command executions enqueued for local execution",
                            "nullable": true,
                            "type": "integer"
                        },
                        "reported_total": {
                            "description": "Total results reported back to admin",
                            "nullable": true,
                            "type": "integer"
                        },
                        "synced_total": {
                            "description": "Total command sync calls made to admin",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "discovery": {
                    "description": "Admin discovery metrics",
                    "properties": {
                        "admins_found_last": {
                            "description": "Number of admins discovered during the last scan",
                            "nullable": true,
                            "type": "integer"
                        },
                        "scans_total": {
                            "description": "Total discovery scans performed",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "health_check": {
                    "description": "Health check report metrics (only active when VPN is down and agent is in HTTP fallback mode)",
                    "properties": {
                        "reports_total": {
                            "description": "Total health check reports sent to admin via HTTP fallback",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "node_id": {
                    "description": "Node unique identifier",
                    "format": "uuid",
                    "type": "string"
                },
                "oban_queues": {
                    "description": "Oban job queue states",
                    "items": {
                        "properties": {
                            "available": {
                                "description": "Jobs available to run",
                                "type": "integer"
                            },
                            "completed": {
                                "description": "Completed jobs",
                                "type": "integer"
                            },
                            "discarded": {
                                "description": "Discarded jobs (max retries exceeded)",
                                "type": "integer"
                            },
                            "executing": {
                                "description": "Jobs currently executing",
                                "type": "integer"
                            },
                            "queue": {
                                "description": "Queue name (e.g., 'default', 'commands')",
                                "type": "string"
                            },
                            "retryable": {
                                "description": "Jobs awaiting retry",
                                "type": "integer"
                            }
                        },
                        "type": "object"
                    },
                    "type": "array"
                },
                "proxy": {
                    "description": "Proxy server connection and security metrics",
                    "properties": {
                        "bytes_down_mb": {
                            "description": "Cumulative target→client bytes in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "bytes_down_total": {
                            "description": "Cumulative bytes forwarded target→client across all tunnels",
                            "nullable": true,
                            "type": "integer"
                        },
                        "bytes_up_mb": {
                            "description": "Cumulative client→target bytes in MB",
                            "nullable": true,
                            "type": "number"
                        },
                        "bytes_up_total": {
                            "description": "Cumulative bytes forwarded client→target across all tunnels",
                            "nullable": true,
                            "type": "integer"
                        },
                        "http_blocked_by_reason": {
                            "additionalProperties": {
                                "type": "integer"
                            },
                            "description": "HTTP blocked requests grouped by reason",
                            "example": {
                                "docker_network_blocked": 3,
                                "docker_port_blocked": 1,
                                "localhost_blocked": 5,
                                "metadata_service_blocked": 2
                            },
                            "nullable": true,
                            "type": "object"
                        },
                        "http_blocked_total": {
                            "description": "Total HTTP requests blocked by security rules",
                            "nullable": true,
                            "type": "integer"
                        },
                        "http_connections_total": {
                            "description": "Total HTTP proxy connections",
                            "nullable": true,
                            "type": "integer"
                        },
                        "socks5_blocked_by_reason": {
                            "additionalProperties": {
                                "type": "integer"
                            },
                            "description": "SOCKS5 blocked requests grouped by reason",
                            "example": {
                                "kubernetes_port_blocked": 2,
                                "localhost_blocked": 3
                            },
                            "nullable": true,
                            "type": "object"
                        },
                        "socks5_blocked_total": {
                            "description": "Total SOCKS5 requests blocked by security rules",
                            "nullable": true,
                            "type": "integer"
                        },
                        "socks5_connections_total": {
                            "description": "Total SOCKS5 proxy connections",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_deadline_total": {
                            "description": "Tunnels force-closed by the total-duration deadline (slowloris defence)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_drain_timeout_total": {
                            "description": "Tunnels force-closed after exceeding the graceful drain grace window",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_normal_total": {
                            "description": "Tunnels closed normally (both sides EOF'd cleanly)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "tunnels_closed_total": {
                            "description": "Total tunnels that reached end-of-life (all close reasons combined)",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "ssh": {
                    "description": "SSH server metrics",
                    "properties": {
                        "authentications_total": {
                            "description": "Total SSH authentication attempts (all methods)",
                            "nullable": true,
                            "type": "integer"
                        },
                        "connections_total": {
                            "description": "Total SSH connections established",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                },
                "timestamp": {
                    "description": "When the metrics were collected (ISO 8601 format)",
                    "format": "date-time",
                    "type": "string"
                },
                "vpn": {
                    "description": "VPN connectivity metrics",
                    "properties": {
                        "pulls_total": {
                            "description": "Total VPN config pulls performed (daily backstop for DNS recovery after netclient restart)",
                            "nullable": true,
                            "type": "integer"
                        }
                    },
                    "type": "object"
                }
            },
            "type": "object"
        }
    },
    "title": "AgentMetricsResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

Commands.Command

POST /api/v1/commands

Create a new command

Description Create a new command for execution on nodes using flexible targeting options.

Targeting types: - 'all': Target all nodes (with optional filters) - 'nodes': Target specific nodes by IDs (with optional filters) - 'clusters': Target specific clusters by names (with optional filters)

Node and cluster filters can be applied to further refine targeting.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Request body

application/json

{
    "command_text": "ABC=value\necho $ABC\nsudo docker ps",
    "targeting": {
        "node_filters": {
            "id_type": "persistent",
            "status": "healthy"
        },
        "node_ids": [
            "01234567-89ab-cdef-0123-456789abcdef"
        ],
        "type": "nodes"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Create a new command with flexible targeting options",
    "example": {
        "command_text": "ABC=value\necho $ABC\nsudo docker ps",
        "targeting": {
            "node_filters": {
                "id_type": "persistent",
                "status": "healthy"
            },
            "node_ids": [
                "01234567-89ab-cdef-0123-456789abcdef"
            ],
            "type": "nodes"
        }
    },
    "properties": {
        "command_text": {
            "description": "Multi-line shell script/commands to execute",
            "example": "ABC=value\necho $ABC\nsystemctl restart nginx",
            "minLength": 1,
            "type": "string"
        },
        "expired_at": {
            "description": "Deadline after which pending/sent executions are automatically expired. Must be in the future. Immutable after creation.",
            "example": "2025-12-31T23:59:59Z",
            "format": "date-time",
            "nullable": true,
            "type": "string"
        },
        "targeting": {
            "example": {
                "cluster_filters": {
                    "name": "*prod*"
                },
                "cluster_names": [
                    "prod",
                    "staging"
                ],
                "node_filters": {
                    "id_type": "persistent",
                    "status": "healthy"
                },
                "type": "clusters"
            },
            "properties": {
                "cluster_filters": {
                    "additionalProperties": false,
                    "description": "Optional filters to apply to target clusters (AND logic with node_filters). Supports all cluster list filters.",
                    "properties": {
                        "has_node_limit": {
                            "description": "Filter clusters that have (true) or do not have (false) a node limit set",
                            "type": "boolean"
                        },
                        "inserted_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters inserted after or on this date"
                        },
                        "inserted_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters inserted before or on this date"
                        },
                        "ipv4_range": {
                            "description": "Filter by IPv4 range (CIDR notation)",
                            "type": "string"
                        },
                        "name": {
                            "description": "Filter by cluster name (exact match or wildcard: prod*, *staging, etc.)",
                            "type": "string"
                        },
                        "node_count": {
                            "description": "Filter by exact node count",
                            "type": "integer"
                        },
                        "node_count__gte": {
                            "description": "Filter by node count greater than or equal to",
                            "type": "integer"
                        },
                        "node_count__lte": {
                            "description": "Filter by node count less than or equal to",
                            "type": "integer"
                        },
                        "updated_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters updated after or on this datetime"
                        },
                        "updated_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters updated before or on this datetime"
                        }
                    },
                    "type": "object"
                },
                "cluster_names": {
                    "description": "Array of cluster names (required when type is 'clusters') (will always be deduplicated)",
                    "example": [
                        "prod",
                        "staging"
                    ],
                    "items": {
                        "type": "string"
                    },
                    "type": "array"
                },
                "node_filters": {
                    "additionalProperties": false,
                    "description": "Optional filters to apply to target nodes (AND logic with cluster_filters). Supports all node list filters except cluster_name.",
                    "properties": {
                        "cluster_name": {
                            "description": "Filter by cluster name (exact match or wildcard: prod*, *staging, etc.)",
                            "type": "string"
                        },
                        "id_type": {
                            "description": "Filter by node ID type",
                            "enum": [
                                "persistent",
                                "random"
                            ],
                            "type": "string"
                        },
                        "inserted_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes inserted after or on this date"
                        },
                        "inserted_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes inserted before or on this date"
                        },
                        "last_seen_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes last seen after or on this datetime"
                        },
                        "last_seen_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes last seen before or on this datetime"
                        },
                        "self_update_enabled": {
                            "description": "Filter by self-update enabled status",
                            "type": "boolean"
                        },
                        "status": {
                            "description": "Filter by node status",
                            "enum": [
                                "healthy",
                                "unhealthy",
                                "unreachable"
                            ],
                            "type": "string"
                        },
                        "updated_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes updated after or on this datetime"
                        },
                        "updated_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes updated before or on this datetime"
                        },
                        "version": {
                            "description": "Filter by node version (exact match or wildcard: 1.0.0, 1.*, etc.)",
                            "type": "string"
                        }
                    },
                    "type": "object"
                },
                "node_ids": {
                    "description": "Array of node IDs (required when type is 'nodes') (will always be deduplicated)",
                    "example": [
                        "01234567-89ab-cdef-0123-456789abcdef",
                        "fedcba98-7654-3210-fedc-ba9876543210"
                    ],
                    "items": {
                        "format": "uuid",
                        "type": "string"
                    },
                    "type": "array"
                },
                "type": {
                    "description": "Targeting strategy: 'all' for all nodes, 'nodes' for specific nodes, 'clusters' for specific clusters",
                    "enum": [
                        "all",
                        "nodes",
                        "clusters"
                    ],
                    "type": "string"
                }
            },
            "required": [
                "type"
            ],
            "type": "object"
        },
        "timeout": {
            "description": "Command timeout in milliseconds (optional, null or omitted means no timeout, must be > 0)",
            "example": 30000,
            "minimum": 1,
            "nullable": true,
            "type": "integer"
        }
    },
    "required": [
        "command_text",
        "targeting"
    ],
    "title": "CommandCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "command_text": "ABC=value\necho $ABC\nsystemctl restart nginx",
        "expired_at": "2025-12-31T23:59:59Z",
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-17T10:30:00Z",
        "targeting": {
            "node_filters": {
                "status": "healthy"
            },
            "node_ids": [
                "01234567-89ab-cdef-0123-456789abcdef"
            ],
            "type": "nodes"
        },
        "timeout": 30000,
        "updated_at": "2025-06-17T10:30:00Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single command response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/CommandResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "CommandSingleResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

GET /api/v1/commands

List all commands

Description Returns a paginated list of all commands with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
command_text query string No Filter by command text (exact match or wildcard: ls, docker*, etc.)
expired_at__gte query No Filter records where expired_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
expired_at__lte query No Filter records where expired_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
has_expired_at query boolean No Filter by whether an expiration is set: true returns commands with expired_at, false returns commands without
has_timeout query boolean No Filter by whether a timeout is set: true returns commands with a timeout, false returns commands without
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
timeout__gte query integer No Filter commands with timeout greater than or equal to this value (milliseconds)
timeout__lte query integer No Filter commands with timeout less than or equal to this value (milliseconds)
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)

Response 200 OK

application/json

{
    "data": [
        {
            "command_text": "ABC=value\necho $ABC\nsystemctl restart nginx",
            "expired_at": "2025-12-31T23:59:59Z",
            "id": "01234567-89ab-cdef-0123-456789abcdef",
            "inserted_at": "2025-06-17T10:30:00Z",
            "targeting": {
                "node_filters": {
                    "status": "healthy"
                },
                "node_ids": [
                    "01234567-89ab-cdef-0123-456789abcdef"
                ],
                "type": "nodes"
            },
            "timeout": 30000,
            "updated_at": "2025-06-17T10:30:00Z"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of commands with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/CommandResponse"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "CommandPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/commands/{id}

Get a specific command

Description Returns details for a specific command by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Command ID

Response 200 OK

application/json

{
    "data": {
        "command_text": "ABC=value\necho $ABC\nsystemctl restart nginx",
        "expired_at": "2025-12-31T23:59:59Z",
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-17T10:30:00Z",
        "targeting": {
            "node_filters": {
                "status": "healthy"
            },
            "node_ids": [
                "01234567-89ab-cdef-0123-456789abcdef"
            ],
            "type": "nodes"
        },
        "timeout": 30000,
        "updated_at": "2025-06-17T10:30:00Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single command response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/CommandResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "CommandSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/commands/{id}

Delete a command

Description Delete a command and all its related command executions (cascaded deletion).

Only commands where ALL executions are completed can be deleted. Attempting to delete a command with pending or sent executions will return 409.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Command ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Commands.CommandExecution

GET /api/v1/command_executions

List command executions

Description Returns a paginated list of command executions with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
cancelled_at__gte query No Filter records where cancelled_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
cancelled_at__lte query No Filter records where cancelled_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
cluster_name query string No Filter by cluster name via node's cluster (exact match or wildcard: prod, staging, etc.)
command_id query string No Filter by command ID
completed_at__gte query No Filter records where completed_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
completed_at__lte query No Filter records where completed_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
exit_code query integer No Filter by exact exit code
exit_code__gte query integer No Filter executions with exit code greater than or equal to this value (e.g. 1 for all failures)
exit_code__lte query integer No Filter executions with exit code less than or equal to this value
has_cluster query boolean No Filter by cluster_id presence (true = cluster-wide executions, false = non-cluster-wide)
has_output query boolean No Filter by whether output is present: true returns executions with output, false returns executions with no output
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
node_id query string No Filter by node ID
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
output query string No Text search in output (exact match or wildcard: error, *failed, etc.)
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
sent_at__gte query No Filter records where sent_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
sent_at__lte query No Filter records where sent_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
status query string No Filter by execution status
target_all query boolean No Filter by target_all flag
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)

Response 200 OK

application/json

{
    "data": [
        {
            "cluster_name": "prod-east",
            "command_id": "fedcba98-7654-3210-fedc-ba9876543210",
            "command_text": "echo hello\nls -la",
            "completed_at": "2025-06-17T10:31:00Z",
            "exit_code": 5,
            "id": "01234567-89ab-cdef-0123-456789abcdef",
            "inserted_at": "2025-06-17T10:30:00Z",
            "node_id": "abcdef01-2345-6789-abcd-ef0123456789",
            "output": "$ ABC=value\n$ echo $ABC\nvalue\n$ systemctl restart nginx\nFailed to restart nginx.service: Unit not found\n",
            "sent_at": "2025-06-17T10:30:00Z",
            "status": "completed",
            "target_all": false,
            "updated_at": "2025-06-17T10:31:00Z"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of command executions with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/CommandExecutionResponse"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "CommandExecutionPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/command_executions/{id}

Get a specific command execution

Description Returns details for a specific command execution by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Command Execution ID

Response 200 OK

application/json

{
    "data": {
        "cluster_name": "prod-east",
        "command_id": "fedcba98-7654-3210-fedc-ba9876543210",
        "command_text": "echo hello\nls -la",
        "completed_at": "2025-06-17T10:31:00Z",
        "exit_code": 5,
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-17T10:30:00Z",
        "node_id": "abcdef01-2345-6789-abcd-ef0123456789",
        "output": "$ ABC=value\n$ echo $ABC\nvalue\n$ systemctl restart nginx\nFailed to restart nginx.service: Unit not found\n",
        "sent_at": "2025-06-17T10:30:00Z",
        "status": "completed",
        "target_all": false,
        "updated_at": "2025-06-17T10:31:00Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single command execution response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/CommandExecutionResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "CommandExecutionSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/command_executions/{id}

Delete a command execution

Description Delete a specific command execution.

Only completed, cancelled, or expired executions can be deleted. Attempting to delete pending or sent executions will return 409.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Command Execution ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

PATCH /api/v1/command_executions/{id}/cancel

Cancel a command execution

Description Attempts to cancel a command execution. Behavior depends on current status:

  • pending: Immediately marked cancelled in the database (command never ran).
  • sent: Sends cancellation request to agent (best-effort, async). The agent is the source of truth — if it already ran the command, it reports back the real result and the execution is marked completed. If the agent honoured the cancellation (exit code 143), it is marked cancelled.
  • completed / cancelled: Returns 409 conflict (already terminal).

Returns 200 if cancellation was initiated. For sent executions, poll status to confirm the outcome.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Command Execution ID

Response 200 OK

application/json

{
    "data": {
        "result": "cancellation request sent"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Response from command execution cancellation request",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/CancelExecutionData"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "CancelExecutionResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Response 503 Service Unavailable

application/json

{
    "error": {
        "code": "service_unavailable",
        "message": "Downstream dependency unreachable"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "503 Service Unavailable",
    "example": {
        "error": {
            "code": "service_unavailable",
            "message": "Downstream dependency unreachable"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "service_unavailable",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Downstream dependency unreachable",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ServiceUnavailableResponse",
    "type": "object"
}

Ssh.SshUsername

POST /api/v1/nodes/{node_id}/ssh_usernames

Create SSH username

Description Create a new SSH username for a specific node, optionally with public keys and/or password

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
node_id path string No Node ID to create SSH username for

Request body

application/json

{
    "password": "MySecurePassword123!",
    "public_keys": [
        {
            "key_name": "laptop",
            "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop"
        },
        {
            "key_name": "ci",
            "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... ci@deploy"
        }
    ],
    "username": "admin"
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Create a new SSH username for a node, optionally with password and/or public keys",
    "example": {
        "password": "MySecurePassword123!",
        "public_keys": [
            {
                "key_name": "laptop",
                "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop"
            },
            {
                "key_name": "ci",
                "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... ci@deploy"
            }
        ],
        "username": "admin"
    },
    "properties": {
        "password": {
            "description": "Optional password for username/password SSH authentication (12-128 characters if provided, will be hashed with Argon2)",
            "example": "MySecurePassword123!",
            "maxLength": 128,
            "minLength": 12,
            "nullable": true,
            "type": "string"
        },
        "public_keys": {
            "description": "Optional array of SSH public keys to create with this username",
            "items": {
                "properties": {
                    "key_name": {
                        "description": "Human-readable name for the SSH key",
                        "example": "laptop",
                        "type": "string"
                    },
                    "public_key": {
                        "description": "SSH public key in OpenSSH format",
                        "example": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
                        "type": "string"
                    }
                },
                "required": [
                    "key_name",
                    "public_key"
                ],
                "type": "object"
            },
            "nullable": true,
            "type": "array"
        },
        "username": {
            "description": "SSH username for node access (3-32 characters, must start with letter or underscore, lowercase letters/digits/hyphens/underscores only)",
            "example": "admin",
            "maxLength": 32,
            "minLength": 3,
            "pattern": "^[a-z_][a-z0-9_-]*$",
            "type": "string"
        }
    },
    "required": [
        "username"
    ],
    "title": "SshUsernameCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "has_password": true,
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-23T10:30:00Z",
        "node_id": "fedcba98-7654-3210-fedc-ba9876543210",
        "public_keys": [
            {
                "id": "fedcba98-7654-3210-fedc-ba9876543210",
                "inserted_at": "2025-06-23T10:30:00Z",
                "key_name": "laptop",
                "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
                "ssh_username_id": "01234567-89ab-cdef-0123-456789abcdef",
                "updated_at": "2025-06-23T10:30:00Z"
            }
        ],
        "updated_at": "2025-06-23T10:30:00Z",
        "username": "admin"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single SSH username response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/SshUsername"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SshUsernameSingleResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

GET /api/v1/ssh_usernames

List SSH usernames

Description Returns a paginated list of SSH usernames with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
cluster_name query string No Filter by cluster name via node's cluster (exact match or wildcard: prod, east, etc.)
has_password query boolean No Filter by whether username has password configured
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
node_id query string No Filter by node ID
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
username query string No Filter by username (exact match or wildcard: root, admin, etc.)

Response 200 OK

application/json

{
    "data": [
        {
            "has_password": true,
            "id": "01234567-89ab-cdef-0123-456789abcdef",
            "inserted_at": "2025-06-23T10:30:00Z",
            "node_id": "fedcba98-7654-3210-fedc-ba9876543210",
            "public_keys": [
                {
                    "id": "fedcba98-7654-3210-fedc-ba9876543210",
                    "inserted_at": "2025-06-23T10:30:00Z",
                    "key_name": "laptop",
                    "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
                    "ssh_username_id": "01234567-89ab-cdef-0123-456789abcdef",
                    "updated_at": "2025-06-23T10:30:00Z"
                }
            ],
            "updated_at": "2025-06-23T10:30:00Z",
            "username": "admin"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of SSH usernames with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/SshUsername"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SshUsernamePaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/ssh_usernames/{id}

Get SSH username

Description Get a specific SSH username by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No SSH username ID

Response 200 OK

application/json

{
    "data": {
        "has_password": true,
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-23T10:30:00Z",
        "node_id": "fedcba98-7654-3210-fedc-ba9876543210",
        "public_keys": [
            {
                "id": "fedcba98-7654-3210-fedc-ba9876543210",
                "inserted_at": "2025-06-23T10:30:00Z",
                "key_name": "laptop",
                "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
                "ssh_username_id": "01234567-89ab-cdef-0123-456789abcdef",
                "updated_at": "2025-06-23T10:30:00Z"
            }
        ],
        "updated_at": "2025-06-23T10:30:00Z",
        "username": "admin"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single SSH username response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/SshUsername"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SshUsernameSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/ssh_usernames/{id}

Delete SSH username

Description Delete an SSH username and all associated public keys

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No SSH username ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Ssh.SshPublicKey

POST /api/v1/ssh_usernames/{ssh_username_id}/ssh_public_keys

Create SSH public key

Description Create a new SSH public key for a specific SSH username. The key must be in valid OpenSSH format.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
ssh_username_id path string No SSH username ID to create public key for

Request body

application/json

{
    "key_name": "laptop-key",
    "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop"
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Create a new SSH public key for a username. The key must be in valid OpenSSH format.",
    "example": {
        "key_name": "laptop-key",
        "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop"
    },
    "properties": {
        "key_name": {
            "description": "Human-readable name for the SSH key",
            "example": "laptop-key",
            "maxLength": 255,
            "minLength": 1,
            "type": "string"
        },
        "public_key": {
            "description": "SSH public key in OpenSSH format (algorithm base64data [comment]). Supported algorithms: ssh-ed25519 (recommended), ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa",
            "example": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
            "pattern": "^(ssh-ed25519|ecdsa-sha2-nistp(?:256|384|521)|ssh-rsa)\\s+([A-Za-z0-9+/]+=*)\\s*(.*)$",
            "type": "string"
        }
    },
    "required": [
        "public_key",
        "key_name"
    ],
    "title": "SshPublicKeyCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-23T10:30:00Z",
        "key_name": "laptop-key",
        "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
        "ssh_username_id": "fedcba98-7654-3210-fedc-ba9876543210",
        "updated_at": "2025-06-23T10:30:00Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single SSH public key response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/SshPublicKey"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SshPublicKeySingleResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

GET /api/v1/ssh_public_keys

List SSH public keys

Description Returns a paginated list of SSH public keys with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
cluster_name query string No Filter by cluster name via node's cluster (exact match or wildcard: prod, east, etc.)
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
key_name query string No Filter by key name (exact match or wildcard: my-key, prod, etc.)
node_id query string No Filter by node ID
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
public_key query string No Filter by public key content (useful for searching email comments: *@example.com)
ssh_username_id query string No Filter by SSH username ID
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
username query string No Filter by SSH username (exact match or wildcard: deploy, admin, etc.)

Response 200 OK

application/json

{
    "data": [
        {
            "id": "01234567-89ab-cdef-0123-456789abcdef",
            "inserted_at": "2025-06-23T10:30:00Z",
            "key_name": "laptop-key",
            "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
            "ssh_username_id": "fedcba98-7654-3210-fedc-ba9876543210",
            "updated_at": "2025-06-23T10:30:00Z"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of SSH public keys with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/SshPublicKey"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SshPublicKeyPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/ssh_public_keys/{id}

Get SSH public key

Description Get a specific SSH public key by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No SSH public key ID

Response 200 OK

application/json

{
    "data": {
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-23T10:30:00Z",
        "key_name": "laptop-key",
        "public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQw7Di3fBr2oc2vbZN5YLz8YpJ8PQb5bXwQwe+QgYX8 user@laptop",
        "ssh_username_id": "fedcba98-7654-3210-fedc-ba9876543210",
        "updated_at": "2025-06-23T10:30:00Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single SSH public key response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/SshPublicKey"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SshPublicKeySingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/ssh_public_keys/{id}

Delete SSH public key

Description Delete an SSH public key

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No SSH public key ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

SelfUpdates.Request

POST /api/v1/self_update_requests

Create a new self-update request

Description Create a new self-update request to trigger agent updates.

The request will be processed asynchronously. Only healthy nodes with self_update_enabled=true will be updated.

Targeting types: - 'all': Target all nodes (with optional filters) - 'nodes': Target specific nodes by IDs (with optional filters) - 'clusters': Target specific clusters by names (with optional filters)

Node and cluster filters can be applied to further refine targeting.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Request body

application/json

{
    "targeting": {
        "node_filters": {
            "version": "0.1.*"
        },
        "type": "all"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Create a new self-update request.\n\nUses the same targeting system as commands. Only healthy nodes with self_update_enabled=true will be updated.\n",
    "example": {
        "targeting": {
            "node_filters": {
                "version": "0.1.*"
            },
            "type": "all"
        }
    },
    "properties": {
        "targeting": {
            "description": "Targeting specification",
            "properties": {
                "cluster_filters": {
                    "additionalProperties": false,
                    "description": "Optional filters to apply to target clusters (AND logic with node_filters). Supports all cluster list filters.",
                    "properties": {
                        "has_node_limit": {
                            "description": "Filter clusters that have (true) or do not have (false) a node limit set",
                            "type": "boolean"
                        },
                        "inserted_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters inserted after or on this date"
                        },
                        "inserted_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters inserted before or on this date"
                        },
                        "ipv4_range": {
                            "description": "Filter by IPv4 range (CIDR notation)",
                            "type": "string"
                        },
                        "name": {
                            "description": "Filter by cluster name (exact match or wildcard: prod*, *staging, etc.)",
                            "type": "string"
                        },
                        "node_count": {
                            "description": "Filter by exact node count",
                            "type": "integer"
                        },
                        "node_count__gte": {
                            "description": "Filter by node count greater than or equal to",
                            "type": "integer"
                        },
                        "node_count__lte": {
                            "description": "Filter by node count less than or equal to",
                            "type": "integer"
                        },
                        "updated_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters updated after or on this datetime"
                        },
                        "updated_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter clusters updated before or on this datetime"
                        }
                    },
                    "type": "object"
                },
                "cluster_names": {
                    "description": "Cluster names (required if type is 'clusters')",
                    "items": {
                        "type": "string"
                    },
                    "type": "array"
                },
                "node_filters": {
                    "additionalProperties": false,
                    "description": "Optional filters to apply to target nodes (AND logic with cluster_filters). Supports all node list filters except cluster_name.",
                    "properties": {
                        "cluster_name": {
                            "description": "Filter by cluster name (exact match or wildcard: prod*, *staging, etc.)",
                            "type": "string"
                        },
                        "id_type": {
                            "description": "Filter by node ID type",
                            "enum": [
                                "persistent",
                                "random"
                            ],
                            "type": "string"
                        },
                        "inserted_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes inserted after or on this date"
                        },
                        "inserted_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes inserted before or on this date"
                        },
                        "last_seen_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes last seen after or on this datetime"
                        },
                        "last_seen_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes last seen before or on this datetime"
                        },
                        "self_update_enabled": {
                            "description": "Filter by self-update enabled status",
                            "type": "boolean"
                        },
                        "status": {
                            "description": "Filter by node status",
                            "enum": [
                                "healthy",
                                "unhealthy",
                                "unreachable"
                            ],
                            "type": "string"
                        },
                        "updated_at__gte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes updated after or on this datetime"
                        },
                        "updated_at__lte": {
                            "anyOf": [
                                {
                                    "format": "date-time",
                                    "type": "string"
                                },
                                {
                                    "format": "date",
                                    "type": "string"
                                }
                            ],
                            "description": "Filter nodes updated before or on this datetime"
                        },
                        "version": {
                            "description": "Filter by node version (exact match or wildcard: 1.0.0, 1.*, etc.)",
                            "type": "string"
                        }
                    },
                    "type": "object"
                },
                "node_ids": {
                    "description": "Node IDs (required if type is 'nodes')",
                    "items": {
                        "format": "uuid",
                        "type": "string"
                    },
                    "type": "array"
                },
                "type": {
                    "description": "Targeting type",
                    "enum": [
                        "all",
                        "nodes",
                        "clusters"
                    ],
                    "type": "string"
                }
            },
            "required": [
                "type"
            ],
            "type": "object"
        }
    },
    "required": [
        "targeting"
    ],
    "title": "SelfUpdateRequestCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-17T10:30:00Z",
        "status": "completed",
        "summary": {
            "failed": 2,
            "total": 10,
            "triggered": 8
        },
        "targeting": {
            "node_filters": {
                "self_update_enabled": true,
                "status": "healthy"
            },
            "type": "all"
        },
        "updated_at": "2025-06-17T10:35:00Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single self-update request response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/SelfUpdateRequestResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SelfUpdateRequestSingleResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

GET /api/v1/self_update_requests

List all self-update requests

Description Returns a paginated list of all self-update requests with filtering and sorting

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
status query string No Filter by status
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)

Response 200 OK

application/json

{
    "data": [
        {
            "id": "01234567-89ab-cdef-0123-456789abcdef",
            "inserted_at": "2025-06-17T10:30:00Z",
            "status": "completed",
            "summary": {
                "failed": 2,
                "total": 10,
                "triggered": 8
            },
            "targeting": {
                "node_filters": {
                    "self_update_enabled": true,
                    "status": "healthy"
                },
                "type": "all"
            },
            "updated_at": "2025-06-17T10:35:00Z"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of self-update requests",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/SelfUpdateRequestResponse"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SelfUpdateRequestPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/self_update_requests/{id}

Get a specific self-update request

Description Returns details for a specific self-update request by ID

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Self-update request ID

Response 200 OK

application/json

{
    "data": {
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2025-06-17T10:30:00Z",
        "status": "completed",
        "summary": {
            "failed": 2,
            "total": 10,
            "triggered": 8
        },
        "targeting": {
            "node_filters": {
                "self_update_enabled": true,
                "status": "healthy"
            },
            "type": "all"
        },
        "updated_at": "2025-06-17T10:35:00Z"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single self-update request response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/SelfUpdateRequestResponse"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "SelfUpdateRequestSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/self_update_requests/{id}

Delete a self-update request

Description Delete a self-update request.

Only completed requests can be deleted. Attempting to delete a pending or processing request will return 409.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Self-update request ID

Response 204 No Content


Schema of the response body


Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Response 409 Conflict

application/json

{
    "error": {
        "code": "conflict",
        "message": "Resource already exists"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "409 Conflict",
    "example": {
        "error": {
            "code": "conflict",
            "message": "Resource already exists"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "conflict",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource already exists",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ConflictResponse",
    "type": "object"
}

Events.Type

GET /api/v1/event_types

List event types

Description Returns the full catalog of event types Edge Core can publish. Use this list to build a webhook's subscribed_events array — every value here is valid, anything else is rejected at create time. Static, code-owned list. See AsyncAPI spec for each event's payload shape.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Response 200 OK

application/json

{
    "data": [
        "edge.enrollment_key.verified",
        "edge.node.registered",
        "edge.node.reregistered",
        "edge.node.version_changed",
        "edge.node.status_changed",
        "edge.node.cluster_changed",
        "edge.node.update_triggered",
        "edge.command_execution.created",
        "edge.command_execution.sent",
        "edge.command_execution.completed",
        "edge.command_execution.cancelled",
        "edge.command_execution.expired",
        "edge.command_execution.pruned",
        "edge.ssh_username.verified",
        "edge.self_update_request.completed"
    ],
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Full catalog of event types Edge Core can publish.",
    "properties": {
        "data": {
            "description": "Full catalog of event types Edge Core can publish, in catalog order.\n\nUse this list to build a webhook's `subscribed_events` array — every\nentry here is a valid value, anything else is rejected at create time.\nThe list is static (code-owned). See [AsyncAPI spec](/asyncdoc) for\neach event's payload shape.\n",
            "example": [
                "edge.enrollment_key.verified",
                "edge.node.registered",
                "edge.node.reregistered",
                "edge.node.version_changed",
                "edge.node.status_changed",
                "edge.node.cluster_changed",
                "edge.node.update_triggered",
                "edge.command_execution.created",
                "edge.command_execution.sent",
                "edge.command_execution.completed",
                "edge.command_execution.cancelled",
                "edge.command_execution.expired",
                "edge.command_execution.pruned",
                "edge.ssh_username.verified",
                "edge.self_update_request.completed"
            ],
            "items": {
                "type": "string"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "EventTypeListResponse",
    "type": "object"
}

Events.Webhook

POST /api/v1/webhooks

Create webhook

Description Create a webhook subscription. The destination URL is validated against the SSRF deny list at create time. secret (HMAC signing key, >= 32 bytes) and headers are write-only — encrypted at rest and never returned in any GET response. subscribed_events is an explicit list of event types this webhook fires on; the full catalog is documented in the AsyncAPI spec.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)

Request body

application/json

{
    "headers": {
        "Authorization": "Bearer xoxb-token"
    },
    "secret": "a-cryptographically-random-32-byte-secret",
    "subscribed_events": [
        "edge.node.registered",
        "edge.command_execution.completed"
    ],
    "url": "https://example.com/edge-events"
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body

{
    "description": "Create a new webhook subscription. Webhooks are immutable after create —\nto change any field, delete and recreate.\n\n- `url` is SSRF-checked downstream. Loopback, RFC1918, link-local, and\n  cloud-metadata IPs/hostnames are denied unless\n  `WEBHOOK_ALLOW_PRIVATE_IPS=true` is set on the admin process.\n- `secret` is the HMAC-SHA256 signing key. Stays on the server; receivers\n  verify the `X-Edge-Signature` header against their stored copy.\n- `headers` is an arbitrary string→string map stamped on every request\n  (e.g. `Authorization: Bearer ...`). Up to 20 entries.\n- `subscribed_events` is an explicit list of event-type strings — no\n  wildcards. Each string must be a known event type from the catalog;\n  unknown values are rejected at create time.\n\nDelivery retry budget is `WEBHOOK_MAX_ATTEMPTS` (default 3).\n\nThe full event catalog with payload schemas is documented in the\n[AsyncAPI spec](/asyncdoc).\n",
    "example": {
        "headers": {
            "Authorization": "Bearer xoxb-token"
        },
        "secret": "a-cryptographically-random-32-byte-secret",
        "subscribed_events": [
            "edge.node.registered",
            "edge.command_execution.completed"
        ],
        "url": "https://example.com/edge-events"
    },
    "properties": {
        "headers": {
            "additionalProperties": {
                "maxLength": 4096,
                "type": "string"
            },
            "description": "Extra HTTP headers. Up to 20 entries; each value up to 4096 characters.",
            "example": {
                "Authorization": "Bearer xoxb-token",
                "X-Custom": "value"
            },
            "maxProperties": 20,
            "type": "object"
        },
        "secret": {
            "description": "HMAC-SHA256 signing key (≥ 32 bytes). Never returned in responses.",
            "example": "a-cryptographically-random-32-byte-secret",
            "maxLength": 256,
            "minLength": 32,
            "type": "string"
        },
        "subscribed_events": {
            "description": "Explicit list of event types this webhook subscribes to. Each entry must be a known event type from the catalog. See [AsyncAPI spec](/asyncdoc).",
            "example": [
                "edge.node.registered",
                "edge.command_execution.completed"
            ],
            "items": {
                "maxLength": 256,
                "type": "string"
            },
            "maxItems": 20,
            "minItems": 1,
            "type": "array"
        },
        "url": {
            "description": "Absolute http(s) URL. SSRF-checked downstream.",
            "example": "https://example.com/edge-events",
            "maxLength": 2048,
            "minLength": 1,
            "pattern": "^https?://.+",
            "type": "string"
        }
    },
    "required": [
        "url",
        "secret",
        "subscribed_events"
    ],
    "title": "WebhookCreateRequest",
    "type": "object"
}

Response 201 Created

application/json

{
    "data": {
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2026-05-05T10:00:00Z",
        "subscribed_events": [
            "edge.node.registered",
            "edge.command_execution.completed"
        ],
        "updated_at": "2026-05-05T10:00:00Z",
        "url": "https://example.com/edge-events"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single webhook response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/Webhook"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "WebhookSingleResponse",
    "type": "object"
}

Response 422 Unprocessable Entity

application/json

{
    "error": {
        "code": "validation_failed",
        "details": {
            "name": [
                "can't be blank"
            ],
            "timeout": [
                "must be greater than 0"
            ]
        },
        "message": "Validation failed"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "422 Validation Failed",
    "example": {
        "error": {
            "code": "validation_failed",
            "details": {
                "name": [
                    "can't be blank"
                ],
                "timeout": [
                    "must be greater than 0"
                ]
            },
            "message": "Validation failed"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "validation_failed",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Validation failed",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "ChangesetErrorResponse",
    "type": "object"
}

GET /api/v1/webhooks

List webhooks

Description Returns a paginated list of webhook subscriptions. The full catalog of event types you can subscribe to is documented in the AsyncAPI spec.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
event_type query string No Returns webhooks whose subscribed_events list contains this event type. Pass a literal event type, e.g. edge.node.registered. See AsyncAPI spec for the catalog.
inserted_at__gte query No Filter records where inserted_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
inserted_at__lte query No Filter records where inserted_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
order_by query string No Comma-separated list of fields to sort by
order_directions query string No Comma-separated list of sort directions (asc/desc) corresponding to order_by fields
page query integer 1 No Page number (1-indexed)
page_size query integer 20 No Items per page
updated_at__gte query No Filter records where updated_at is on or after this datetime (ISO 8601 datetime; date-only is treated as start of day UTC)
updated_at__lte query No Filter records where updated_at is on or before this datetime (ISO 8601 datetime; date-only is treated as end of day UTC)
url query string No Filter by URL (exact match or wildcard: prefix, suffix, substring)

Response 200 OK

application/json

{
    "data": [
        {
            "id": "01234567-89ab-cdef-0123-456789abcdef",
            "inserted_at": "2026-05-05T10:00:00Z",
            "subscribed_events": [
                "edge.node.registered",
                "edge.command_execution.completed"
            ],
            "updated_at": "2026-05-05T10:00:00Z",
            "url": "https://example.com/edge-events"
        }
    ],
    "meta": {
        "pagination": {
            "has_next": true,
            "has_prev": false,
            "next_page": 2,
            "page": 1,
            "page_size": 20,
            "prev_page": 0,
            "total_count": 150,
            "total_pages": 8
        },
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Paginated list of webhooks with filtering and sorting metadata",
    "properties": {
        "data": {
            "items": {
                "$ref": "#/components/schemas/Webhook"
            },
            "type": "array"
        },
        "meta": {
            "$ref": "#/components/schemas/PaginatedMeta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "WebhookPaginatedResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

GET /api/v1/webhooks/{id}

Get webhook

Description Get a single webhook by ID.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Webhook ID

Response 200 OK

application/json

{
    "data": {
        "id": "01234567-89ab-cdef-0123-456789abcdef",
        "inserted_at": "2026-05-05T10:00:00Z",
        "subscribed_events": [
            "edge.node.registered",
            "edge.command_execution.completed"
        ],
        "updated_at": "2026-05-05T10:00:00Z",
        "url": "https://example.com/edge-events"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "Single webhook response",
    "properties": {
        "data": {
            "$ref": "#/components/schemas/Webhook"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "data",
        "meta"
    ],
    "title": "WebhookSingleResponse",
    "type": "object"
}

Response 400 Bad Request

application/json

{
    "error": {
        "code": "bad_request",
        "details": {
            "ipv4_range": [
                "Invalid format."
            ],
            "name": [
                "Invalid format. Expected ~r/^[a-z0-9]/"
            ]
        },
        "message": "Invalid request parameters"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "400 Bad Request",
    "example": {
        "error": {
            "code": "bad_request",
            "details": {
                "ipv4_range": [
                    "Invalid format."
                ],
                "name": [
                    "Invalid format. Expected ~r/^[a-z0-9]/"
                ]
            },
            "message": "Invalid request parameters"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "bad_request",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Invalid request parameters",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "BadRequestResponse",
    "type": "object"
}

Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

DELETE /api/v1/webhooks/{id}

Delete webhook

Description Permanently delete a webhook. Webhooks are immutable after create — to change any field (URL, secret, headers, subscribed_events) delete and recreate. The retry budget is process-wide (WEBHOOK_MAX_ATTEMPTS env var on the admin), not per-webhook.

Input parameters

Parameter In Type Default Nullable Description
apiKey header string N/A No API key for REST API access (API_KEY or MASTER_KEY)
id path string No Webhook ID

Response 204 No Content


Schema of the response body


Response 404 Not Found

application/json

{
    "error": {
        "code": "not_found",
        "message": "Resource not found"
    },
    "meta": {
        "request_id": "550e8400-e29b-41d4-a716-446655440000",
        "timestamp": "2026-04-15T10:00:00.000Z"
    }
}
This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body

{
    "description": "404 Not Found",
    "example": {
        "error": {
            "code": "not_found",
            "message": "Resource not found"
        },
        "meta": {
            "request_id": "550e8400-e29b-41d4-a716-446655440000",
            "timestamp": "2026-04-15T10:00:00.000Z"
        }
    },
    "properties": {
        "error": {
            "properties": {
                "code": {
                    "example": "not_found",
                    "type": "string"
                },
                "details": {
                    "nullable": true
                },
                "message": {
                    "example": "Resource not found",
                    "type": "string"
                }
            },
            "required": [
                "code",
                "message"
            ],
            "type": "object"
        },
        "meta": {
            "$ref": "#/components/schemas/Meta"
        }
    },
    "required": [
        "error",
        "meta"
    ],
    "title": "NotFoundResponse",
    "type": "object"
}

Schemas

Admin

Name Type Description
admin_cluster_name string Name of the admin cluster this admin belongs to
admin_peer_count integer Number of other admins this admin meshes with (= total_admins - 1). Derived from current topology.
edge_node_capacity integer Maximum edge nodes this admin can own. Derived: max_wireguard_peers - admin_peer_count. The cluster-sharding algorithm consumes this value.
erlang_node_name string Erlang distribution node name
id string Admin ID (e.g., k7m3n2p9x4j6)
last_computed_at string(date-time) | null Last time metadata was computed
max_wireguard_peers integer Operator-configured WireGuard peer budget for this admin. Counts both admin-mesh peers and edge-node peers.
name string Admin name (e.g., admin-k7m3n2p9x4j6)
netmaker_host_id string Netmaker host ID for this admin (UUID format)
vpn_hostname string DNS hostname for this admin

AdminCluster

Name Type Description
admin_count integer Number of admins in this cluster
admins Array<AdminClusterMember> Admins present in this cluster, sorted by name
ipv4_range string IPv4 CIDR for the admin cluster network
name string Admin cluster network name (e.g., admin-cluster-main)

AdminClusterMember

Name Type Description
ipv4_address string | null IPv4 address assigned within the admin cluster CIDR (without prefix length)
last_checked_in string(date-time) | null Last time this admin's netclient reported in to Netmaker (ISO 8601)
name string Admin name (e.g., admin-k7m3n2p9x4j6)
netmaker_host_id string Netmaker host ID (UUID)
status string | null Netmaker-derived status: online (recent checkin), offline (stale checkin), disconnected (admin disabled)
use_static_port boolean True when the admin pins WireGuard to a fixed port across restarts
vpn_hostname string DNS hostname inside the admin cluster network
wireguard_ip_address string | null IP address WireGuard peers send tunnel packets to (public or LAN-reachable)
wireguard_port integer | null WireGuard listen port

AdminClusters

Type: Array<AdminCluster>

AdminClustersResponse

Name Type Description
data AdminClusters
meta Meta

AdminMetricsResponse

Name Type Description
data Properties: application, commands, discovery, event_broker, gateways, membership, metadata, nodes, oban_queues, proxy, quantum, reconciliation, self_updates, ssh, timestamp, vpn, webhook

AdminResponse

Name Type Description
data Admin
meta Meta

AdminTopologyEntry

Name Type Description
admin_peer_count integer Admin-mesh peers for this admin (= total_admins - 1)
edge_node_capacity integer Edge nodes this admin can own (= max_wireguard_peers - admin_peer_count)
erlang_node_name string Erlang distribution node name
max_wireguard_peers integer Operator-configured WireGuard peer budget for this admin
name string Admin name (e.g., admin-k7m3n2p9x4j6)
netmaker_host_id string Netmaker host ID for this admin (UUID format)
vpn_hostname string Netmaker dns hostname

AgentCommandExecutionPaginatedResponse

Name Type Description
data Array<Internal.AgentCommandExecutionResponse>
meta PaginatedMeta

AgentMetricsResponse

Name Type Description
data Properties: application, cluster_name, commands, discovery, health_check, node_id, oban_queues, proxy, ssh, timestamp, vpn

AliasPaginatedResponse

Name Type Description
data Array<AliasResponse>
meta PaginatedMeta

AliasResponse

Name Type Description
cluster_name string Name of the cluster
id string(uuid) Unique alias identifier
inserted_at string(date-time) Timestamp when the alias was created
name string Alias name (used in DNS)
node_id string(uuid) ID of the node this alias belongs to
updated_at string(date-time) Timestamp when the alias was last updated
vpn_hostname string Full DNS hostname (FQDN)

AliasSingleResponse

Name Type Description
data AliasResponse
meta Meta

BadRequestResponse

Name Type Description
error Properties: code, details, message
meta Meta

CancelExecutionData

Name Type Description
result string Cancellation request status message

CancelExecutionResponse

Name Type Description
data CancelExecutionData
meta Meta

ChangeClusterRequest

Name Type Description
cluster_name string Name of the target cluster to move this node to.

ChangesetErrorResponse

Name Type Description
error Properties: code, details, message
meta Meta

ClusterCreateRequest

Name Type Description
ipv4_range string | null IPv4 CIDR range (auto-generated if not provided)
name string Cluster name — primary identifier (max 24 chars, lowercase alphanumeric + hyphens)
node_limit integer | null Maximum nodes allowed in this cluster (null means no limit enforced)

ClusterPaginatedResponse

Name Type Description
data Array<ClusterResponse>
meta PaginatedMeta

ClusterResponse

Name Type Description
id string(uuid) Unique cluster identifier (UUID for database compatibility, use name for API operations)
inserted_at string(date-time) When the cluster was created
ipv4_range string IPv4 CIDR range for this cluster
name string Cluster name - primary identifier used in API operations (max 24 chars, alphanumeric with hyphens)
network_name string Netmaker network name
node_count integer Number of nodes in this cluster
node_limit integer | null Maximum number of nodes allowed in this cluster (null means no limit enforced)
nodes Array<NodeSummary> Summary of nodes in this cluster
updated_at string(date-time) When the cluster was last updated
vpn_domain string DNS domain suffix for nodes in this cluster

ClusterSingleResponse

Name Type Description
data ClusterResponse
meta Meta

ClusterUpdateRequest

Name Type Description
node_limit integer | null Maximum nodes allowed in this cluster (null means no limit enforced)

CommandCreateRequest

Name Type Description
command_text string Multi-line shell script/commands to execute
expired_at string(date-time) | null Deadline after which pending/sent executions are automatically expired. Must be in the future. Immutable after creation.
targeting Example: {'cluster_filters': {'name': '*prod*'}, 'cluster_names': ['prod', 'staging'], 'node_filters': {'id_type': 'persistent', 'status': 'healthy'}, 'type': 'clusters'}
timeout integer | null Command timeout in milliseconds (optional, null or omitted means no timeout, must be > 0)

CommandExecutionPaginatedResponse

Name Type Description
data Array<CommandExecutionResponse>
meta PaginatedMeta

CommandExecutionResponse

Name Type Description
cancelled_at string(date-time) | null When the command execution was cancelled
cluster_name string | null The cluster explicitly targeted when this execution was created. Only set when the command used clusters targeting against a single cluster — null for all, nodes, or multi-cluster targeting.
command_id string(uuid) ID of the command being executed
command_text string | null The command text being executed (denormalized for convenience)
completed_at string(date-time) | null When the command execution was completed
exit_code integer | null Final exit code (0 = success, non-zero = failure)
expired_at string(date-time) | null The expiration deadline from the parent command (null if no expiration was set)
id string(uuid) Unique command execution identifier
inserted_at string(date-time) When the execution was created
node_id string(uuid) ID of the target node
output string | null Combined output from command execution
sent_at string(date-time) | null When the command was sent to the agent
status string Current execution status
target_all boolean Whether this execution was created from a system-wide command
timeout integer | null Command timeout in milliseconds (null means no timeout)
updated_at string(date-time) When the execution was last updated

CommandExecutionSingleResponse

Name Type Description
data CommandExecutionResponse
meta Meta

CommandPaginatedResponse

Name Type Description
data Array<CommandResponse>
meta PaginatedMeta

CommandResponse

Name Type Description
command_text string Multi-line shell script/commands
expired_at string(date-time) | null Deadline after which pending/sent executions are automatically expired (immutable after creation)
id string(uuid) Unique command identifier
inserted_at string(date-time) When the command was created
targeting Example: {'node_filters': {'status': 'healthy'}, 'node_ids': ['01234567-89ab-cdef-0123-456789abcdef'], 'type': 'nodes'} Targeting configuration used when creating this command (informational only, not filterable)
timeout integer | null Command timeout in milliseconds (optional, null means no timeout)
updated_at string(date-time) When the command was last updated

CommandSingleResponse

Name Type Description
data CommandResponse
meta Meta

ConflictResponse

Name Type Description
error Properties: code, details, message
meta Meta

CreateAliasRequest

Name Type Description
name string Alias name (lowercase alphanumeric with hyphens)

EdgeClusters

EdgeClustersResponse

Name Type Description
data EdgeClusters
meta Meta

EnrollmentKeyCreateRequest

Name Type Description
expired_at string(date-time) | null Expiry datetime (ISO 8601). Omit or pass null for no expiry.
name string | null Optional human-readable label for this key. Display only — not used for lookup.
uses_remaining integer | null Number of uses (must be >= 1). Pass null for unlimited. Omit to use the default of 1.

EnrollmentKeyPaginatedResponse

Name Type Description
data Array<EnrollmentKeyResponse>
meta PaginatedMeta

EnrollmentKeyResponse

Name Type Description
cluster_name string Cluster this key belongs to
expired_at string(date-time) | null Expiry datetime (ISO 8601). null means never expires.
id string(uuid) Enrollment key ID
inserted_at string(date-time) When the enrollment key was created
key string Enrollment key blob (base64 JSON). Set as ENROLLMENT_KEY on the agent.
last_used_at string(date-time) | null When the key was last used. null if unused.
name string | null Optional human-readable label for this key (display only). null if unset.
updated_at string(date-time) When the enrollment key was last updated
uses_remaining integer | null Remaining uses. null means unlimited.

EnrollmentKeySingleResponse

Name Type Description
data EnrollmentKeyResponse
meta Meta

EnrollmentKeyUpdateRequest

Name Type Description
expired_at string(date-time) | null Expiry datetime (ISO 8601), or null to remove expiry. Omit to leave unchanged.
name string | null Human-readable label for this key, or null to clear. Omit to leave unchanged.
uses_remaining integer | null Positive integer to set a use limit, or null to make the key unlimited. Omit to leave unchanged.

EventTypeListResponse

Name Type Description
data Array<string> Full catalog of event types Edge Core can publish, in catalog order.

Use this list to build a webhook's subscribed_events array — every entry here is a valid value, anything else is rejected at create time. The list is static (code-owned). See AsyncAPI spec for each event's payload shape. | | meta | Meta | |

ForbiddenResponse

Name Type Description
error Properties: code, details, message
meta Meta

HostMetricsResponse

Name Type Description
cluster_name string Name of the cluster this node belongs to
cpu Properties: cores, load_15m, load_1m, load_5m CPU metrics
disk Properties: available_bytes, available_gb, total_bytes, total_gb, usage_percent, used_bytes, used_gb Disk metrics for root filesystem (/)
memory Properties: available_bytes, available_gb, total_bytes, total_gb, usage_percent, used_bytes, used_gb Memory metrics
node_id string(uuid) Node unique identifier
timestamp string(date-time) When the metrics were collected (ISO 8601 format)
uptime Properties: human, seconds System uptime information

Meta

Name Type Description
request_id string Unique request identifier (mirrors x-request-id response header)
timestamp string(date-time) ISO 8601 UTC timestamp of when the response was generated

MyAdminCluster

Name Type Description
degraded boolean True when total_nodes exceeds total_edge_capacity
name string Admin cluster name
topology Array<AdminTopologyEntry> List of all admins in the cluster
total_admins integer Total number of admins in the cluster
total_edge_capacity integer Sum of edge_node_capacity across all admins in this admin cluster. This is the system's total edge-node sharding budget.
total_nodes integer Total nodes registered in the system across all clusters
weak_leader string Name of the current weak leader admin (alphabetically first admin ID in the cluster). Best-effort duplicate work reduction — not a strong guarantee. Always populated — defaults to self on bootstrap, updated on first metadata recomputation.

MyAdminClusterResponse

Name Type Description
data MyAdminCluster
meta Meta

NodePaginatedResponse

Name Type Description
data Array<NodeResponse>
meta PaginatedMeta

NodeResponse

Name Type Description
api_token string API token for agent authentication
cluster_name string Name of the cluster this node belongs to
host_metrics_port integer Host metrics port (Node Exporter)
http_port integer HTTP API port
http_proxy_port integer HTTP proxy port
id string(uuid) Unique node identifier
id_type string Type of node identifier (persistent or random)
inserted_at string(date-time) When the node was created
last_seen_at string(date-time) | null Last heartbeat timestamp from the node
mdns_hostname string mDNS hostname — resolvable on the local LAN via multicast DNS
netmaker_host_id string(uuid) | null Netmaker Host UUID for API operations
node_name string Human-readable node name (derived from ID)
proxy_password string Password for proxy authentication (username is always '_')
self_update_enabled boolean Whether self-updates are enabled
socks5_proxy_port integer SOCKS5 proxy port
ssh_port integer SSH port
status string Current node status
updated_at string(date-time) When the node was last updated
version string | null Agent version
vpn_hostname string DNS hostname for this node
wireguard_metrics_port integer WireGuard metrics port (WireGuard Exporter)

NodeSingleResponse

Name Type Description
data NodeResponse
meta Meta

NodeSummary

Name Type Description
id string Node ID
id_type string Node ID type
status string Node status
vpn_hostname string DNS hostname for this node

NotFoundResponse

Name Type Description
error Properties: code, details, message
meta Meta

OrphanedClusters

OrphanedClustersResponse

Name Type Description
data OrphanedClusters
meta Meta

PaginatedMeta

Name Type Description
pagination Pagination
request_id string Unique request identifier
timestamp string(date-time) ISO 8601 UTC response timestamp

Pagination

Name Type Description
has_next boolean Whether a next page exists
has_prev boolean Whether a previous page exists
next_page integer | null Next page number, null when on the last page
page integer Current page number
page_size integer Items per page
prev_page integer | null Previous page number, null when on the first page
total_count integer Total number of items
total_pages integer Total number of pages

SelfUpdateRequestCreateRequest

Name Type Description
targeting Properties: cluster_filters, cluster_names, node_filters, node_ids, type Targeting specification

SelfUpdateRequestPaginatedResponse

Name Type Description
data Array<SelfUpdateRequestResponse>
meta PaginatedMeta

SelfUpdateRequestResponse

Name Type Description
id string(uuid) Unique request identifier
inserted_at string(date-time) When the request was created
status string Request processing status
summary Example: {'failed': 2, 'total': 10, 'triggered': 8} Summary of results (available after completion)
targeting Example: {'node_filters': {'self_update_enabled': True, 'status': 'healthy'}, 'type': 'all'} Targeting configuration (same format as commands)
updated_at string(date-time) When the request was last updated

SelfUpdateRequestSingleResponse

Name Type Description
data SelfUpdateRequestResponse
meta Meta

ServiceUnavailableResponse

Name Type Description
error Properties: code, details, message
meta Meta

SshPublicKey

Name Type Description
id string(uuid) Unique SSH public key identifier
inserted_at string(date-time) When the SSH public key was created
key_name string Human-readable name for the SSH key
public_key string SSH public key in OpenSSH format (algorithm base64data [comment])
ssh_username_id string(uuid) SSH username this key belongs to
updated_at string(date-time) When the SSH public key was last updated

SshPublicKeyCreateRequest

Name Type Description
key_name string Human-readable name for the SSH key
public_key string SSH public key in OpenSSH format (algorithm base64data [comment]). Supported algorithms: ssh-ed25519 (recommended), ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521, ssh-rsa

SshPublicKeyPaginatedResponse

Name Type Description
data Array<SshPublicKey>
meta PaginatedMeta

SshPublicKeySingleResponse

Name Type Description
data SshPublicKey
meta Meta

SshUsername

Name Type Description
has_password boolean Whether this username has a password configured for authentication
id string(uuid) Unique SSH username identifier
inserted_at string(date-time) When the SSH username was created
node_id string(uuid) Node this username belongs to
public_keys Array<SshPublicKey> SSH public keys associated with this username (only included when preloaded)
updated_at string(date-time) When the SSH username was last updated
username string SSH username for node access (3-32 characters)

SshUsernameCreateRequest

Name Type Description
password string | null Optional password for username/password SSH authentication (12-128 characters if provided, will be hashed with Argon2)
public_keys Array<Properties: key_name, public_key> Optional array of SSH public keys to create with this username
username string SSH username for node access (3-32 characters, must start with letter or underscore, lowercase letters/digits/hyphens/underscores only)

SshUsernamePaginatedResponse

Name Type Description
data Array<SshUsername>
meta PaginatedMeta

SshUsernameSingleResponse

Name Type Description
data SshUsername
meta Meta

UnifiedMetricsResponse

Name Type Description
data Properties: agent, cluster_name, host, node_id, timestamp
meta Meta

Webhook

Name Type Description
id string(uuid) Unique webhook identifier
inserted_at string(date-time) When the webhook was created
subscribed_events Array<string> Explicit list of event types this webhook fires on. Each entry is a literal event type from the catalog (no wildcards). See AsyncAPI spec for the full catalog.
updated_at string(date-time) When the webhook was last updated
url string Destination URL — receives a POST per matching event

WebhookCreateRequest

Name Type Description
headers Example: {'Authorization': 'Bearer xoxb-token', 'X-Custom': 'value'} Extra HTTP headers. Up to 20 entries; each value up to 4096 characters.
secret string HMAC-SHA256 signing key (≥ 32 bytes). Never returned in responses.
subscribed_events Array<string> Explicit list of event types this webhook subscribes to. Each entry must be a known event type from the catalog. See AsyncAPI spec.
url string Absolute http(s) URL. SSRF-checked downstream.

WebhookPaginatedResponse

Name Type Description
data Array<Webhook>
meta PaginatedMeta

WebhookSingleResponse

Name Type Description
data Webhook
meta Meta

Security schemes

Name Type Scheme Description
apiKey http bearer API key for REST API access (API_KEY or MASTER_KEY)

Tags

Name Description
Admins.Metadata
Admins.Metrics
Nodes.Cluster
Nodes.EnrollmentKey
Nodes.Node
Nodes.Alias
Nodes.Metrics
Commands.Command
Commands.CommandExecution
Ssh.SshUsername
Ssh.SshPublicKey
SelfUpdates.Request
Events.Type
Events.Webhook