openapi: 3.0.3 info: title: KubeOrch Core API description: REST API for the KubeOrch Kubernetes workflow orchestration platform. version: 0.0.3 x-stability-level: beta license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 contact: name: KubeOrch Community url: https://github.com/KubeOrch externalDocs: description: KubeOrch Beta API conventions and compatibility policy url: https://github.com/KubeOrch/core/blob/main/docs/API_CONVENTIONS.md servers: - url: http://localhost:3000/v1 description: Local development - url: https://api.kubeorch.dev/v1 description: Production tags: - name: Auth description: Authentication and authorization - name: Workspaces description: Workspace tenancy and base membership management - name: Environments description: Workspace-scoped deployment environment identities - name: Applications description: Environment-scoped desired application identities - name: Artifacts description: Immutable workspace build evidence registered by external CI or manual onboarding - name: Releases description: Immutable application revision and artifact bindings that do not deploy - name: Plans description: Immutable proposed changes, approval requests, and terminal decisions - name: Workflows description: Workflow management and execution - name: Clusters description: Kubernetes cluster management - name: Resources description: Deployed resource tracking - name: Builds description: Container image builds - name: Plugins description: Plugin management - name: Dashboard description: Dashboard statistics paths: /api/auth/register: post: tags: [Auth] summary: Register a new user operationId: registerUser x-stability-level: beta x-kubeorch-workspace-boundary: none requestBody: required: true content: application/json: schema: type: object required: [email, password, name] properties: email: type: string format: email password: type: string minLength: 6 name: type: string responses: "201": description: User registered successfully content: application/json: schema: $ref: "#/components/schemas/AuthResponse" "400": $ref: "#/components/responses/BadRequest" "409": description: Email already registered /api/auth/login: post: tags: [Auth] summary: Login with email and password operationId: loginUser x-stability-level: beta x-kubeorch-workspace-boundary: none requestBody: required: true content: application/json: schema: type: object required: [email, password] properties: email: type: string format: email password: type: string responses: "200": description: Login successful content: application/json: schema: $ref: "#/components/schemas/AuthResponse" "401": description: Invalid credentials /api/auth/refresh: post: tags: [Auth] summary: Refresh an expired JWT token operationId: refreshAuthToken x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [auth:refresh] security: - bearerAuth: [] responses: "200": description: Token refreshed content: application/json: schema: $ref: "#/components/schemas/AuthResponse" /api/auth/methods: get: tags: [Auth] summary: Get available authentication methods operationId: listAuthMethods x-stability-level: beta x-kubeorch-workspace-boundary: none responses: "200": description: List of enabled auth methods /api/workspaces: get: tags: [Workspaces] summary: List workspaces for the authenticated identity operationId: listWorkspaces x-stability-level: beta x-kubeorch-workspace-boundary: identity x-kubeorch-required-scopes: [workspaces:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/PageCursor" - $ref: "#/components/parameters/PageSize" responses: "200": description: Workspaces ordered by newest membership first headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/WorkspaceList" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" post: tags: [Workspaces] summary: Create a workspace and bootstrap its first owner description: The workspace and creator membership are persisted atomically. Replaying the same idempotency key and normalized request returns the original result. operationId: createWorkspace x-stability-level: beta x-kubeorch-workspace-boundary: identity x-kubeorch-required-scopes: [workspaces:write] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWorkspaceRequest" responses: "201": description: Workspace created, or the original creation response replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Workspace" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}: parameters: - $ref: "#/components/parameters/WorkspaceId" get: tags: [Workspaces] summary: Get workspace metadata operationId: getWorkspace x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [workspaces:read] security: - bearerAuth: [] responses: "200": description: Workspace metadata and the caller's base role headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Workspace" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" patch: tags: [Workspaces] summary: Update workspace metadata description: Repeating the same field values is inherently idempotent. Only owners and admins can update metadata. operationId: updateWorkspace x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [workspaces:write] x-kubeorch-idempotency: inherent security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateWorkspaceRequest" responses: "200": description: Updated workspace headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Workspace" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "403": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/members: parameters: - $ref: "#/components/parameters/WorkspaceId" get: tags: [Workspaces] summary: List active workspace memberships operationId: listWorkspaceMemberships x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [memberships:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/PageCursor" - $ref: "#/components/parameters/PageSize" responses: "200": description: Memberships ordered newest first headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/MembershipList" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" post: tags: [Workspaces] summary: Add a workspace member description: User identity is the natural idempotency key. Repeating an existing user and role returns the current membership; a different role returns a documented conflict. operationId: addWorkspaceMembership x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [memberships:write] x-kubeorch-idempotency: inherent security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AddMembershipRequest" responses: "200": description: Existing membership returned for an idempotent replay content: application/json: schema: $ref: "#/components/schemas/Membership" "201": description: Membership created content: application/json: schema: $ref: "#/components/schemas/Membership" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "403": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/members/{memberId}: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/MemberId" patch: tags: [Workspaces] summary: Change a workspace member's base role description: Repeating the current role is inherently idempotent. Only an owner can grant or change an owner role. operationId: updateWorkspaceMembership x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [memberships:write] x-kubeorch-idempotency: inherent security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateMembershipRequest" responses: "200": description: Membership updated content: application/json: schema: $ref: "#/components/schemas/Membership" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "403": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" delete: tags: [Workspaces] summary: Remove a workspace membership description: Membership removal is inherently idempotent at the persistence boundary. The final owner cannot be removed. operationId: removeWorkspaceMembership x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [memberships:write] x-kubeorch-idempotency: inherent security: - bearerAuth: [] responses: "204": description: Membership removed "401": $ref: "#/components/responses/APIError" "403": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/environments: parameters: - $ref: "#/components/parameters/WorkspaceId" get: tags: [Environments] summary: List environments in a workspace description: Environments are ordered by creation time and opaque identifier, newest first. operationId: listEnvironments x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [environments:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/PageCursor" - $ref: "#/components/parameters/PageSize" responses: "200": description: Workspace environments headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/EnvironmentList" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" post: tags: [Environments] summary: Create an environment identity description: Names are unique per workspace after trimming outer whitespace, collapsing internal Unicode whitespace, and Unicode lowercase normalization. No cluster connection is required. operationId: createEnvironment x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [environments:write] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateEnvironmentRequest" responses: "201": description: Environment created, or the original creation response replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Environment" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/environments/{environmentId}: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/EnvironmentId" get: tags: [Environments] summary: Get an environment operationId: getEnvironment x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [environments:read] security: - bearerAuth: [] responses: "200": description: Environment identity and metadata headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Environment" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" patch: tags: [Environments] summary: Update environment metadata description: Repeating the same field values is inherently idempotent. Renamed environments remain subject to normalized workspace uniqueness. operationId: updateEnvironment x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [environments:write] x-kubeorch-idempotency: inherent security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateEnvironmentRequest" responses: "200": description: Environment updated headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Environment" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/applications: parameters: - $ref: "#/components/parameters/WorkspaceId" get: tags: [Applications] summary: List applications in a workspace description: Applications are ordered newest first. Archived applications are excluded unless includeArchived is true. Cursors are bound to the selected filters. operationId: listApplications x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [applications:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/PageCursor" - $ref: "#/components/parameters/PageSize" - name: environmentId in: query required: false description: Return only applications belonging to this environment in the route workspace. schema: $ref: "#/components/schemas/ResourceId" - name: includeArchived in: query required: false description: Include non-destructively archived applications. schema: type: boolean default: false responses: "200": description: Workspace applications matching the filters headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/ApplicationList" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" post: tags: [Applications] summary: Create a draft application description: Creates desired application identity and metadata without contacting a cluster. The environment must belong to the route workspace. operationId: createApplication x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [applications:write] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateApplicationRequest" responses: "201": description: Draft application created, or the original creation response replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Application" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/applications/{applicationId}: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ApplicationId" get: tags: [Applications] summary: Get an application description: Archived applications remain directly retrievable by identifier. operationId: getApplication x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [applications:read] security: - bearerAuth: [] responses: "200": description: Application identity and desired metadata headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Application" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" patch: tags: [Applications] summary: Update application desired metadata description: Repeating the same field values is inherently idempotent. This operation stores desired metadata only and does not contact a cluster. operationId: updateApplication x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [applications:write] x-kubeorch-idempotency: inherent security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateApplicationRequest" responses: "200": description: Application updated headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Application" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" delete: tags: [Applications] summary: Archive an application description: Archive is non-destructive and inherently idempotent. Repeated requests return the original archive timestamp. operationId: archiveApplication x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [applications:write] x-kubeorch-idempotency: inherent security: - bearerAuth: [] responses: "200": description: Archived application headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Application" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/artifacts: parameters: - $ref: "#/components/parameters/WorkspaceId" get: tags: [Artifacts] summary: List registered artifacts description: Returns immutable artifact evidence in descending creation order without fetching evidence references. operationId: listArtifacts x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [artifacts:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/PageCursor" - $ref: "#/components/parameters/PageSize" responses: "200": description: Workspace artifacts headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/ArtifactList" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" post: tags: [Artifacts] summary: Register immutable artifact evidence description: Registers a digest-pinned OCI image and metadata. This operation never fetches evidence, builds source, or deploys to a cluster. operationId: createArtifact x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [artifacts:write] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateArtifactRequest" responses: "201": description: Artifact registered, or an existing identical artifact replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Artifact" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/artifacts/{artifactId}: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ArtifactId" get: tags: [Artifacts] summary: Get registered artifact evidence operationId: getArtifact x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [artifacts:read] security: - bearerAuth: [] responses: "200": description: Immutable artifact evidence headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Artifact" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/applications/{applicationId}/releases: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ApplicationId" get: tags: [Releases] summary: List application releases description: Returns immutable releases in descending creation order. Listing does not inspect a cluster. operationId: listReleases x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [releases:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/PageCursor" - $ref: "#/components/parameters/PageSize" responses: "200": description: Releases for the route application headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/ReleaseList" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" post: tags: [Releases] summary: Create an immutable application release description: Binds one application revision to registered workspace artifacts. It records a handoff only and never mutates workflows or clusters. operationId: createRelease x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [releases:write] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateReleaseRequest" responses: "201": description: Release created, or the original creation response replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Release" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/applications/{applicationId}/releases/{releaseId}: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/ApplicationId" - $ref: "#/components/parameters/ReleaseId" get: tags: [Releases] summary: Get an application release operationId: getRelease x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [releases:read] security: - bearerAuth: [] responses: "200": description: Immutable application release headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Release" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/plans: parameters: - $ref: "#/components/parameters/WorkspaceId" get: tags: [Plans] summary: List proposed Plans in a workspace description: Plans are immutable and ordered by creation time and opaque identifier, newest first. operationId: listPlans x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [plans:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/PageCursor" - $ref: "#/components/parameters/PageSize" responses: "200": description: Workspace Plans headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/PlanList" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" post: tags: [Plans] summary: Create an immutable proposed Plan description: Records proposed change evidence for review. Creation does not apply the Plan, contact a cluster, or open a Git pull request. operationId: createPlan x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [plans:write] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePlanRequest" responses: "201": description: Proposed Plan created, or the original creation response replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Plan" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/plans/{planId}: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/PlanId" get: tags: [Plans] summary: Get an immutable Plan and its approval state operationId: getPlan x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [plans:read] security: - bearerAuth: [] responses: "200": description: Plan evidence and approval state headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/json: schema: $ref: "#/components/schemas/Plan" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/plans/{planId}/approval-requests: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/PlanId" post: tags: [Plans] summary: Request approval for a proposed Plan description: Moves a proposed Plan to approval-requested exactly once. This operation does not apply the Plan. operationId: requestPlanApproval x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [plans:write] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePlanApprovalRequest" responses: "201": description: Approval requested, or the original transition response replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Plan" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workspaces/{workspaceId}/plans/{planId}/decisions: parameters: - $ref: "#/components/parameters/WorkspaceId" - $ref: "#/components/parameters/PlanId" post: tags: [Plans] summary: Approve or reject a Plan description: Records one terminal owner or administrator decision. Approval may be denied when policy forbids self-approval. This operation does not apply the Plan. operationId: decidePlan x-stability-level: beta x-kubeorch-workspace-boundary: workspace x-kubeorch-required-scopes: [plans:approve] x-kubeorch-idempotency: required security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreatePlanDecisionRequest" responses: "201": description: Terminal decision recorded, or the original decision response replayed headers: X-Request-Id: $ref: "#/components/headers/RequestId" Idempotency-Replayed: $ref: "#/components/headers/IdempotencyReplayed" content: application/json: schema: $ref: "#/components/schemas/Plan" "400": $ref: "#/components/responses/APIError" "401": $ref: "#/components/responses/APIError" "403": $ref: "#/components/responses/APIError" "404": $ref: "#/components/responses/APIError" "409": $ref: "#/components/responses/APIError" "413": $ref: "#/components/responses/APIError" /api/workflows: get: tags: [Workflows] summary: List all workflows for the authenticated user operationId: listWorkflows x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [workflows:read] security: - bearerAuth: [] parameters: - name: page in: query schema: type: integer default: 1 - name: limit in: query schema: type: integer default: 20 responses: "200": description: Paginated list of workflows "401": $ref: "#/components/responses/Unauthorized" post: tags: [Workflows] summary: Create a new workflow operationId: createWorkflow x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [workflows:write] security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [name] properties: name: type: string description: type: string responses: "201": description: Workflow created /api/workflows/{id}: get: tags: [Workflows] summary: Get a specific workflow operationId: getWorkflow x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [workflows:read] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/WorkflowId" responses: "200": description: Workflow details "404": description: Workflow not found put: tags: [Workflows] summary: Update workflow metadata operationId: updateWorkflow x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [workflows:write] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/WorkflowId" responses: "200": description: Workflow updated delete: tags: [Workflows] summary: Delete a workflow operationId: deleteWorkflow x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [workflows:write] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/WorkflowId" responses: "200": description: Workflow deleted /api/workflows/{id}/run: post: tags: [Workflows] summary: Execute the workflow operationId: runWorkflow x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [workflows:execute] security: - bearerAuth: [] parameters: - $ref: "#/components/parameters/WorkflowId" responses: "200": description: Workflow execution started /api/clusters: get: tags: [Clusters] summary: List all clusters operationId: listClusters x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [clusters:read] security: - bearerAuth: [] responses: "200": description: List of clusters post: tags: [Clusters] summary: Add a new cluster operationId: createCluster x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [clusters:write] security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: [name, server, auth_type] properties: name: type: string server: type: string format: uri auth_type: type: string enum: [bearer_token, certificate, kubeconfig, service_account, oidc] token: type: string responses: "201": description: Cluster added /api/clusters/{name}/test: post: tags: [Clusters] summary: Test cluster connection operationId: testClusterConnection x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [clusters:read] security: - bearerAuth: [] parameters: - name: name in: path required: true schema: type: string responses: "200": description: Connection test result /api/resources: get: tags: [Resources] summary: List tracked Kubernetes resources operationId: listResources x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [resources:read] security: - bearerAuth: [] responses: "200": description: List of resources /api/builds/start: post: tags: [Builds] summary: Start a container image build operationId: startBuild x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [builds:write] security: - bearerAuth: [] responses: "200": description: Build started /api/plugins: get: tags: [Plugins] summary: List all plugins operationId: listPlugins x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [plugins:read] security: - bearerAuth: [] responses: "200": description: List of plugins /api/dashboard/stats: get: tags: [Dashboard] summary: Get dashboard statistics operationId: getDashboardStats x-stability-level: beta x-kubeorch-workspace-boundary: legacy-user x-kubeorch-required-scopes: [dashboard:read] security: - bearerAuth: [] responses: "200": description: Dashboard stats components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT parameters: WorkflowId: name: id in: path required: true schema: type: string WorkspaceId: name: workspaceId in: path required: true description: Opaque workspace identifier. Clients must not infer semantics from it. schema: $ref: "#/components/schemas/ResourceId" MemberId: name: memberId in: path required: true description: Opaque membership identifier. schema: $ref: "#/components/schemas/ResourceId" EnvironmentId: name: environmentId in: path required: true description: Opaque environment identifier. schema: $ref: "#/components/schemas/ResourceId" ApplicationId: name: applicationId in: path required: true description: Opaque application identifier. schema: $ref: "#/components/schemas/ResourceId" ArtifactId: name: artifactId in: path required: true description: Opaque artifact identifier. schema: $ref: "#/components/schemas/ResourceId" ReleaseId: name: releaseId in: path required: true description: Opaque release identifier. schema: $ref: "#/components/schemas/ResourceId" PlanId: name: planId in: path required: true description: Opaque Plan identifier. schema: $ref: "#/components/schemas/ResourceId" PageCursor: name: cursor in: query required: false description: Opaque cursor returned by the previous page. schema: $ref: "#/components/schemas/Cursor" PageSize: name: limit in: query required: false description: Maximum number of records to return. schema: type: integer minimum: 1 maximum: 100 default: 20 IdempotencyKey: name: Idempotency-Key in: header required: true description: Caller-generated key used to replay a mutation safely. schema: type: string minLength: 8 maxLength: 128 pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$" schemas: ResourceId: type: string minLength: 1 maxLength: 128 pattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$" description: Opaque resource identifier. Clients must compare it only as a string. Timestamp: type: string format: date-time description: UTC RFC 3339 timestamp. Writers emit a trailing `Z`. example: "2026-08-18T12:00:00Z" Cursor: type: string minLength: 1 maxLength: 1024 description: Opaque, endpoint-specific pagination cursor. PageInfo: type: object required: [hasMore] properties: nextCursor: allOf: - $ref: "#/components/schemas/Cursor" nullable: true hasMore: type: boolean additionalProperties: false MembershipRole: type: string enum: [owner, admin, member] description: Fixed base role. Custom roles are not part of the Beta workspace contract. Workspace: type: object required: [id, name, role, createdAt, updatedAt] properties: id: $ref: "#/components/schemas/ResourceId" name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 role: $ref: "#/components/schemas/MembershipRole" createdAt: $ref: "#/components/schemas/Timestamp" updatedAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false Membership: type: object required: [id, workspaceId, userId, role, status, createdAt, updatedAt] properties: id: $ref: "#/components/schemas/ResourceId" workspaceId: $ref: "#/components/schemas/ResourceId" userId: $ref: "#/components/schemas/ResourceId" role: $ref: "#/components/schemas/MembershipRole" status: type: string enum: [active] createdAt: $ref: "#/components/schemas/Timestamp" updatedAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false CreateWorkspaceRequest: type: object required: [name] properties: name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 additionalProperties: false UpdateWorkspaceRequest: type: object minProperties: 1 properties: name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 additionalProperties: false AddMembershipRequest: type: object required: [userId, role] properties: userId: $ref: "#/components/schemas/ResourceId" role: $ref: "#/components/schemas/MembershipRole" additionalProperties: false UpdateMembershipRequest: type: object required: [role] properties: role: $ref: "#/components/schemas/MembershipRole" additionalProperties: false WorkspaceList: type: object required: [items, pageInfo] properties: items: type: array items: $ref: "#/components/schemas/Workspace" pageInfo: $ref: "#/components/schemas/PageInfo" additionalProperties: false MembershipList: type: object required: [items, pageInfo] properties: items: type: array items: $ref: "#/components/schemas/Membership" pageInfo: $ref: "#/components/schemas/PageInfo" additionalProperties: false Environment: type: object required: [id, workspaceId, name, createdAt, updatedAt] properties: id: $ref: "#/components/schemas/ResourceId" workspaceId: $ref: "#/components/schemas/ResourceId" name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 createdAt: $ref: "#/components/schemas/Timestamp" updatedAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false CreateEnvironmentRequest: type: object required: [name] properties: name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 additionalProperties: false UpdateEnvironmentRequest: type: object minProperties: 1 properties: name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 additionalProperties: false EnvironmentList: type: object required: [items, pageInfo] properties: items: type: array items: $ref: "#/components/schemas/Environment" pageInfo: $ref: "#/components/schemas/PageInfo" additionalProperties: false DesiredState: type: object description: Extensible desired application metadata and non-secret references. Unknown nested fields are preserved. Credentials, tokens, kubeconfigs, and Secret values are rejected; use reference fields instead. additionalProperties: true ApplicationStatus: type: string enum: [draft, archived] Application: type: object required: [id, workspaceId, environmentId, name, desiredState, status, createdAt, updatedAt] properties: id: $ref: "#/components/schemas/ResourceId" workspaceId: $ref: "#/components/schemas/ResourceId" environmentId: $ref: "#/components/schemas/ResourceId" name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 desiredState: $ref: "#/components/schemas/DesiredState" status: $ref: "#/components/schemas/ApplicationStatus" archivedAt: allOf: - $ref: "#/components/schemas/Timestamp" nullable: true createdAt: $ref: "#/components/schemas/Timestamp" updatedAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false CreateApplicationRequest: type: object required: [environmentId, name] properties: environmentId: $ref: "#/components/schemas/ResourceId" name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 desiredState: $ref: "#/components/schemas/DesiredState" additionalProperties: false UpdateApplicationRequest: type: object minProperties: 1 properties: name: type: string minLength: 1 maxLength: 100 description: type: string maxLength: 1000 desiredState: $ref: "#/components/schemas/DesiredState" additionalProperties: false ApplicationList: type: object required: [items, pageInfo] properties: items: type: array items: $ref: "#/components/schemas/Application" pageInfo: $ref: "#/components/schemas/PageInfo" additionalProperties: false ArtifactSource: type: object required: [repository, ref, sha] properties: repository: allOf: - $ref: "#/components/schemas/SafeHTTPSReference" description: HTTPS source repository URL without embedded credentials or query parameters. ref: type: string minLength: 1 maxLength: 512 sha: type: string pattern: "^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$" description: Full immutable source commit identifier. additionalProperties: false ArtifactEvidence: type: object properties: sbom: $ref: "#/components/schemas/SafeHTTPSReference" provenance: $ref: "#/components/schemas/SafeHTTPSReference" scan: $ref: "#/components/schemas/SafeHTTPSReference" ciRun: $ref: "#/components/schemas/SafeHTTPSReference" additionalProperties: false description: Safe HTTPS metadata references. KubeOrch stores but does not fetch these URLs during registration. Artifact: type: object required: [id, workspaceId, image, digest, source, evidence, createdBy, createdAt] properties: id: $ref: "#/components/schemas/ResourceId" workspaceId: $ref: "#/components/schemas/ResourceId" image: type: string maxLength: 512 pattern: "^.+@sha256:[a-f0-9]{64}$" description: Canonical OCI repository and immutable digest. Mutable tags are not retained as identity. digest: type: string pattern: "^sha256:[a-f0-9]{64}$" source: $ref: "#/components/schemas/ArtifactSource" evidence: $ref: "#/components/schemas/ArtifactEvidence" createdBy: $ref: "#/components/schemas/ResourceId" createdAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false CreateArtifactRequest: type: object required: [image, source] properties: image: type: string maxLength: 512 pattern: "^.+@sha256:[a-f0-9]{64}$" description: OCI image reference pinned by digest. A tag without a digest is rejected. source: $ref: "#/components/schemas/ArtifactSource" evidence: $ref: "#/components/schemas/ArtifactEvidence" additionalProperties: false ArtifactList: type: object required: [items, pageInfo] properties: items: type: array items: $ref: "#/components/schemas/Artifact" pageInfo: $ref: "#/components/schemas/PageInfo" additionalProperties: false ReleaseSource: type: string enum: [external-ci, manual] Release: type: object required: [id, workspaceId, applicationId, applicationRevision, artifactIds, source, createdBy, createdAt] oneOf: - properties: source: enum: [external-ci] required: [sourceReference] - properties: source: enum: [manual] properties: id: $ref: "#/components/schemas/ResourceId" workspaceId: $ref: "#/components/schemas/ResourceId" applicationId: $ref: "#/components/schemas/ResourceId" applicationRevision: type: string minLength: 1 maxLength: 128 pattern: "^[A-Za-z0-9][A-Za-z0-9._:/@+\\-]{0,127}$" artifactIds: type: array minItems: 1 maxItems: 100 uniqueItems: true items: $ref: "#/components/schemas/ResourceId" source: $ref: "#/components/schemas/ReleaseSource" sourceReference: allOf: - $ref: "#/components/schemas/SafeHTTPSReference" description: Required HTTPS CI-run reference when source is external-ci. createdBy: $ref: "#/components/schemas/ResourceId" createdAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false CreateReleaseRequest: type: object required: [applicationRevision, artifactIds, source] oneOf: - properties: source: enum: [external-ci] required: [sourceReference] - properties: source: enum: [manual] properties: applicationRevision: type: string minLength: 1 maxLength: 128 pattern: "^[A-Za-z0-9][A-Za-z0-9._:/@+\\-]{0,127}$" description: Immutable desired-state or canvas revision supplied by the caller. artifactIds: type: array minItems: 1 maxItems: 100 uniqueItems: true items: $ref: "#/components/schemas/ResourceId" source: $ref: "#/components/schemas/ReleaseSource" sourceReference: allOf: - $ref: "#/components/schemas/SafeHTTPSReference" description: Required HTTPS CI-run reference when source is external-ci. additionalProperties: false SafeHTTPSReference: type: string format: uri maxLength: 2048 pattern: "^https://[^/?#@]+(/[^?#]*)?$" description: HTTPS URL without embedded credentials, query parameters, or fragments. ReleaseList: type: object required: [items, pageInfo] properties: items: type: array items: $ref: "#/components/schemas/Release" pageInfo: $ref: "#/components/schemas/PageInfo" additionalProperties: false AuditCorrelationId: type: string format: uuid description: Stable correlation identifier for the later append-only audit event. PlanSource: type: string enum: [manual, external-ci, ai, managed-build] PlanStatus: type: string enum: [proposed, approval-requested, approved, rejected] PlanCheckStatus: type: string enum: [unknown, passed, warning, failed] PlanCostStatus: type: string enum: [unknown, available, unavailable] PlanEvidenceReference: type: string format: uri maxLength: 2048 pattern: '^https://[^/?#@]+(?:/[^?#]*)?$' description: Credential-free HTTPS reference without a query string or fragment. KubeOrch stores but does not fetch it during Plan creation. PlanResultReference: type: object required: [status] properties: status: $ref: "#/components/schemas/PlanCheckStatus" summary: type: string maxLength: 1000 reference: $ref: "#/components/schemas/PlanEvidenceReference" additionalProperties: false PlanCostReference: type: object required: [status] properties: status: $ref: "#/components/schemas/PlanCostStatus" summary: type: string maxLength: 1000 reference: $ref: "#/components/schemas/PlanEvidenceReference" additionalProperties: false PlanPolicyResult: type: object required: [status, selfApprovalForbidden] properties: status: $ref: "#/components/schemas/PlanCheckStatus" summary: type: string maxLength: 1000 reference: $ref: "#/components/schemas/PlanEvidenceReference" selfApprovalForbidden: type: boolean description: Server-enforced Beta policy. Plan creators cannot approve their own Plans, and request values cannot relax this rule. default: true readOnly: true additionalProperties: false PlanApprovalRequest: type: object required: [requestedBy, auditCorrelationId, requestedAt] properties: requestedBy: $ref: "#/components/schemas/ResourceId" reason: type: string maxLength: 1000 auditCorrelationId: $ref: "#/components/schemas/AuditCorrelationId" requestedAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false PlanDecision: type: object required: [decision, reason, decidedBy, auditCorrelationId, decidedAt] properties: decision: type: string enum: [approve, reject] reason: type: string minLength: 1 maxLength: 1000 decidedBy: $ref: "#/components/schemas/ResourceId" auditCorrelationId: $ref: "#/components/schemas/AuditCorrelationId" decidedAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false Plan: type: object required: [id, workspaceId, applicationId, environmentId, desiredRevision, source, diffSummary, validation, cost, policy, status, createdBy, auditCorrelationId, createdAt, updatedAt] properties: id: $ref: "#/components/schemas/ResourceId" workspaceId: $ref: "#/components/schemas/ResourceId" applicationId: $ref: "#/components/schemas/ResourceId" environmentId: $ref: "#/components/schemas/ResourceId" desiredRevision: type: string minLength: 1 maxLength: 128 pattern: '^[A-Za-z0-9][A-Za-z0-9._:/@+\-]{0,127}$' source: $ref: "#/components/schemas/PlanSource" diffSummary: type: string minLength: 1 maxLength: 4000 evidenceSummary: type: string maxLength: 2000 validation: $ref: "#/components/schemas/PlanResultReference" cost: $ref: "#/components/schemas/PlanCostReference" policy: $ref: "#/components/schemas/PlanPolicyResult" status: $ref: "#/components/schemas/PlanStatus" createdBy: $ref: "#/components/schemas/ResourceId" auditCorrelationId: $ref: "#/components/schemas/AuditCorrelationId" approvalRequest: $ref: "#/components/schemas/PlanApprovalRequest" decision: $ref: "#/components/schemas/PlanDecision" createdAt: $ref: "#/components/schemas/Timestamp" updatedAt: $ref: "#/components/schemas/Timestamp" additionalProperties: false CreatePlanRequest: type: object required: [applicationId, environmentId, desiredRevision, source, diffSummary, validation, cost, policy] properties: applicationId: $ref: "#/components/schemas/ResourceId" environmentId: $ref: "#/components/schemas/ResourceId" desiredRevision: type: string minLength: 1 maxLength: 128 pattern: '^[A-Za-z0-9][A-Za-z0-9._:/@+\-]{0,127}$' source: $ref: "#/components/schemas/PlanSource" diffSummary: type: string minLength: 1 maxLength: 4000 evidenceSummary: type: string maxLength: 2000 validation: $ref: "#/components/schemas/PlanResultReference" cost: $ref: "#/components/schemas/PlanCostReference" policy: $ref: "#/components/schemas/PlanPolicyResult" additionalProperties: false CreatePlanApprovalRequest: type: object properties: reason: type: string maxLength: 1000 additionalProperties: false CreatePlanDecisionRequest: type: object required: [decision, reason] properties: decision: type: string enum: [approve, reject] reason: type: string minLength: 1 maxLength: 1000 additionalProperties: false PlanList: type: object required: [items, pageInfo] properties: items: type: array items: $ref: "#/components/schemas/Plan" pageInfo: $ref: "#/components/schemas/PageInfo" additionalProperties: false FieldViolation: type: object required: [field, code, message] properties: field: type: string description: JSON Pointer to the invalid field when available. code: type: string description: Stable machine-readable validation code. message: type: string description: Human-readable validation message. additionalProperties: false APIError: type: object required: [type, title, status, code, requestId] properties: type: type: string format: uri-reference description: Stable problem type URI. title: type: string status: type: integer minimum: 400 maximum: 599 detail: type: string instance: type: string format: uri-reference code: type: string description: Stable KubeOrch error code suitable for programmatic handling. requestId: type: string description: Safe correlation identifier; never contains credentials. errors: type: array items: $ref: "#/components/schemas/FieldViolation" additionalProperties: false AuthResponse: type: object properties: token: type: string user: type: object properties: id: type: string name: type: string email: type: string format: email role: type: string enum: [user, admin] Error: type: object properties: error: type: string responses: BadRequest: description: Invalid request content: application/json: schema: $ref: "#/components/schemas/Error" Unauthorized: description: Authentication required content: application/json: schema: $ref: "#/components/schemas/Error" APIError: description: Request failed using the Beta API error envelope. headers: X-Request-Id: $ref: "#/components/headers/RequestId" content: application/problem+json: schema: $ref: "#/components/schemas/APIError" headers: RequestId: description: Correlation identifier for support and audit records. schema: type: string minLength: 1 maxLength: 128 IdempotencyReplayed: description: "`true` when the response was replayed from an earlier idempotent request." schema: type: boolean