Skip to Content
API Reference

API Reference

The kubenest REST API is the interface used by the web console, CLI tools, and any automation you build on top of kubenest. Every action the UI performs is an API call — there is no privileged back channel. This page covers the conventions that apply across the entire API and indexes all available endpoints.

A full interactive API reference with request/response schemas, live “Try it” execution, and example bodies is available at https://api.{your-domain}/docs (Swagger UI). This page is the conceptual overview and quick-reference; use /docs when you need to inspect a specific field or test a request.


Base URL

All endpoints are prefixed with:

https://api.{your-domain}/api/v1

Replace {your-domain} with the domain you configured during installation. If you are running a local development instance, the default is http://localhost:8000/api/v1.


Authentication

Obtaining tokens

Authenticate by posting credentials to the login endpoint. Note that the login endpoint uses application/x-www-form-urlencoded (not JSON) to comply with the OAuth2 password flow convention:

login
curl -X POST https://api.your-domain.com/api/v1/login \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=admin@example.com&password=your-password"

Response:

{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer" }

The login response also sets an HttpOnly refresh token cookie. Do not discard it — you need it to refresh the access token.

Using the access token

Include the access token in the Authorization header on every subsequent request:

Authorization: Bearer {access_token}

Access tokens expire after 30 minutes. When a request returns 401 Unauthorized with detail: "Token expired", refresh the token (see below).

Refreshing the access token

The refresh endpoint reads the HttpOnly cookie set at login and issues a new access token without requiring you to re-enter your password. It also rotates the refresh cookie:

refresh token
curl -X POST https://api.your-domain.com/api/v1/refresh \ -b cookies.txt \ # curl cookie jar that stores the refresh cookie -c cookies.txt

In a browser context, the browser sends the cookie automatically. In a script, manage the cookie jar explicitly with -b/-c.

Refresh tokens expire after 7 days. After a refresh token expires, the user must log in again.

Logging out

logout
curl -X POST https://api.your-domain.com/api/v1/logout \ -H "Authorization: Bearer $TOKEN"

Logout invalidates the refresh token cookie and clears the server-side session. The access token itself cannot be invalidated (it is a signed JWT with no revocation list) — it will expire naturally after 30 minutes.


Request conventions

Content-Type. All endpoints except POST /login expect Content-Type: application/json. The login endpoint expects application/x-www-form-urlencoded.

Namespaced resources. Apps and stack templates are addressed by {namespace}/{name} rather than by UUID. The namespace maps to the project’s Kubernetes namespace, and the name is the App or template name you chose at create time. This makes URLs human-readable and stable.

Pagination. List endpoints return a data array and a pagination object:

{ "data": [...], "pagination": { "total": 142, "page": 1, "page_size": 20, "pages": 8 } }

Pass ?page=2&page_size=50 to paginate. The default page size is 20; the maximum is 100.

Filtering and sorting. Most list endpoints accept query parameters for filtering. Common ones: ?cluster_id=..., ?project_id=..., ?phase=running, ?name=prefix. Sorting: ?sort_by=created_at&sort_order=desc.


Response conventions

Success codes. 200 OK for reads and updates; 201 Created for creates; 202 Accepted for async operations that return before completion (the response body contains the initial state with phase: pending); 204 No Content for deletes.

Async responses. Operations that dispatch events to the operator (app create/patch/delete, addon install/upgrade) return 202 Accepted with the initial resource state. Subscribe to the SSE stream or poll the resource endpoint to track progress.


Error format

4xx client errors return a simple detail string:

{ "detail": "App 'my-app' not found in namespace 'my-project'" }

422 Unprocessable Entity (validation failures) returns a list of structured errors, one per invalid field:

{ "detail": [ { "loc": ["body", "components", 0, "workload_spec", "replicas"], "msg": "ensure this value is greater than 0", "type": "value_error.number.not_gt" } ] }

The loc array is a path through the request body to the invalid field. The first element is always "body" for JSON request bodies or "query" for query parameters.

409 Conflict is returned when a write is attempted on a resource that is in blocked_sync drift state, or when a component removal would break an exportRef dependency.

503 Service Unavailable is returned when the target cluster is disconnected and the operation requires the operator to be reachable. The detail includes the cluster ID and last-seen timestamp.


Rate limits

API rate limits are applied per user. Check current usage:

check rate limits
curl -H "Authorization: Bearer $TOKEN" \ "https://api.your-domain.com/api/v1/rate-limits" | jq .

Response:

{ "limits": { "requests_per_minute": 300, "remaining": 287, "reset_at": "2026-06-11T14:23:00Z" } }

Rate limit headers are also included on every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.


Endpoint index

Auth

MethodPathDescription
POST/loginObtain access token. Body: application/x-www-form-urlencoded with username and password. Sets refresh cookie.
POST/refreshExchange refresh cookie for a new access token. Rotates the refresh cookie.
POST/logoutInvalidate the refresh token cookie.

Clusters

MethodPathDescription
GET/orgs/{org_id}/clustersList all clusters in the organization.
POST/orgs/{org_id}/clustersRegister a new cluster or initiate cloud provisioning.
GET/clusters/{id}Get cluster details, status, and metrics.
PATCH/clusters/{id}Update cluster metadata (name, description).
DELETE/clusters/{id}Delete the cluster record. Fails if active projects exist.
GET/clusters/{id}/metricsCPU, memory, and node count metrics aggregated from the last operator heartbeat.
GET/clusters/{id}/install-commandRetrieve the pre-filled Helm install command for the operator. Mints a fresh 365-day cluster JWT on every call and stores it as the cluster’s current token — this is also how you rotate a token.
GET/clusters/{id}/install-instructionsStep-by-step install walkthrough for the operator, including the Helm command. Reuses the existing token if one is already stored.
POST/clusters/{id}/scaleChange node count (cloud-provisioned clusters only).
GET/clusters/{id}/configGet the cluster’s component configuration (ingress, storage, and related platform components).
PUT/clusters/{id}/configReplace the cluster’s component configuration.
GET/clusters/{id}/provisioning-jobsList provisioning jobs for a cloud-provisioned cluster, with status and timestamps.
POST/clusters/{id}/register-argocdRegister the cluster as an ArgoCD target so the GitOps controller can sync to it.
GET/clusters/{id}/rbacList cluster-scoped role assignments.
POST/clusters/{id}/rbacGrant a cluster-scoped role to a user.
PUT/clusters/{id}/rbacReplace a user’s cluster-scoped role.
DELETE/clusters/{id}/rbacRevoke a cluster-scoped role assignment.
GET/clusters/{id}/registry-secretsList image pull secrets attached at the cluster level.
POST/clusters/{id}/registry-secretsAttach an image pull secret at the cluster level.

Projects

MethodPathDescription
GET/projectsList all projects the user can access.
POST/projectsCreate a project (Kubernetes namespace) on a cluster.
GET/projects/{id}Get project details, status, and resource quota usage.
DELETE/projects/{id}Delete project and all its apps and addons. Requires the project to be empty unless force=true.
GET/projects/{id}/appsList every app in the project.
GET/projects/{id}/available-exportsList export values published by apps and addons in the project, for wiring exportRef entries.
GET/projects/{id}/rbacList project-scoped role assignments.
POST/projects/{id}/rbacGrant a project-scoped role to a user.
PUT/projects/{id}/rbacReplace a user’s project-scoped role.
DELETE/projects/{id}/rbacRevoke a project-scoped role assignment.
GET/projects/{id}/secrets-overviewSummarize the secrets visible to the project and where each one is inherited from.
GET/projects/{id}/registry-secretsList image pull secrets attached at the project level.
POST/projects/{id}/registry-secretsAttach an image pull secret at the project level.
GET/projects/{id}/effective-registry-secretsResolve the image pull secrets that actually apply, merging cluster-level and project-level attachments.

Projects have no update endpoint. Name, cluster, and resource quotas are fixed at creation time — there is no PATCH /projects/{id}. Changing any of them means deleting the project and creating a new one.


Apps

MethodPathDescription
GET/appsList apps. Filter by ?project_id=, ?phase=, ?cluster_id=.
POST/appsCreate an app. Body includes name, project_id, and components array. Returns 202 Accepted.
GET/apps/{namespace}/{name}Get app details, component statuses, drift state, and resolved exports.
PATCH/apps/{namespace}/{name}Add, remove, or patch components. Returns 202 Accepted.
DELETE/apps/{namespace}/{name}Delete app and all its components. Returns 202 Accepted.
POST/apps/{namespace}/{name}/scaleScale a specific workload component’s replica count. Body: {component_name, replicas}.
POST/apps/{namespace}/{name}/pauseSet all workload replicas to 0, snapshot pre-pause counts.
POST/apps/{namespace}/{name}/resumeRestore pre-pause replica counts.
POST/apps/{namespace}/{name}/redeployForce a hard-refresh and re-sync without spec changes.
GET/apps/{namespace}/{name}/deploymentsList deployment history (create, patch, rollback events).
POST/apps/{namespace}/{name}/rollbackRestore a prior deployment spec. Body: {deployment_id} or {revision}. Returns 202 Accepted.
POST/apps/{namespace}/{name}/deployments/{deployment_id}/rollbackRoll back to one specific deployment by ID.
GET/apps/{namespace}/{name}/logsFetch recent logs across the app’s components.
GET/apps/{namespace}/{name}/components/{component}/logs/streamStream logs from a single component.
GET/apps/{namespace}/{name}/metricsCPU and memory usage per component.
POST/apps/{namespace}/{name}/attach-addonAttach an existing addon instance to the app and wire its exports into a component.
DELETE/apps/{namespace}/{name}/attach-addon/{addon_instance_id}Detach an addon instance from the app.
GET/apps/{namespace}/{name}/components/{component}/secretsList a component’s secret keys.
PATCH/apps/{namespace}/{name}/components/{component}/secretsSet or update a component’s secret values.
DELETE/apps/{namespace}/{name}/components/{component}/secrets/{key}Remove a single secret key from a component.

Stack Templates

MethodPathDescription
GET/stack-templatesList templates. Filter by ?scope=, ?cluster_id=, ?project_id=.
POST/stack-templatesCreate a template directly (full template body).
GET/stack-templates/{namespace}/{name}Get template details including parameters and component specs.
PUT/stack-templates/{namespace}/{name}Replace template contents (creates a new version).
DELETE/stack-templates/{namespace}/{name}Delete a template. Fails if active deployed instances reference it.
POST/stack-templates/from-app/{namespace}/{name}Capture a running app as a new template. Body: {name, version, scope, preserve_export_refs}.
POST/stack-templates/from-chartCreate a template wrapping a Helm chart with promoted parameters.
POST/stack-templates/from-yamlImport a template from a StackTemplateExport JSON body.
POST/stack-templates/{namespace}/{name}/deployDeploy a template to a project. Body: {project_id, parameters, app_name, timeout}. Returns 202 Accepted.
GET/stack-templates/inspect-chartFetch schema and defaults for a Helm chart. Query params: ?repo=&name=&version=. Cached 1 hour.
GET/stack-templates/registryBrowse the community template registry.

Addon Instances

MethodPathDescription
GET/addon-instancesList addon instances. Filter by ?project_id=, ?phase=.
POST/addon-instancesDeploy a standalone addon instance. Returns 202 Accepted.
GET/addon-instances/{id}Get instance details, current phase, and resolved exports.
PATCH/addon-instances/{id}Update values or chart version. Creates a new revision. Returns 202 Accepted.
DELETE/addon-instances/{id}Uninstall and delete the addon instance. Query param: ?preserve_pvcs=true.
POST/addon-instances/{id}/rollbackRestore a prior revision. Body: {revision_number} or {revision_id}.
GET/addon-instances/{id}/revisionsList all revisions with values snapshots and notes.

To find what depends on an addon instance, use GET /projects/{id}/available-exports — it lists the exports each addon and app publishes, which is what exportRef entries resolve against.


Addon Definitions

MethodPathDescription
GET/addon-definitionsList all addon definitions in the catalog.
GET/addon-definitions/{name}Get a definition’s chart reference, default values, and export schema.

Organizations and users

Organizations are the top-level tenant boundary. Clusters, projects, and credentials all belong to one.

MethodPathDescription
GET/orgsList organizations the caller belongs to.
POST/orgsCreate an organization.
GET/orgs/{id}Get organization details.
PUT/orgs/{id}Update an organization.
DELETE/orgs/{id}Delete an organization and everything scoped to it.
GET/orgs/{id}/membersList members and their organization roles.
POST/orgs/{id}/membersAdd a user to the organization.
PUT/orgs/{id}/members/{user_id}Change a member’s organization role.
DELETE/orgs/{id}/members/{user_id}Remove a member from the organization.
GET/org/settingsGet settings for the caller’s current organization.
PATCH/org/settingsUpdate settings for the caller’s current organization.
GET/orgs/{id}/credentialsList cloud provider credentials used for cluster provisioning.
POST/orgs/{id}/credentialsStore a new set of cloud provider credentials.
GET/credentials/{id}Get a credential record. Secret material is never returned.
PATCH/credentials/{id}Rotate or rename a credential.
DELETE/credentials/{id}Delete a credential.
GET/user/meGet the authenticated user’s profile and role assignments.
GET/usersList users.
POST/userCreate a user.
GET/user/{id}Get a user.
PATCH/user/{id}Update a user.
DELETE/user/{id}Delete a user.

Provisioning jobs

Cloud cluster provisioning runs asynchronously. Creating a cluster with a cloud provider returns a job you poll or watch over SSE.

MethodPathDescription
GET/provisioning-jobs/{id}Get job status and current phase.
GET/provisioning-jobs/{id}/logsFetch Terraform and bootstrap output for the job.
POST/provisioning-jobs/{id}/retryRetry a failed job without recreating resources that already exist.

Events (SSE)

MethodPathDescription
GET/events/streamServer-Sent Events stream. Filter by ?namespace=&name= for a specific app, ?addon_instance_id= for an addon, or ?cluster_id= for all events on a cluster.

The SSE stream uses standard text/event-stream encoding. Each event has a type field and a JSON data payload. Event types include app.status, addon.status, cluster.status, drift.detected, and build.log.

subscribe to app events
curl -N -H "Authorization: Bearer $TOKEN" \ "https://api.your-domain.com/api/v1/events/stream?namespace=my-project&name=my-app"

The connection is long-lived. Clients should implement reconnection with a backoff if the connection drops. The Last-Event-ID header is supported — pass the last received event ID to resume from where you left off.


See also:

Last updated on