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: 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/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" 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 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